【笔记】KaiOS OTA APN 方案(OMADM)

一、【需求】功能逻辑

OMADM 机制根据节点信息修改对应的APN,因此代码也通过Node消息管控实现。

  1. _listenOpApnSettings
  2. opCheckIsInProgressAndSaveNodeValue
  3. saveAndUpdateApnValue
    1. this.operatorVariantHandlers[simslot.index].applySettings(mcc, mnc/*, false*/, apnEnabledStateChange)
  4. applySettings(mcc, mnc, updateAPN)
  5. applyOperatorVariantSettings(result)
  6. buildApnSettings(allApnList)
    1. 初始化APN数组 var apnSettings = [] 和tmpApnSettings
    2. 根据APN_TYPES.length长度遍历赋值tmpApnSettings,
    3. 再将数组拷贝给apnSettings 保存 apnSettings = this.convertApnSettings(tmpApnSettings); this.buildPreferredApnSettings(apnSettings);
  7. buildPreferredApnSettings(apnSettings) 
  8. navigator.b2g.engmodeManager.setDataProfileByType(JSON.stringify(apnSettings[index]), 1);

二、【设计】接口说明 

总体接口流程

InterfaceModuleComment
_listenOpApnSettings(simslot) operator_variant_manager.js
opCheckIsInProgressAndSaveNodeValue(node, value, simslot)operator_variant_manager.js
saveAndUpdateApnValue(node, value, simslot)operator_variant_manager.js
applySettings(mcc, mnc, updateAPN)operator_variant_handler.jsupdateAPN是OMADM对应的APN class 类型
applyOperatorVariantSettings(result)operator_variant_handler.js
buildApnSettings(allApnList)operator_variant_handler.js
buildPreferredApnSettings(apnSettings)operator_variant_handler.js此接口只会被调用一次,因此在manager里面循环传参updateAPN调用applySettings()执行卡的时候,不能下发全部类型的全部APN。(存疑)
setDataProfileByTypeEngmodeManager.jsm

Manager通过发消息触发服务执行:

