一、【需求】功能逻辑
OMADM 机制根据节点信息修改对应的APN,因此代码也通过Node消息管控实现。
- _listenOpApnSettings
- opCheckIsInProgressAndSaveNodeValue
- saveAndUpdateApnValue
- this.operatorVariantHandlers[simslot.index].applySettings(mcc, mnc/*, false*/, apnEnabledStateChange)
- applySettings(mcc, mnc, updateAPN)
- applyOperatorVariantSettings(result)
- buildApnSettings(allApnList)
- 初始化APN数组 var apnSettings = [] 和tmpApnSettings
- 根据APN_TYPES.length长度遍历赋值tmpApnSettings,
- 再将数组拷贝给apnSettings 保存 apnSettings = this.convertApnSettings(tmpApnSettings); this.buildPreferredApnSettings(apnSettings);
- buildPreferredApnSettings(apnSettings)
- navigator.b2g.engmodeManager.setDataProfileByType(JSON.stringify(apnSettings[index]), 1);
二、【设计】接口说明
总体接口流程
Interface | Module | Comment |
_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.js | updateAPN是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。(存疑) |
setDataProfileByType | EngmodeManager.jsm | Manager通过发消息触发服务执行: 1.Services.cpmm.sendAsyncMessage("Engmode:setDataProfileByType", 2.内部收到消息在receiveMessage(aMessage)匹配case 执行 case "Engmode:setDataProfileByType:Return": 3. |
_setDataProfileByType | EngmodeService.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 对象的值设置为 null
dump('_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 没有ready
if (!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) {}
});
正常逻辑:
- new OperatorVariantHandler =>
- OperatorVariantHandler start() =>
- 监听'cardstatechange' & 'iccinfochange' =>
- 收到以上事件且 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'
解决方案:
- 删除GID=null 时直接return 的逻辑,即gid1=null不return,可正常初始化。
- 新开发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
- start()->
- getDMApnProtocol()->
- ObserveDMApnSettings()->
- combineApn(apnSettings, key)->
- this.cloneApn(apn)
2、从数据库到业务使用:ril.data.apnSettings.sim→DataCall
- observeSetting(aSettingInfo)
- ->this.handleSettingChanged(name, result);
- ->this.handleApnSettingChanged(clientId, resultApnObj)
- ->handler.updateApnSettings(aApnList);
(三)Engmode 模块(gecko)
- gecko/koost/engmode/EngmodeService.jsm
在engmode实现同步APN到MD的接口,定义上层和底层APN Type的映射关系,用于同步dataProfile到Modem。
js/module | Interface | Comment |
EngmodeManager.jsm | setDataProfileByType(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.jsm | system/b2g/omni.ja | gecko/dom/system/gonk/radio |
EngmodeService.jsm EngmodeManager.jsm |
system/b2g/omni.ja | gecko/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,同样需要建立映射关系。文章来源:https://www.toymoban.com/news/detail-799439.html
举例如下:文章来源地址https://www.toymoban.com/news/detail-799439.html
APN Type | AP class | MD profile_Id | Comment/eg |
ims | 1 | 5 | const NETWORK_TYPE_MOBILE_IMS = 5; |
fota | 2 | 7 | const NETWORK_TYPE_MOBILE_FOTA = 7; |
default | 3 | 0 | const NETWORK_TYPE_MOBILE = 1; |
mms | 4 | 2 | const NETWORK_TYPE_MOBILE_MMS = 2; |
- MD ProfileId 可以自定义的,AP Class应该运营商有要求。
- apn.json中配置"profile_id"字段
到了这里,关于【笔记】KaiOS OTA APN 方案(OMADM)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!