【笔记】APN 配置参数 bitmask 数据转换(Android & KaiOS)

一、参数说明

(一)APN配置结构对比

| 平台 | Android | KaiOS |
| 文件类型 | xml | json |

结构 每个<apn>标签是一条APN,包含完成的信息 层级数组结构,使用JSON格式的数据。最外层是mcc,其次mnc,最后APN用数组形式配置(每个APN都是一个对象,不含mccmnc属性)。
Android: apns-conf.xml
XML 复制代码
<!-- Android: apns-conf.xml -->
<?xml version="1.0" encoding="utf-8"?>
<apns version="8">
  <apn carrier="T-Mobile US" mcc="001" mnc="01" apn="fast.t-mobile.com" user="" password="" server="" proxy="" port="" mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc" mmsproxy="" mmsport="" type="default,mms,supl,hipri,xcap,rcs" protocol="IPV6" roaming_protocol="IP" bearer_bitmask="" mvno_type="ecid" mvno_match_data="[4]4310260" class="" user_visible="true" user_editable="true" authtype="0"/>
</apns>
KaiOS: apns.json

特别需要注意格式(很容易出错),数组最后不用加逗号,注意大/中括号的首位一致性。

css 复制代码
{
"202": {
  "10": [
    {"carrier":"Wind Internet","apn":"gint.b-online.gr","type":["default","supl"]},
    {"voicemail":"122","type":["operatorvariant"]},
    {"carrier":"Wind MMS","apn":"mnet.b-online.gr","mmsc":"http://192.168.200.95/servlets/mms","mmsproxy":"192.168.200.11","mmsport":"9401","type":["mms"]}
  ],
  "01": [
    {"carrier":"Cosmote Wireless Internet","apn":"","type":["ia"]},
    {"voicemail":"123","type":["operatorvariant"]},
    {"carrier":"Cosmote Wireless Internet","apn":"internet","type":["default","supl"]},
    {"carrier":"Cosmote Mms","apn":"mms","mmsc":"http://mmsc.cosmote.gr:8002","mmsproxy":"10.10.10.20","mmsport":"8080","type":["mms"]}
  ],
  "09": [
    {"carrier":"Q Internet","apn":"myq","type":["default","supl"]},
    {"voicemail":"122","type":["operatorvariant"]},
    {"carrier":"Q-Telecom MMS GPRS","apn":"q-mms.myq.gr","mmsc":"http://mms.myq.gr","mmsproxy":"192.168.80.134","mmsport":"8080","type":["mms"]}
  ]
},
"001": {
  "01": [
    {"carrier":"Testing SIM default","apn":"test","type":["default"],"protocol":"IPV4V6","roaming_protocol":"IPV4V6","user_visible":"true"},
    {"carrier":"IMS","apn":"ims","type":["ims"],"protocol":"IPV4V6","roaming_protocol":"IPV4V6","user_visible":"true"},
    {"carrier":"XCAP","apn":"xcap","type":["xcap"],"protocol":"IPV4V6","roaming_protocol":"IPV4V6","user_visible":"true","authtype":"0"}
  ]
}
}

(二)bearer配置值对比

  • 1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20 (The original bearer value in Android,位运算)
  • 1048575(The original bearer value in KaiOS using decimalism)

二、代码解析

(一)Android

待完善

(二)KaiOS(DataCallManager.jsm)

1、bitmask的进制转换

可以参考PDN建立逻辑,gecko/dom/system/gonk/radio/DataCallManager.jsm

javascript 复制代码
//DataCallManager.jsm

//检查对应的rat是否包含在此APN bearer 配置中
// Check rat value include in the bit map or not.
function bitmaskHasTech(aBearerBitmask, aRadioTech) {
  if (aBearerBitmask == 0) {
    return true;
  } else if (aRadioTech > 0) {
    return (aBearerBitmask & (1 << (aRadioTech - 1))) != 0;
  }
  return false;
}