1.Services.cpmm.sendAsyncMessage("Engmode:setDataProfileByType",

2.内部收到消息在receiveMessage(aMessage)匹配case 执行

case "Engmode:setDataProfileByType:Return":
    request = this.requestMsgHdl(msg);

3.

_setDataProfileByTypeEngmodeService.jsm

在 buildPreferredApnSettings定制的类型会触发dataprofile下发MD,在engmode中实现。

(一)System模块-运营商管理OperatorVariantHandler (gaia)

Manager中update创建OperatorVariantHelper,Handler start创建OperatorVariantHelper。

  • OperatorVariantHandler
    • 在operator_variant_manager.js创建,在operator_variant_handler.js实现自身功能逻辑。
    • OperatorVariantHandler 是一个管理运营商变体的对象,用于存储和处理与运营商变体相关的信息。
  • OperatorVariantHelper
    • 在OperatorVariantHandler  start 时new OperatorVariantHelper,创建对象并使用helper进行mccmnc的变化监听
    • this._operatorVariantHelper.listen();

代码路径

  • gaia/apps/system/js/operator_variant_handler.js 具体APN数据处理者
  • gaia/apps/system/js/operator_variant_manager.js 运营商初始化管理
  • gaia/apps/system/js/operator_variant_handler.js 处理加载和应用不同的运营商信息

operator_variant_manager.js 
Manager的代码结构说明
(function() {var OperatorVariantManager = function(core) {/** Array of OperatorVariantHandler objects. */if (core) {this.mobileConnections = core.mobileConnections;}this.operatorVariantHandlers = [];};OperatorVariantManager.IMPORTS = ['js/operator_variant_handler.js'];//定义事件,在BaseModule监听到时执行对应逻辑OperatorVariantManager.EVENTS = ['simslot-updated','simslot-iccinfochange','logohidden'];BaseModule.create(OperatorVariantManager, {});//具体功能实现
})();

1、在 KaiOS 的 JavaScript 中,BaseModule 是一个基础模块,用于封装应用程序中的通用功能,例如管理应用程序状态、处理事件、创建通用UI等。BaseModule.create() 是一个用于创建模块实例的静态方法,第一个参数为模块构造函数,第二个参数为模块的配置对象,用于指定模块的名称、版本、依赖关系等信息。

2、logohidden 是一个自定义的事件名称(在OperatorVariantManager.EVENTS定义),用于在 KaiOS 中指示系统已经完成启动过程并准备好显示应用程序。当系统启动时,会显示 KaiOS 的 Logo,一旦logohidden!=null,就会触发 logohidden 事件,表明系统已经启动完毕并准备好显示应用程序。

(1)在下面init代码片段中,注册 logohidden 事件的监听器,在事件触发时调用 updateSavedIccIds() 方法,该方法用于更新保存的 ICCID 列表。这个事件监听器只会在 logohidden 后执行一次,因为 { once: true } 参数指定了事件只会触发一次,确保 updateSavedIccIds() 方法不会被重复调用。

(2)_handle_logohidden 方法是一个事件监听器,它会在 logohidden 事件触发时被调用。在这个方法中,会遍历所有的移动连接对象,并检查是否有对应的 operatorVariantHandlers 对象。如果没有,就将该对象的值设置为 null。

- 正常日志参考:

01-17 10:47:30.019 690 690 I GeckoDump: operator_variant_manager gid =544d
01-17 10:47:30.019 690 690 I GeckoDump: operator_variant_manager simslot.index = 0
01-17 10:47:34.093 690 690 I GeckoDump: _handle_logohidden operatorVariantHandlers[0] : [object Object]

- 异常情况:(在下方案例根据代码详细说明)

01-17 10:44:05.244 712 712 I GeckoDump: operator_variant_manager gid  = null

01-17 10:44:05.245 712 712 I GeckoDump: operator_variant_manager persist gid =[object Promise]

01-17 10:44:49.532 712 712 I GeckoDump: _handle_logohidden  operatorVariantHandlers[0] set to value null // logohidden 发现未初始化,设为'null'

PIN解锁后,不再更新operatorVariantHandlers

01-17 10:44:54.232 712 712 I GeckoDump: operator_variant_manager gid =544d
01-17 10:44:54.232 712 712 I GeckoDump: operatorVariantHandlers[0] : null

  BaseModule.create(OperatorVariantManager, {name: 'OperatorVariantManager',_start: function() {},_stop: function() {},//监听到simslot-updated事件,会更新OperatorVariantHandler'_handle_simslot-updated': function(evt) {var simslot = evt.detail;this._updateOperatorVariantHandler(simslot);},//监听到logohidden事件。会影响APN的加载,如operatorVariantHandlers[index]被初始化成null。'_handle_logohidden': function() {navigator.b2g.mobileConnections.forEach((conn, index) => {if (!this.operatorVariantHandlers[index]) {//如果指定SIM 卡槽还没有准备好,就需要将对应的 operatorVariantHandlers 对象的值设置为 nulldump('_handle_logohidden operatorVariantHandlers[' + index + '] set to value null ')this.operatorVariantHandlers[index] = 'null';}});},//监听到simslot-iccinfochange事件时执行。'_handle_simslot-iccinfochange': function(evt) {var simslot = evt.detail;this._updateOperatorVariantHandler(simslot);},//在SIM状态变化的时候会执行,如果存在客制化return了可能会导致operatorVariantHandlers=nnull因此出现APN加载中断问题。//【关键逻辑】this.operatorVariantHandlers[simslot.index]只会在这里赋值_updateOperatorVariantHandler: function(simslot) {if (!this._isVariantReady(simslot)) {return;}if (!this.operatorVariantHandlers[simslot.index]) {this.operatorVariantHandlers[simslot.index] =new OperatorVariantHandler(simslot.simCard.iccInfo.iccid,simslot.index, this);this.operatorVariantHandlers[simslot.index].start();}},//SIM卡槽状态_isVariantReady: function(simslot) {//sim不存在 || SIM没有iccInfo || SIM iccInfo没有iccid = SIM 没有readyif (!simslot.simCard ||!simslot.simCard.iccInfo ||!simslot.simCard.iccInfo.iccid) {if (this.operatorVariantHandlers[simslot.index]) {this.operatorVariantHandlers[simslot.index] = 'removed';} else {this.operatorVariantHandlers[simslot.index] = null;}return false;} else if (!this.deviceInfoOs) {return false;}return true;},updateSavedIccIds: function() {},//初始化,会调用_updateOperatorVariantHandler,并监听logohidden和拔卡//OperatorVariantManager 对象被创建时被调用,用于初始化该对象并注册必要的事件监听器init: function() {if (this.deviceInfoOs) {SettingsObserver.unobserve('deviceinfo.os', this.updateDeviceInfoOs);SIMSlotManager.getSlots().forEach(function(slot) {this._updateOperatorVariantHandler(slot);}, this);}window.addEventListener('logohidden', () => {this.updateSavedIccIds();}, { once: true });  //只执行一次window.addEventListener('simslot-removed', () => {this.updateSavedIccIds();});},updateDeviceInfoOs: function(value) {},nsureValueUnderKeyIsArray: function(key) {}});

正常逻辑:

  1. new OperatorVariantHandler =>
  2. OperatorVariantHandler start() =>
  3. 监听'cardstatechange' & 'iccinfochange' =>
  4. 收到以上事件且 cardstate 是 'ready' 时,匹配APN。
异常代码案例 

如果在 _updateOperatorVariantHandler 中添加GID等参数校验的时候考虑不全,实现代码时 return,则在插入有PIN码的卡时,可能会导致SIM卡相应index的operatorVariantHandlers一直为null,不会进行APN加载。

iccManager及其内gid判断代码return造成 logohidden 监听发现未初始化,设为'null。因为KaiOS逻辑,PIN lock情况下只能得到iccid, 得不到mcc/mnc/gid等信息。

  • PIN lock 时 gid1=null
  • SIM ready 时默认 'ff'

解决方案:

  1. 删除GID=null 时直接return 的逻辑,即gid1=null不return,可正常初始化。
  2. 新开发PIN unlock后的逻辑,重新触发初始化APN,执行加载。
    _updateOperatorVariantHandler: function(simslot) {if (!this._isVariantReady(simslot)) {return;}//非kaios原生存在缺陷的代码片段var iccManager = navigator.b2g.iccManager;if (iccManager) {var icc = iccManager.getIccById(simslot.simCard.iccInfo.iccid);if (icc) {var iccInfo = icc.iccInfo;if (iccInfo) {var gid = iccInfo.gid1;dump('operator_variant_manager: gid = ' + gid);if (gid === undefined || gid === null || gid === '') {//从persist.gsm.sim.gid获取,此值不用手动写入,根据卡。var gid1 = navigator.b2g.engmodeManager.getPropertyValue("persist.gsm.sim.gid");dump('operator_variant_manager: persist gid1 = ' + gid1);return;  //若PIN lock会直接return导致OperatorVariantHandler一直为null。}//gid}//iccInfo}//icc}//iccManager//最终卡状态ready后,唯一正常初始化operatorVariantHandlers的地方if (!this.operatorVariantHandlers[simslot.index]) {this.operatorVariantHandlers[simslot.index] =new OperatorVariantHandler(simslot.simCard.iccInfo.iccid,simslot.index, this);this.operatorVariantHandlers[simslot.index].start();}}//updateOperatorVariantHandler 私有方法

(二)APN 模块

operatorVariantHandlers正常加载后,根据卡匹配apn.json的APN 配置,

1、从配置加载到系统数据库:apn.json→ril.data.apnSettings.sim

  1. start()->
  2. getDMApnProtocol()->
  3. ObserveDMApnSettings()->
  4. combineApn(apnSettings, key)->
  5. this.cloneApn(apn)

2、从数据库到业务使用:ril.data.apnSettings.sim→DataCall

  1. observeSetting(aSettingInfo)
  2. ->this.handleSettingChanged(name, result);
  3. ->this.handleApnSettingChanged(clientId, resultApnObj)
  4. ->handler.updateApnSettings(aApnList);

(三)Engmode 模块(gecko)

  • gecko/koost/engmode/EngmodeService.jsm

在engmode实现同步APN到MD的接口,定义上层和底层APN Type的映射关系,用于同步dataProfile到Modem。

js/moduleInterfaceComment
EngmodeManager.jsmsetDataProfileByType(strApnSetting, type)管理通过消息调起服务。
EngmodeService.jsm_setDataProfileByType(networkType, profileId, apn, protocol, roamingProtocol, authType, user, password, type, maxConnsTime, maxConns, waitTime, enabled, inactivityTimer, callback) 定义服务

三、【开发】调试 Debug

源码编译到软件分区路径的说明,在设备中可以查看编译产物,使用adb pull/push 调试,webapps对应应用内的application.zip 和系统omini.ja  都是压缩包的形式。

Note:若编译调试,单编应用的产物路径在 gaia\profile\webapps\settings(应用名)

相关文件adb 设备路径代码模块路径

operator_variant_manager.js

operator_variant_handler.js

system/b2g/webapps/system/gaia\apps\system
DatacallManager.jsmsystem/b2g/omni.jagecko/dom/system/gonk/radio
EngmodeService.jsm
EngmodeManager.jsm
system/b2g/omni.jagecko/koost/engmode

四、业务知识

SIM

在KaiOS中,是operator_variant_handler.js文件管理着OperatorVariantHandler对象中运营商的信息,包括初始化和切换卡变更。

iccid

mcc

mnc

OMADM 

OMA-DM(Open Mobile Alliance Device Management)是一种用于远程管理移动设备的协议,通过OMA-DM协议,运营商可以向设备推送各种配置、更新、命令等。

在OMA-DM协议中,消息体是指通过协议传输的消息数据。

在OMA-DM协议中,更新APN配置时,需要通过指定一个APN配置模板来实现。

一般通过服务器推送消息到设备,用户终端收到后根据信息修改对应的APN。有的运营商通过class匹配不同类型的APN,而上层修改APN后也需要同步到MD,同样需要建立映射关系。

举例如下:

APN TypeAP classMD profile_IdComment/eg
ims15const NETWORK_TYPE_MOBILE_IMS = 5;
fota27const NETWORK_TYPE_MOBILE_FOTA = 7;
default30const NETWORK_TYPE_MOBILE = 1;
mms42const NETWORK_TYPE_MOBILE_MMS = 2;
  • MD ProfileId 可以自定义的,AP  Class应该运营商有要求。
  • apn.json中配置"profile_id"字段

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/633806.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,入门教程(38)——大型工程软件中类(class)修饰词partial的使用方法

上一篇: C#,入门教程(37)——优秀程序员的修炼之道https://blog.csdn.net/beijinghorn/article/details/125011644 一、大型(工程应用)软件倚重 partial 先说说大型(工程应用)软件对源代码的文件及函数“…

用 Python 制作可视化 GUI 界面,一键实现证件照背景颜色的替换

今天,我们来分享一下如何通过Python的十来行代码来替换证件照的背景颜色,那么在最后,小编也会将上述的流程制作成一个GUI界面来方便大家使用。关于界面的大致模样其实和先前的相差不大,大家应该都看过上一篇的内容 界面大体的样子…

实战-ApacheSuperset未授权访问漏洞(CVE-2023-27524)

声明: 该文章仅供网络安全领域的学习使用,请勿利用文章内的相关技术从事任何非法行为。 测试资产为国外 IP,存在漏洞的 IP 地址已做打码处理。 我们只进行 poc,请勿进行任何非法入侵和攻击。 知攻善防,遇强则强。 开发…

MYSQL索引实例

1.用SQL语句创建学生表student,定义主键,姓名不能重名,性别只能输入男或女,所在系的默认值是“计算机”。 mysql> create table student(-> Sno int primary key auto_increment,-> Sname varchar(255) not null unique…

MacOS受欢迎的数据库开发工具 Navicat Premium 15 中文版

Navicat Premium 15 Mac是一款数据库管理工具,提供了一个全面的解决方案,用于连接、管理和维护各种数据库系统。以下是Navicat Premium 15 Mac的一些主要功能和特点: 软件下载:Navicat Premium 15 中文版下载 多平台支持&#xff…

kettle 同步gbase8t数据到mysql时clob类型乱码

一、问题 使用kettle 同步gbase8t数据到mysql时clob类型乱码。 varchar类型不乱码。 环境:win10 kettle:9.x 二、解决 1 (有效)修改kettle编码格式 打开kettle的安装目录,进入data-integration目录记事本编辑spoon.bat搜索PE…

【PyTorch】PyTorch之Tensors索引切片篇

文章目录 前言一、ARGWHERE二、CAT、CONCAT、CONCATENATE三、CHUNK四、GATHER五、MOVEDIM和MOVEAXIS六、PERMUTE七、RESHAPE八、SELECT九、SPLIT十、SQUEEZE十一、T十二、TAKE十三、TILE十四、TRANSPOSE十五、UNBIND十六、UNSQUEEZE十七、WHERE 前言 介绍常用的PyTorch之Tenso…

软件工程研究生后期总结

写这篇随笔的时候,我已经处于研究生阶段的后期,只剩下一个硕论答辩即可结束研究生生涯。趁有闲暇时间,我希望可以从实习、兼职、论文和求职等几个角度重新整理一下研究生后期的工作和收获,以及对未来工作和生活做出展望。 首先简…

【VUE】记录一次 VUE中配置生产环境和开发环境方法

前言 我这里 使用Vue CLI(Vue Command Line Interface)创建Vue.js项目是一种简单的方式,它提供了一个交互式的命令行工具来帮助你初始化和管理Vue.js项目。 并且我这个项目需要区分生产环境和开发环境。这里具体完整记录下,整个…

第15届蓝桥杯嵌入式省赛准备第二天总结笔记(使用STM32cubeMX创建hal库工程+按键输入)

一.查看电路图 按键是使用的PB0,PB1,PB2,PA0四个引脚,然后使用CubeMX配置引脚,4个脚都配置为输入模式和上拉。 程序生成之后把不用的删掉,需要的留下,这里我把函数名改了。 然后写按键扫描读取程序,这里参考的正点原子…

Vue中ElementUI结合transform使用时,修复el-select弹框定位不准确问题

在大屏开发中,比如将1920*1080放到更大像素(3500*2400)大屏上演示,此时需要使用到transform来对页面进行缩放,但是此时发现弹框定位出错问题,无法准备定位到实际位置。之前写过一篇讲解的是ElementUI中的&l…

【Android】自定义View onDraw()方法会调用两次

问题 自定义了View后,在构造函数中设置画笔颜色,发现它没起效,但是在onDraw()里设置颜色就会起效,出问题的代码如下: public RoundSeekbarView(Context context, Nullable AttributeSet attrs) {super(context, attrs…

视频美颜SDK与人工智能的结合:技术突破与挑战

本篇文章,小编将与大家共同探讨美颜SDK与人工智能结合背后的技术原理、创新应用以及面临的挑战。 一、技术原理:人工智能在美颜中的应用 视频美颜SDK通过整合深度学习和计算机视觉技术,能够更准确地识别人脸特征、肤色、表情等信息&#xff…

深入理解傅里叶变换

目录 1. 什么是傅里叶变换 2. 为什么要分解为正弦波的叠加参考资料 1. 什么是傅里叶变换 高等数学中一般是从周期函数的傅里叶级数开始介绍的,这里也不例外。 简单的说,从高中我们就学过一个理想的波可以用三角函数来描述,但是实际上的波可…

MAC iterm 显示git分支名

要在Mac上的iTerm中显示Git分支名,您需要使用一个名为“Oh My Zsh”的插件。Oh My Zsh是一个流行的Zsh框架,它提供了许多有用的功能和插件,包括在终端中显示Git分支名。 以下是在iTerm中显示Git分支名的步骤: 1、安装Oh My Zsh&…

Git入门详细教程

一、Git概述🎇 Git官网 Git是一个开源的分布式版本控制系统,用于跟踪文件的变化和协作开发。它允许多个开发者在同一项目中共同工作,并能够有效地管理代码的版本和历史记录。Git可以帮助开发团队更好地协作,追踪代码变更&#xf…

什么是比特币?

比特币 比特币 (英语:Bitcoin,缩写:BTC )是一种基于 去中心化,采用 点对点网络,开放源代码,以 区块链 作为底层技术的 加密货币。比特币由 中本聪(Satoshi Nakamoto&…

Nginx前后端分离部署springboot和vue项目

Nginx前后端分离部署springboot和vue项目,其实用的比较多,有的小伙伴对其原理和配置还一知半解,现在就科普一下: 1、准备后端项目 后端工程无论是微服务还是单体,一般最终都是jar启动,关键点就是把后端服…

go mock模拟接口的实现

简介 mock翻译过来是‘模拟’的意思,也就是模拟接口返回的信息,用已有的信息替换接口返回的信息,从而提供仿真环境,实现模拟数据下的功能测试; 在多人合作编码时,你写的一个函数func DoSth(People)用到了别…

【android】有些系统的应用唤起不了

Intent launchIntent getActivity().getPackageManager().getLaunchIntentForPackage("com.miui.screenrecorder"); if (launchIntent ! null) {// 应用存在,可以启动startActivity(launchIntent); } else {// 应用不存在,可以提示用户或者采…