CarrierConfig配置使用和加载流程简介

背景描述

https://blog.csdn.net/a396604593/article/details/118668137
https://blog.csdn.net/a396604593/article/details/127279642
通过上面两篇文章,我们知道一些telephony的配置,但是这些配置为什么会生效,是哪里加载的这些配置,以什么样的命名规则去匹配这些文件。
本篇文章从这些问题出发,简单的看看CarrierConfig的使用和配置加载

关于CarrierConfig配置问题

以下分析基于android 12展讯um512平台

涉及到的模块:
frameworks\base\telephony
packages\providers\TelephonyProvider
packages\services\Telephony
packages\apps\CarrierConfig
从心出发

从上层应用角度出发,代码调用举例
1、packages\apps\Settings\src\com\android\settings\network\apn\ApnEditor.java

final CarrierConfigManager configManager = (CarrierConfigManager)getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (configManager != null) {final PersistableBundle b = configManager.getConfigForSubId(mSubId);if (b != null) {//读取运营商配置hinddenXcapType = b.getBoolean(CarrierConfigManager.KEY_CARRIER_APN_XCAP_HIDDEN_BOOL, true);}    
}

2、frameworks\base\telephony\java\android\telephony\CarrierConfigManager.java

@Nullablepublic PersistableBundle getConfigForSubId(int subId) {try {ICarrierConfigLoader loader = getICarrierConfigLoader();if (loader == null) {Rlog.w(TAG, "Error getting config for subId " + subId+ " ICarrierConfigLoader is null");return null;}return loader.getConfigForSubIdWithFeature(subId, mContext.getOpPackageName(),mContext.getAttributionTag());} catch (RemoteException ex) {Rlog.e(TAG, "Error getting config for subId " + subId + ": "+ ex.toString());}return null;}

3、packages\services\Telephony\src\com\android\phone\CarrierConfigLoader.java
先拿到defaultConfig,再判断是否有覆盖,最终返回PersistableBundle类型对象

    public PersistableBundle getConfigForSubIdWithFeature(int subscriptionId, String callingPackage,String callingFeatureId) {if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subscriptionId,callingPackage, callingFeatureId, "getCarrierConfig")) {return new PersistableBundle();}int phoneId = SubscriptionManager.getPhoneId(subscriptionId);PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();if (SubscriptionManager.isValidPhoneId(phoneId)) {PersistableBundle config = mConfigFromDefaultApp[phoneId];if (config != null) {retConfig.putAll(config);}config = mConfigFromCarrierApp[phoneId];if (config != null) {retConfig.putAll(config);}config = mPersistentOverrideConfigs[phoneId];if (config != null) {retConfig.putAll(config);}config = mOverrideConfigs[phoneId];if (config != null) {retConfig.putAll(config);}// Ignore the theoretical case of the default app not being present since that won't// work in CarrierConfigLoader today.final boolean allConfigsApplied =(mConfigFromCarrierApp[phoneId] != null|| getCarrierPackageForPhoneId(phoneId) == null)&& mConfigFromDefaultApp[phoneId] != null;retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, allConfigsApplied);} else {if (mNoSimConfig != null) {retConfig.putAll(mNoSimConfig);}}return retConfig;}

4、frameworks\base\core\java\android\os\PersistableBundle.java继承BaseBundle.java
维护一个map对象,可以实现get和put操作。

===================================================================
以上为一个完整的取值流程。
那么这些值是什么时候放进去的呢?

CarrierConfig数据加载

1、上面第三步

getConfigForSubIdWithFeature获取默认配置
PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
//frameworks\base\telephony\java\android\telephony\CarrierConfigManager.java
//调用到CarrierConfigManager里的默认map

后续的几个数组,通过打断点看到是mConfigFromDefaultApp覆盖了默认配置
2、packages\services\Telephony\src\com\android\phone\CarrierConfigLoader.java
读取xml

...
config = restoreConfigFromXml(mPlatformCarrierConfigPackage, "", phoneId);
mConfigFromDefaultApp[phoneId] = config;
...
mPlatformCarrierConfigPackage =mContext.getString(R.string.platform_carrier_config_package);
...
<string name="platform_carrier_config_package" translatable="false">com.android.carrierconfig</string>

当插入卡时CarrierConfigLoader的log如下

	Line 12160: M0186CC  10-22 02:46:41.633  1394  1812 D CarrierConfigLoader: mHandler: EVENT_DO_FETCH_DEFAULT phoneId: 0Line 12161: M0186CD  10-22 02:46:41.634  1394  1812 D CarrierConfigLoader: File path: carrierconfig-com.android.carrierconfig-override-00101210004466778894-1696.xmlLine 12162: M0186CE  10-22 02:46:41.634  1394  1812 D CarrierConfigLoader: File not found: /data/user_de/0/com.android.phone/files/carrierconfig-com.android.carrierconfig-override-00101210004466778894-1696.xmlLine 12163: M0186CF  10-22 02:46:41.635  1394  1812 D CarrierConfigLoader: File path: carrierconfig-com.android.carrierconfig-00101210004466778894-1696.xmlLine 12164: M0186D0  10-22 02:46:41.635  1394  1812 D CarrierConfigLoader: restoredBundle: PersistableBundle[{allowed_initial_attach_apn_types_string_array=[ia, default], __carrier_config_package_version__=1, config_ims_package_override_string=com.google.android.ims, hide_enable_2g_bool=true, carrier_metered_roaming_apn_types_strings=[default, dun, supl], allow_hold_call_during_emergency_bool=false, hide_enhanced_4g_lte_bool=true, always_show_data_rat_icon_bool=false, carrier_default_wfc_ims_mode_int=1, carrier_volte_available_bool=false, wcdma_default_signal_strength_measurement_string=rscp, hide_lte_plus_data_icon_bool=false, carrier_metered_apn_types_strings=[default, dun, supl], carrier_name_string=Tele2, carrier_name_override_bool=true}]Line 12165: M0186D1  10-22 02:46:41.636  1394  1812 D CarrierConfigLoader: File path: /data/user_de/0/com.android.phone/files/carrierconfig-com.android.carrierconfig-00101210004466778894-1696.xml

发现加载的是/data/user_de/0/com.android.phone/files/carrierconfig-com.android.carrierconfig-00101210004466778894-1696.xml的值进行覆盖。
这个文件命名规则

/** Builds a canonical file name for a config file. */private static String getFilenameForConfig(@NonNull String packageName, @NonNull String extraString,@NonNull String iccid, int cid) {// the same carrier should have a single copy of XML file named after carrier id.// However, it's still possible that platform doesn't recognize the current sim carrier,// we will use iccid + carrierid as the canonical file name. carrierid can also handle the// cases SIM OTA resolves to different carrier while iccid remains the same.return "carrierconfig-" + packageName + extraString + "-" + iccid + "-" + cid + ".xml";}

3、xml是哪里写入的
packages\services\Telephony\src\com\android\phone\CarrierConfigLoader.java
插入卡时,调用到updateConfigForPhoneId,根据插入的卡信息更新配置文件

private void updateConfigForPhoneId(int phoneId) {mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1));}