//bearer十进制转成二进制
// Show the detail rat type.
function bitmaskToString(aBearerBitmask) {
  if (aBearerBitmask == 0 || aBearerBitmask === undefined) {
    return 0;
  }

  let val = "";
  for (let i = 1; i < RIL.GECKO_RADIO_TECH.length; i++) {
    if ((aBearerBitmask & (1 << (i - 1))) != 0) {
      val = val.concat(i + "|");
    }
  }
  return val;
}

function bearerBitmapHasCdma(aBearerBitmask) {
  return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & aBearerBitmask) != 0;
}

bitmaskToString接口中,将bitmask转化成String时,循环RIL.GECKO_RADIO_TECH的长度次,经过位运算转换成与Android原始配置的bearer_bitmask相同格式的bearer位符,用"|"间隔rat类型位。

是如何通过RIL调用ril_consts.js内的GECKO_RADIO_TECH?

DataCallManager.jsm 中定义RIL对象,并使用XPCOMUtils.defineLazyGetter()方法来实现懒加载,即在要使用时才加载和初始化对象(只有在第一次访问该对象时才会进行初始化和加载),避免不必要的性能开销和资源浪费。

RIL对象是通过ChromeUtils.import 方法从ril_consts.js文件中导入的,该对象由ril_consts.js文件中的代码创建和初始化的。

javascript 复制代码
//DataCallManaer.jsm

"use strict";

//XPCOM 是一个用于 实现跨语言组件的技术框架。
//导入XPCOMUtils对象(工具库),简化和封装XPCOM组件的开发和使用。
//使用常量const来定义 XPCOMUtils 对象,以确保在运行时不会发生对象被重新赋值的情况。
const { XPCOMUtils } = ChromeUtils.import(
  "resource://gre/modules/XPCOMUtils.jsm"
);

//定义RIL对象,后续调用 RIL.GECKO_RADIO_TECH
XPCOMUtils.defineLazyGetter(this, "RIL", function() {
  return ChromeUtils.import("resource://gre/modules/ril_consts.js");
});


//ref RIL.GECKO_RADIO_TECH
const TCP_BUFFER_SIZES = [
  null,
  "4092,8760,48000,4096,8760,48000", // gprs
  "4093,26280,70800,4096,16384,70800", // edge
  "58254,349525,1048576,58254,349525,1048576", // umts
  "16384,32768,131072,4096,16384,102400", // is95a = 1xrtt
  "16384,32768,131072,4096,16384,102400", // is95b = 1xrtt
  "16384,32768,131072,4096,16384,102400", // 1xrtt
  "4094,87380,262144,4096,16384,262144", // evdo0
  "4094,87380,262144,4096,16384,262144", // evdoa
  "61167,367002,1101005,8738,52429,262114", // hsdpa
  "40778,244668,734003,16777,100663,301990", // hsupa = hspa
  "40778,244668,734003,16777,100663,301990", // hspa
  "4094,87380,262144,4096,16384,262144", // evdob
  "131072,262144,1048576,4096,16384,524288", // ehrpd
  "524288,1048576,2097152,262144,524288,1048576", // lte
  "122334,734003,2202010,32040,192239,576717", // hspa+
  "4096,87380,110208,4096,16384,110208", // gsm (using default value)
  "4096,87380,110208,4096,16384,110208", // tdscdma (using default value)
  "122334,734003,2202010,32040,192239,576717", // iwlan
  "122334,734003,2202010,32040,192239,576717", // ca
];


//定义了一个常量RIL_RADIO_CDMA_TECHNOLOGY_BITMASK,用于表示CDMA射频技术类型的掩码值。
//RIL.GECKO_RADIO_TECH.indexOf 查找各个CDMA技术类型在GECKO_RADIO_TECH数组中的下标值,
//-1 的目的是得到对应的掩码位数,并将此转换成掩码值,
//使用按位左移(<<)运算符得到掩码值,
//各个掩码值按位或(|)操作得到最终的掩码值。
const RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("is95a") - 1)) |
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("is95b") - 1)) |
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("1xrtt") - 1)) |
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("evdo0") - 1)) |
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("evdoa") - 1)) |
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("evdob") - 1)) |
  (1 << (RIL.GECKO_RADIO_TECH.indexOf("ehrpd") - 1));


