[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,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 				:= EuiccGoogle
LOCAL_SRC_FILES 			:= EuiccGoogle.apk
LOCAL_MODULE_CLASS 			:= APPS
LOCAL_CERTIFICATE 			:= PRESIGNED
LOCAL_PRIVILEGED_MODULE 	:= true
LOCAL_MODULE_TAGS 			:= optional
include $(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中注册广播
        <receiver
            android:name=".PartnerReceiver"
            android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
            android:directBootAware="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.android.euicc.action.PARTNER_CUSTOMIZATION" />
            </intent-filter>
        </receiver>
  • 在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中增加两个字段
    <string name="sim_slot_mappings_json" translatable="false">{"sim-slot-mappings":[{"devices":["custom_go"],"esim-slot-ids":[0],"psim-slot-ids":[1]}]}</string>

    <integer name="download_type">3</integer>

谷歌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;*/
     }
 
     @Override
diff --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.java
index 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"
   />

原文地址:https://blog.csdn.net/Hebin320320/article/details/133779194

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读552次。com.mongodb.MongoQueryException: Query failed with error code 292 and error message 'Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.' on server 11.51.141.63:27017 _mongodb 大文件 下载失败
文章浏览阅读635次,点赞9次,收藏8次。MongoDB 是一种 NoSQL 数据库,它将每个数据存储为一个文档,这里的文档类似于 JSON/BSON 对象,具体数据结构由键值(key/value)对组成。
文章浏览阅读2.1k次。和。_mongodb 日期类型
文章浏览阅读1.7k次。Scalestack等客户期待使用MongoDB Atlas Vector Search和Amazon Bedrock构建下一代应用程序
文章浏览阅读970次。SpringBoot整合中间件mongodb、ES_springboot3 elasticsearch json数据
文章浏览阅读673次。MongoDB 简介_尚医通sql
文章浏览阅读1k次,点赞8次,收藏9次。官网下载MongoDB安装包后进行解压(因了解并不深入,故暂不进行详细说明,自行查找其他安装方法,后期了解深入后将进行该教程的完善)在bin目录下使用命令启动:./mongod --config …/mongodb.conf。该文章任然处于完善中,如果存在错误遗漏的地方,欢迎私信联系。安装相关的nuget包后即可通过以下方法连接数据。YX9010_0@的第二十篇文章。
文章浏览阅读1.2k次,点赞17次,收藏26次。社交场景, 使用 MongoDB 存储存储用户信息, 以及用户发表的朋友圈信息, 通过地理位置索引实现附近的人, 地点等功能.游戏场景, 使用 MongoDB 存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.物流场景, 使用 MongoDB 存储订单信息, 订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.物联网场景, 使用 MongoDB 存储所有接入的智能设备信息, 以及设备汇报的日
文章浏览阅读686次。您可以使用 update_one() 方法来更新 MongoDB 中调用的记录或文档。update_one() 方法的第一个参数是 query 对象,用于定义要更新的文档。注释:如果查询找到多个记录,则仅更新第一个匹配项。第二个参数是定义文档新值的对象。_python 更新 mongodb 数据
文章浏览阅读1.3k次。首先来学习一下nosql这里安装就不进行介绍 只记录一下让自己了解mongodb。_nosql注入
文章浏览阅读4.1k次,点赞8次,收藏7次。在data的目录下,创建一个db文件。因为启动MongoDB服务之前必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功。第一步:安装时,Custom是指可以自定义安装路径,然后傻瓜式安装即可(注意:先不要安装图形化工具,否则安装时间会特别长):如果要想连接成功,必须要开服务,即mongod -dbpath C:MongoDBdatadb的cmd要一直开着。然后回车,ctrl+F输入port找到端口号,一般为:27017。打开命令行,然后找到bin文件地址,并输入。_mongodb windows安装
文章浏览阅读5.1k次,点赞3次,收藏43次。详细介绍MongoDB数据库的基本知识,安装方法,基本操作,_mongodb数据库
文章浏览阅读3.2k次。安装教程翻看以往文章。_navicat 连接mongodb
文章浏览阅读426次,点赞9次,收藏12次。win10开放端口:https://blog.csdn.net/m0_43605481/article/details/119255256。我的是阿里云服务器,所以直接在安全组中加入规则,端口范围:27017,授权对象:0.0.0.0。windows在mongodb安装文件夹的bin文件夹中的mongod.cfg。数据库名字是test,打算创建一个用户,账号aaa,密码bbb,权限readWrite。因为该用户是创建在test数据库的,所以在最后要加上test。O了,然后恢复了test的数据。
文章浏览阅读1.1k次。聚合操作主要用于处理数据并返回计算结果。聚合操作将来自多个文档的值组合在一起,按条件分组后,再进行一系列操作(如求和、平均值、最大值、最小值)以返回单个结果。MongoDB的聚合查询​聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档里不存在的文档信息。MongoDB中聚合(aggregate)主要用于处理数据(例如分组统计平均值、求和、最大值等),并返回计算后的数据结果,有点类似sql语句中的count(*)、groupby。..._如何将几个db的数据统整在一起做查询
文章浏览阅读680次,点赞7次,收藏8次。(2)application.properties配置文件。(4)UserService类。(5)测试和测试结果。
文章浏览阅读1k次,点赞17次,收藏25次。Studio 3T 2023.9 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端,支持自然语言查询_mongodb客户端
文章浏览阅读1.1k次,点赞32次,收藏27次。插件式的存储引擎架构可以实现 Server 层和存储引擎层的解耦,可以支持多种存储引擎,如 MySQL 既可以支持 B-Tree 结构的 InnoDB 存储引擎,还可以支持 LSM 结构的 RocksDB 存储引擎。MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。的简称,是 JSON 文档的二进制表示,支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
文章浏览阅读5.1k次,点赞6次,收藏96次。本文设计了一种基于智能室内温度控制的自动调速风扇。以STM32系列单片机为核心主控板,通过程序代码驱动和使用温度传感器模块实现对环境温度的实时监测,并可以实时显示环境温度。同时,可以设置温度检测的上下警告值,根据需求自行调节。_stm32 温控风扇
文章浏览阅读898次,点赞13次,收藏21次。在MongoDB中,我们使用find()和find_one()方法来在集合中查找数据,就像在MySQL数据库中使用SELECT语句来在表中查找数据一样。_pymongo find_one