跟踪Handler EVENT_DO_FETCH_DEFAULT

case EVENT_DO_FETCH_DEFAULT: {// Clear in-memory cache for carrier app config, so when carrier app gets// uninstalled, no stale config is left.if (mConfigFromCarrierApp[phoneId] != null&& getCarrierPackageForPhoneId(phoneId) == null) {mConfigFromCarrierApp[phoneId] = null;}// Restore persistent override values.PersistableBundle config = restoreConfigFromXml(mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId);if (config != null) {logd("Loaded persistent override config from XML. package="+ mPlatformCarrierConfigPackage+ " phoneId=" + phoneId);mPersistentOverrideConfigs[phoneId] = config;}config = restoreConfigFromXml(mPlatformCarrierConfigPackage, "", phoneId);if (config != null) {logd("Loaded config from XML. package="+ mPlatformCarrierConfigPackage+ " phoneId="+ phoneId);mConfigFromDefaultApp[phoneId] = config;Message newMsg = obtainMessage(EVENT_FETCH_DEFAULT_DONE, phoneId, -1);newMsg.getData().putBoolean("loaded_from_xml", true);mHandler.sendMessage(newMsg);} else {// No cached config, so fetch it from the default app.if (bindToConfigPackage(mPlatformCarrierConfigPackage,phoneId,EVENT_CONNECTED_TO_DEFAULT)) {sendMessageDelayed(obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1 /*arg2*/,getMessageToken(phoneId)),BIND_TIMEOUT_MILLIS);} else {// Put a stub bundle in place so that the rest of the logic continues// smoothly.mConfigFromDefaultApp[phoneId] = new PersistableBundle();// Send broadcast if bind fails.notifySubscriptionInfoUpdater(phoneId);// TODO: We *must* call unbindService even if bindService returns false.// (And possibly if SecurityException was thrown.)loge("binding to default app: "+ mPlatformCarrierConfigPackage + " fails");}}break;}

第一次插卡的时候,走bindToConfigPackage,服务器Service绑定成功后发消息获取配置信息。
EVENT_CONNECTED_TO_DEFAULT

case EVENT_CONNECTED_TO_DEFAULT: {removeMessages(EVENT_BIND_DEFAULT_TIMEOUT, getMessageToken(phoneId));final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;// If new service connection has been created, unbind.if (mServiceConnection[phoneId] != conn || conn.service == null) {unbindIfBound(mContext, conn, phoneId);break;}final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);// ResultReceiver callback will execute in this Handler's thread.final ResultReceiver resultReceiver =new ResultReceiver(this) {@Overridepublic void onReceiveResult(int resultCode, Bundle resultData) {unbindIfBound(mContext, conn, phoneId);removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT,getMessageToken(phoneId));// If new service connection has been created, this is stale.if (mServiceConnection[phoneId] != conn) {loge("Received response for stale request.");return;}if (resultCode == RESULT_ERROR || resultData == null) {// On error, abort config fetching.loge("Failed to get carrier config");notifySubscriptionInfoUpdater(phoneId);return;}PersistableBundle config =resultData.getParcelable(KEY_CONFIG_BUNDLE);saveConfigToXml(mPlatformCarrierConfigPackage, "", phoneId,carrierId, config);mConfigFromDefaultApp[phoneId] = config;sendMessage(obtainMessage(EVENT_FETCH_DEFAULT_DONE, phoneId, -1));}};// Now fetch the config asynchronously from the ICarrierService.try {ICarrierService carrierService =ICarrierService.Stub.asInterface(conn.service);carrierService.getCarrierConfig(carrierId, resultReceiver);logdWithLocalLog("Fetch config for default app: "+ mPlatformCarrierConfigPackage+ " carrierid: " + carrierId.toString());} catch (RemoteException e) {loge("Failed to get carrier config from default app: " +mPlatformCarrierConfigPackage + " err: " + e.toString());unbindIfBound(mContext, conn, phoneId);break; // So we don't set a timeout.}sendMessageDelayed(obtainMessage(EVENT_FETCH_DEFAULT_TIMEOUT, phoneId, -1 /*arg2*/,getMessageToken(phoneId)),BIND_TIMEOUT_MILLIS);break;}

carrierService.getCarrierConfig获取运营商配置
resultReceiver回调中保存运营商缓存文件,更新mConfigFromDefaultApp。
mConfigFromDefaultApp也就是我们一开始看到的配置数组

frameworks\base\telephony\java\android\service\carrier\CarrierService.java
上面getCarrierConfig获取运营商配置

@Overridepublic void getCarrierConfig(CarrierIdentifier id, ResultReceiver result) {try {Bundle data = new Bundle();data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(id));result.send(RESULT_OK, data);} catch (Exception e) {Log.e(LOG_TAG, "Error in onLoadConfig: " + e.getMessage(), e);result.send(RESULT_ERROR, null);}}

CarrierService.this.onLoadConfig加载运营商配置信息
packages\apps\CarrierConfig
packages\apps\CarrierConfig\src\com\android\carrierconfig\DefaultCarrierConfigService.java
集成CarrierService,重写onLoadConfig方法:

	public PersistableBundle onLoadConfig(@Nullable CarrierIdentifier id) {Log.d(TAG, "Config being fetched");try {synchronized (this) {if (mFactory == null) {mFactory = XmlPullParserFactory.newInstance();}}XmlPullParser parser = mFactory.newPullParser();return loadConfig(parser, id);}catch (XmlPullParserException e) {Log.e(TAG, "Failed to load config", e);return new PersistableBundle();}}PersistableBundle loadConfig(XmlPullParser parser, @Nullable CarrierIdentifier id) {PersistableBundle config = new PersistableBundle();// OEM customizable filter for carrier requirements not related to hardware/vendor SKU.String sku = getApplicationContext().getResources().getString(R.string.sku_filter);if (id == null) {try {// Load no SIM config if carrier id is not set.parser.setInput(getApplicationContext().getAssets().open(NO_SIM_CONFIG_FILE_NAME), "utf-8");config = readConfigFromXml(parser, null, sku);// Treat vendor_no_sim.xml as if it were appended to the no sim config file.XmlPullParser vendorInput =getApplicationContext().getResources().getXml(R.xml.vendor_no_sim);PersistableBundle vendorConfig = readConfigFromXml(vendorInput, null, sku);config.putAll(vendorConfig);}catch (IOException|XmlPullParserException e) {Log.e(TAG, "Failed to load config for no SIM", e);}return config;}try {if (id.getCarrierId() != TelephonyManager.UNKNOWN_CARRIER_ID) {PersistableBundle configByCarrierId = new PersistableBundle();PersistableBundle configBySpecificCarrierId = new PersistableBundle();PersistableBundle configByMccMncFallBackCarrierId = new PersistableBundle();TelephonyManager telephonyManager = getApplicationContext().getSystemService(TelephonyManager.class);int mccmncCarrierId = telephonyManager.getCarrierIdFromMccMnc(id.getMcc() + id.getMnc());//循环assets列表,匹配下面三个if的文件for (String file : getApplicationContext().getAssets().list("")) {if (file.startsWith(CARRIER_ID_PREFIX + id.getSpecificCarrierId() + "_")) {parser.setInput(getApplicationContext().getAssets().open(file), "utf-8");configBySpecificCarrierId = readConfigFromXml(parser, null, sku);break;} else if (file.startsWith(CARRIER_ID_PREFIX + id.getCarrierId() + "_")) {parser.setInput(getApplicationContext().getAssets().open(file), "utf-8");configByCarrierId = readConfigFromXml(parser, null, sku);} else if (file.startsWith(CARRIER_ID_PREFIX + mccmncCarrierId + "_")) {parser.setInput(getApplicationContext().getAssets().open(file), "utf-8");configByMccMncFallBackCarrierId = readConfigFromXml(parser, null, sku);}}// priority: specific carrier id > carrier id > mccmnc fallback carrier id//配置文件优先级顺序if (!configBySpecificCarrierId.isEmpty()) {config = configBySpecificCarrierId;} else if (!configByCarrierId.isEmpty()) {config = configByCarrierId;} else if (!configByMccMncFallBackCarrierId.isEmpty()) {config = configByMccMncFallBackCarrierId;}}if (config.isEmpty()) {// fallback to use mccmnc.xml when there is no carrier id named config found.parser.setInput(getApplicationContext().getAssets().open(MCCMNC_PREFIX + id.getMcc() + id.getMnc() + ".xml"), "utf-8");config = readConfigFromXml(parser, id, sku);}}catch (IOException | XmlPullParserException e) {Log.d(TAG, e.toString());// We can return an empty config for unknown networks.config = new PersistableBundle();}// Treat vendor.xml as if it were appended to the carrier config file we read.XmlPullParser vendorInput = getApplicationContext().getResources().getXml(R.xml.vendor);try {PersistableBundle vendorConfig = readConfigFromXml(vendorInput, id, sku);config.putAll(vendorConfig);}catch (IOException | XmlPullParserException e) {Log.e(TAG, e.toString());}/***  The vendor_ex.xml only exist when build overlay resource follow feature board.*  For example the CMCC product,if you need modify the a boolean value,add the value in the the vendor_ex.xml.*  path : vendor/sprd/feature_configs/carriers/cmcc/overlay/packages/apps/CarrierConfig/res/xml/vendor_ex.xml*/try {Resources resource = getApplicationContext().getResources();int resId = resource.getIdentifier("vendor_ex", "xml", getPackageName());XmlPullParser vendorExInput =resource.getXml(resId);PersistableBundle vendorConfigEx = readConfigFromXml(vendorExInput, id, sku);config.putAll(vendorConfigEx);Log.d(TAG, "vendor ex for feature config");}catch (IOException | XmlPullParserException | Resources.NotFoundException e) {Log.e(TAG, e.toString());}return config;}

上述加载方法中,for循环遍历assets列表,三个if排列配置优先级和文件名称匹配规则。
readConfigFromXml读取配置文件
最后返回读取到的配置。
以上就是carrierConfig的文件如何根据不同的卡,读取不同文件的加载流程。

尾注

以前只知道一些功能配置什么开关,通过这篇完整,逐渐摸索配置文件的加载流程。
简单的做一个流程总结,希望能帮助到大家。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部