// set to true in ril_consts.js to see debug messages
var DEBUG = RIL_DEBUG.DEBUG_RIL;   //调试用的log打印标识符

如上代码,CDMA技术类型对应的掩码值RIL_RADIO_CDMA_TECHNO如下:

is95a: 1 << (5-1) = 0x10

is95b: 1 << (6-1) = 0x20

1xrtt: 1 << (7-1) = 0x40

evdo0: 1 << (8-1) = 0x80

evdoa: 1 << (9-1) = 0x100

evdob: 1 << (14-1) = 0x2000

ehrpd: 1 << (15-1) = 0x4000

2、GECKO_RADIO_TECH 定义网络制式 (ril_consts.js)

在KaiOS中,RIL.GECKO_RADIO_TECH数组是在Gecko内核的代码中定义的,其实现位于Gecko代码库的"gecko/dom/system/gonk/radio/ril_consts.js"文件中。该文件定义了一系列RIL层的常量,包括射频技术类型、消息ID等。在该文件中,可以找到以下代码片段,其中定义了RIL.GECKO_RADIO_TECH数组的元素和顺序:

javascript 复制代码
//GECKO_RADIO_TECH 数组定义射频技术(网络连接)
this.GECKO_RADIO_TECH = [
  null,
  "gprs",     //1 GPRS
  "edge",     //2 EDGE
  "umts",     //3 UMTS
  "is95a",    //4 IS-95A
  "is95b",    //5 IS-95B
  "1xrtt",    //6 cdma1x?一种CDMA2000射频技术,是CDMAOne技术的升级版(1x Radio Transmission Technology)
  "evdo0",    //7 EVDO-0
  "evdoa",    //8 EVDO-A
  "hsdpa",    //9
  "hsupa",    //10
  "hspa",     //11
  "evdob",    //12 EVDO-B
  "ehrpd",    //13 EVDO-D
  "lte",      //14 LTE
  "hspa+",    //15 HSPA+
  "gsm",      //16 GSM
  "tdscdma",  //17 TD-SCDMA
  "iwlan",    //18 iWLAN(wifi)
  "lte_ca",   //19 LTE_CA
];

