https://blog.csdn.net/a396604593/article/details/118668137
https://blog.csdn.net/a396604593/article/details/127279642
通过上面两篇文章,我们知道一些telephony的配置,但是这些配置为什么会生效,是哪里加载的这些配置,以什么样的命名规则去匹配这些文件。
本篇文章从这些问题出发,简单的看看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
@Nullable
public 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操作。
===================================================================
以上为一个完整的取值流程。
那么这些值是什么时候放进去的呢?
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: 0
Line 12161: M0186CD 10-22 02:46:41.634 1394 1812 D CarrierConfigLoader: File path: carrierconfig-com.android.carrierconfig-override-00101210004466778894-1696.xml
Line 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.xml
Line 12163: M0186CF 10-22 02:46:41.635 1394 1812 D CarrierConfigLoader: File path: carrierconfig-com.android.carrierconfig-00101210004466778894-1696.xml
Line 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) {
@Override
public 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获取运营商配置
@Override
public 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的文件如何根据不同的卡,读取不同文件的加载流程。
以前只知道一些功能配置什么开关,通过这篇完整,逐渐摸索配置文件的加载流程。
简单的做一个流程总结,希望能帮助到大家。