行业知识
[MT8766][Android12] 使用谷歌LPA实现ESIM功能的流程
文章目录
- 开发平台基本信息
- 问题描述
- 实现流程
- 其他问题
开发平台基本信息
芯片: MT8766
版本: Android 12
kernel: msm-4.19
问题描述
客户需要我们设备支持ESIM功能,5月份的时候在高通6125上面预研过ESIM功能,当时ESIM供应商是Links field,集成流程只是内置了ESIM厂商的apk,并且开启了feature以及默认给了一些权限,具体ESIM功能的实现都是在厂商的apk中,所以就没去深入研究ESIM功能。但是,由于Links field报价过高,所以这次又找了两家ESIM厂商,分别是鹏越与紫光;鹏越只把他们的ESIM芯片寄给了我们,然后让我们去找GMS实验室要LPA的相关资料,按照谷歌的标准流程操作,即可实现ESIM功能;而紫光则提供了一个他们的apk,并且要求给权限与feature,与之前的Links field类似。GMS实验室提供了一份资料,里面包含了3份文档以及一个apk。
三份文档的内容大致为:
- 1、如何集成LPA
- 2、如何实现overlay app
- 3、如何在开机向导和系统设置增加ESIM选项
ESIM功能可以简单理解为,ESIM厂家提供芯片,芯片分为贴片式跟拔插式,贴片式是贴到主板上,类似于各种单片机;而拔插式则是一张实体ESIM卡,长得跟普通的SIM卡一样,需要插入到卡槽中才能使用;然后,就到ESIM运营商购买ESIM卡号,安卓系统就可以通过谷歌LPA服务将购买的ESIM卡号下载到ESIM芯片中,下载完成启用ESIM卡就能正常使用了,一张ESIM芯片可以下载多个ESIM卡,但是,设备最多只能启用一张ESIM。
实现流程
在验证ESIM功能之前,可以先到设置-关于手机-sim卡详细信息中查看是否有EID,EID是ESIM芯片的唯一标识,代表着ESIM的正常使用,如果设备无法读取到EID,得排查硬件通路以及modem。
ESIM功能都实现流程可以分为以下几个步骤:
- 启用euicc的feature
- 内置谷歌LPA服务到system/priv-app/
- 给LPA服务增加priv-app权限或者关闭权限校验
- 增加overlay app
- 在系统设置中,调起LPA服务下载ESIM卡号,并启用ESIM
framework中已经有euicc的feature,只需要拷贝到设备即可
--- a/device/mediateksample/custom_go/full_custom_go.mk+++ b/device/mediateksample/custom_go/full_custom_go.mk@@ -7,3 +7,11 @@ MTK_TARGET_PROJECT_FOLDER := $(LOCAL_PATH) -include $(MTK_TARGET_PROJECT_FOLDER)/vnd_$(MTK_TARGET_PROJECT).mk PRODUCT_NAME := full_custom_go +PRODUCT_COPY_FILES += \+frameworks/native/data/etc/android.hardware.telephony.euicc.xml:system/etc/permissions/android.hardware.telephony.euicc.xml \+
内置谷歌LPA服务到system/priv-app/
--- a/device/mediateksample/p8_go/full_custom_go.mk+++ b/device/mediateksample/p8_go/full_custom_go.mk@@ -7,3 +7,11 @@ MTK_TARGET_PROJECT_FOLDER := $(LOCAL_PATH) -include $(MTK_TARGET_PROJECT_FOLDER)/vnd_$(MTK_TARGET_PROJECT).mk PRODUCT_NAME := full_custom_go++PRODUCT_PACKAGES += \+EuiccGoogle \+LOCAL_PATH := $(call my-dir)###############################################################################include $(CLEAR_VARS)LOCAL_MODULE := EuiccGoogleLOCAL_SRC_FILES := EuiccGoogle.apkLOCAL_MODULE_CLASS := APPSLOCAL_CERTIFICATE := PRESIGNEDLOCAL_PRIVILEGED_MODULE := trueLOCAL_MODULE_TAGS := optionalinclude $(BUILD_PREBUILT)
给LPA服务增加priv-app权限或者关闭权限校验,这里选择的是关闭权限校验
--- a/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java+++ b/frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java@@ -3469,6 +3469,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { @NonNull PackageSetting packageSetting, @NonNull Permission permission) { if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) { return true;+ }else if (!RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {+ return true; } final String packageName = pkg.getPackageName(); if (Objects.equals(packageName, PLATFORM_PACKAGE_NAME)) {增加overlay app,这个app是自己写的,需要实现几个功能
- 在AndroidManifest.xml中注册广播
- 在java文件中实现广播,并且广播方法中必须为空
package com.tp.euicc.overlay;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;public class PartnerReceiver extends BroadcastReceiver { public PartnerReceiver() { } @Override public void onReceive(Context context, Intent intent) { }}- 在res/values/strings.xml中增加两个字段
{"sim-slot-mappings":[{"devices":["custom_go"],"esim-slot-ids":[0],"psim-slot-ids":[1]}]} 3谷歌LPA就是通过广播找到overlay app,然后从app的资源文件中获取sim_slot_mappings_json的值,拿到配置数据,其中devices的值要修改为Build.DEVICE,如果是其他项目移植要记得修改。后面的esim是虚拟sim卡,psim是物理sim卡,ids的值分别是对应的卡槽,比如在SIM 1卡槽接了ESIM,这里就配成0,不过实际测试,不过怎么配置ids,都能使用ESIM。
在系统设置中,调起LPA服务下载ESIM卡号,并启用ESIM
按照上面的方式集成之后,在系统设置-网络-移动网络选项,如果没有下载过ESIM,点击就会调起谷歌LPA服务,或者可以通过adb广播调起LPA配置界面,然后根据提示,扫描二维码,下载ESIM卡号即可。
adb shell am start -n"com.google.android.euicc/com.android.euicc.ui.settings.CurrentProfileListActivity"
其他问题
之前在2290上面调试,出现下载完ESIM卡号之后,无法启用ESIM功能,需要在ESIM界面开、关一次飞行模式,ESIM启用按钮才可以点击。解决方案如下:
--- a/QSSI.12/packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java+++ b/QSSI.12/packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java@@ -58,6 +58,7 @@ import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.utils.ThreadUtils; import org.codeaurora.internal.IExtTelephony; import java.util.Arrays; import java.util.List;@@ -106,7 +107,8 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings { private void setScreenState() { int simState = mTelephonyManager.getSimState();- boolean screenState = simState != TelephonyManager.SIM_STATE_ABSENT;+ // boolean screenState = simState != TelephonyManager.SIM_STATE_ABSENT;+ boolean screenState = true; if (screenState) {在MTK8766中同样出现不可点击的问题,而且还把白卡显示出来,造成了混淆,解决方案如下:
--- a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/network/MobileNetworkListController.java+++ b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/network/MobileNetworkListController.java@@ -26,7 +26,9 @@ import android.content.Intent; import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager;+import android.telephony.euicc.EuiccManager; import android.util.ArrayMap;+import android.util.Log; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver;@@ -122,7 +124,7 @@ public class MobileNetworkListController extends AbstractPreferenceController im } else { pref.setSummary(R.string.mobile_network_inactive_esim); /// M: Add for updating enabled state.- pref.setEnabled(false);+ //pref.setEnabled(false); } } else { if (mSubscriptionManager.isActiveSubscriptionId(subId)) {@@ -130,7 +132,7 @@ public class MobileNetworkListController extends AbstractPreferenceController im } else if (SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) { pref.setSummary(mContext.getString(R.string.mobile_network_inactive_sim)); /// M: Add for updating enabled state.- pref.setEnabled(false);+ //pref.setEnabled(false); } else { pref.setSummary(mContext.getString(R.string.mobile_network_tap_to_activate, displayName));@@ -138,7 +140,14 @@ public class MobileNetworkListController extends AbstractPreferenceController im } pref.setOnPreferenceClickListener(clickedPref -> {- if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)+ Log.d(TAG, "clickedPref isEmbedded: " + (info.isEmbedded()));+ Log.d(TAG, "clickedPref isActiveSubscriptionId: " + (mSubscriptionManager.isActiveSubscriptionId(subId)));+ Log.d(TAG, "clickedPref showToggleForPhysicalSim: " + (SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)));+ /// M: Add for updating enabled state.+ if(info.isEmbedded()){+ Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);+ mContext.startActivity(intent);+ }else if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId) && !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) { SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId, true); } else {--- a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/network/MobileNetworkSummaryController.java+++ b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/network/MobileNetworkSummaryController.java@@ -258,8 +258,17 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController mPreference.setEnabled(false); } /// @}- } else {- mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());+ } else { + /// M: Add for updating enabled state.+ mPreference.setOnPreferenceClickListener((Preference pref) -> {+ logPreferenceClick(pref);++ Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);+ mContext.startActivity(intent);+ return true;+ });+ + //mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName()); } }--- a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/network/telephony/MobileNetworkSettings.java+++ b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/network/telephony/MobileNetworkSettings.java@@ -27,6 +27,7 @@ import android.provider.Settings; import android.provider.SearchIndexableResource; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager;+import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import android.util.Log; import android.view.Menu;@@ -100,8 +101,12 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings { return true; } final String key = preference.getKey();+ + Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);+ startActivity(intent);+ return true; - if (TextUtils.equals(key, BUTTON_CDMA_SYSTEM_SELECT_KEY)+ /*if (TextUtils.equals(key, BUTTON_CDMA_SYSTEM_SELECT_KEY) || TextUtils.equals(key, BUTTON_CDMA_SUBSCRIPTION_KEY)) { if (mTelephonyManager.getEmergencyCallbackMode()) { startActivityForResult(@@ -112,7 +117,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings { return true; } - return false;+ return false;*/ } @Overridediff --git a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/security/SimLockPreferenceController.java b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/security/SimLockPreferenceController.javaindex 3b85888..98cbc9b 100644--- a/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/security/SimLockPreferenceController.java+++ b/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/security/SimLockPreferenceController.java@@ -94,10 +94,10 @@ public class SimLockPreferenceController extends BasePreferenceController { for (SubscriptionInfo subInfo : subInfoList) { final int simState = mTelephonyManager.getSimState(subInfo.getSimSlotIndex());- if ((simState != TelephonyManager.SIM_STATE_ABSENT)- && (simState != TelephonyManager.SIM_STATE_UNKNOWN)) {+ // if ((simState != TelephonyManager.SIM_STATE_ABSENT)+ // && (simState != TelephonyManager.SIM_STATE_UNKNOWN)) { return true;- }+ // } } return false; }MTK8766下载完ESIM卡号之后,有信号,能ping通百度,但是浏览器无法上网,最终定位是他们默认APN配置的问题
--- a/device/mediatek/config/apns-conf.xml+++ b/device/mediatek/config/apns-conf.xml@@ -25782,12 +25782,12 @@ mcc="454" mnc="00" apn="mobile"- proxy="192.168.59.51"- port="8080"- mmsc="http://192.168.58.171:8002"- mmsproxy="192.168.59.51"- mmsport="8080"- type="default,supl,mms"+ proxy=""+ port=""+ mmsc=""+ mmsproxy=""+ mmsport=""+ type="default,ia,supl" protocol="IPV4V6" roaming_protocol="IPV4V6" />
- 在res/values/strings.xml中增加两个字段
- 在java文件中实现广播,并且广播方法中必须为空
- 在AndroidManifest.xml中注册广播