//定义遵循的协议类型
this.GECKO_PROFILE_INFO_TYPE_COMMON = 0;
this.GECKO_PROFILE_INFO_TYPE_3GPP = 1;
this.GECKO_PROFILE_INFO_TYPE_3GPP2 = 2;
3、DataCall 对 rat 的使用案例
javascript 复制代码
  dataRegistrationChanged(aRadioTech) {
    let targetBearer;
    if (this.apnSetting.bearer === undefined) {
      targetBearer = 0;
    } else {
      targetBearer = this.apnSetting.bearer;
    }
    if (DEBUG) {
      this.debug(
        "dataRegistrationChanged: targetBearer: " +
          bitmaskToString(targetBearer)
      );
    }

    if (bitmaskHasTech(targetBearer, aRadioTech)) {
      // Ignore same rat type. Let handler process the retry.
    } else {
      if (DEBUG) {
        this.debug(
          "dataRegistrationChanged: current APN do not support this rat reset DC. APN:" +
            JSON.stringify(this.apnSetting)
        );
      // Clean the requestedNetworkInterfaces due to current DC can not support this rat under DC retrying state.
      // Let handler process the retry.
      let targetRequestedNetworkInterfaces = this.requestedNetworkInterfaces.slice();
      for (let networkInterface of targetRequestedNetworkInterfaces) {
        this.disconnect(networkInterface);
      }
    }
  },

gecko/koost/telephony/TelephonyBinderService.h

javascript 复制代码
// Cover the GECKO_RADIO_TECH to NETWORK_TYPE_*
int32_t convertRadioTech(const nsAString& rat);

三、日志分析

追溯在PDN建立过程中,读取apn配置的bearer参数到DataCall使用的radio类型的bearer值变化情况。

四、方案开发

相关介绍:KaiOS 新增APN信息字段的代码实现-CSDN博客

在 APN Editor中实现bearer显示

代码模块:gaia/apps/settings /js/panels/apn_editor/apn_editor.js

javascript 复制代码
/**
 * The apn editor module
 */
'use strict';
define(function(require) { //eslint-disable-line
  const ApnEditorConst = require('panels/apn_editor_tct/apn_editor_const');
  const ApnEditorSession = require('panels/apn_editor_tct/apn_editor_session');
  const ApnUtils = require('modules/apn_tct/apn_utils');

  //以下三个常量都是从ApnEditorConst模块中导入的
  const { APN_PROPERTIES } = ApnEditorConst;
  const { APN_PROPERTY_DEFAULTS } = ApnEditorConst;
  const { VALUE_CONVERTERS } = ApnEditorConst;


  return function apnEditor(rootElement) {
    return new ApnEditor(rootElement);
  };
});
将kaios中十进制的bearer转换同Android原始配置的bitmask

测试代码

javascript 复制代码
// 功能:将十进制bearer转换成1-20字符串(同Android)
function bitmaskToString(aBearerBitmask) {
  if (aBearerBitmask == 0 || aBearerBitmask === undefined) {
    return 0;
  }

  let val = "";
  for (let i = 1; i < 20; i++) {
    if ((aBearerBitmask & (1 << (i - 1))) != 0) {
      val = val.concat(i + "|");
    }
  }
  return val;
}

//常量数组,定义rat
const GECKO_RADIO_TECH = [
  null,
  "gprs",
  "edge",
  "umts",
  "is95a",
  "is95b",
  "1xrtt",
  "evdo0",
  "evdoa",
  "hsdpa",
  "hsupa",
  "hspa",
  "evdob",
  "ehrpd",
  "lte",
  "hspa+",
  "gsm",
  "tdscdma",
  "iwlan",
  "lte_ca",
];

//将1-20的bitmask转换成对应的网络制式
function bitmaskToRatString(aBitmask) {
   if (aBitmask == 0 || aBitmask === undefined) {
    return "unspecified";
  }
  let rat = "";
  let splitResult = aBitmask.split("|");
  console.log('splitResult = '+ splitResult);
  rat = splitResult.map(x => GECKO_RADIO_TECH[x]).join(",").slice(0,-1);
  //slice(startIndex,endIndex) 用于去掉最后一个逗号
  return rat;
}

// 测试代码
let apnBearer = '312312';  //apn.json原始配置值
let targetBearer;  //1-20转换目标值
let bearerString = '';

if (apnBearer === undefined) {
    targetBearer = 0;
} else {
    targetBearer = apnBearer;
}

bearerString = bitmaskToString(targetBearer);


// 输出结果
console.log('targetBearer = ' + targetBearer);
console.log('bearerString = '+ bearerString);
相关推荐
百锦再1 小时前
Android Studio开发 SharedPreferences 详解
android·ide·android studio
青春给了狗1 小时前
Android 14 修改侧滑手势动画效果
android
CYRUS STUDIO1 小时前
Android APP 热修复原理
android·app·frida·hotfix·热修复
火柴就是我2 小时前
首次使用Android Studio时,http proxy,gradle问题解决
android
limingade2 小时前
手机打电话时电脑坐席同时收听对方说话并插入IVR预录声音片段
android·智能手机·电脑·蓝牙电话·电脑打电话
浩浩测试一下2 小时前
计算机网络中的DHCP是什么呀? 详情解答
android·网络·计算机网络·安全·web安全·网络安全·安全架构
青春给了狗4 小时前
Android 14 系统统一修改app启动时图标大小和圆角
android
pengyu5 小时前
【Flutter 状态管理 - 柒】 | InheritedWidget:藏在组件树里的"魔法"✨
android·flutter·dart
居然是阿宋6 小时前
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
android·开发语言·kotlin
凉、介6 小时前
PCI 总线学习笔记(五)
android·linux·笔记·学习·pcie·pci