com.android.carrierconfig,carrier_config服务研究

carrier_config相关研究

概述: 在PhoneGlobals创建时,会同时创建carrier_config 服务,实现carrier_config 的类是CarrierConfigLoader。CarrierConfigLoader的主要目的是,绑定特定运营商的App,从而获取特定运营的配置信息。

1. 相关类和aidl

frameworks/base/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl

packages/services/Telephony/src/com/android/phone/CarrierConfigLoader.java

frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java

2. 初始化

private CarrierConfigLoader(Context context) {

mContext = context;

// 监听开机

IntentFilter bootFilter = new IntentFilter();

bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED);

context.registerReceiver(mBootReceiver, bootFilter);

// Register for package updates. Update app or uninstall app update will have all 3 intents,

// in the order or removed, added, replaced, all with extra_replace set to true.

// 监听安装或者卸载

IntentFilter pkgFilter = new IntentFilter();

pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);

pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);

pkgFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);

pkgFilter.addDataScheme("package");

context.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, pkgFilter, null, null);

int numPhones = TelephonyManager.from(context).getPhoneCount();

// 运营商默认配置

mConfigFromDefaultApp = new PersistableBundle[numPhones];

// 运营商App设置

mConfigFromCarrierApp = new PersistableBundle[numPhones];

mServiceConnection = new CarrierServiceConnection[numPhones];

// Make this service available through ServiceManager.

// 让外部可以通过ServiceManager访问carrier_config

ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);

log("CarrierConfigLoader has started");

mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);

}

在构造函数初始化完成后,发送了EVENT_CHECK_SYSTEM_UPDATE事件,Handler对于该事件的处理如下:

case EVENT_CHECK_SYSTEM_UPDATE:

SharedPreferences sharedPrefs =

PreferenceManager.getDefaultSharedPreferences(mContext);

final String lastFingerprint = sharedPrefs.getString(KEY_FINGERPRINT, null);

// 如果系统的构建信息发生了变化,即系统更新了,那么就需要清除缓存。

if (!Build.FINGERPRINT.equals(lastFingerprint)) {

log("Build fingerprint changed. old: "

+ lastFingerprint + " new: " + Build.FINGERPRINT);

// 清除缓存

clearCachedConfigForPackage(null);

// 更新系统构建信息

sharedPrefs.edit().putString(KEY_FINGERPRINT, Build.FINGERPRINT).apply();

}

break;

清除缓存的代码如下,运营商的信息都是通过xml文件保存下来的,packageName为null时会清除所有的xml文件。

private boolean clearCachedConfigForPackage(final String packageName) {

File dir = mContext.getFilesDir();

File[] packageFiles = dir.listFiles(new FilenameFilter() {

public boolean accept(File dir, String filename) {

if (packageName != null) {

return filename.startsWith("carrierconfig-" + packageName + "-");

} else {

// 因为packageName==null,所以会清除掉所有以carrierconfig-开头的文件。

return filename.startsWith("carrierconfig-");

}

}

});

if (packageFiles == null || packageFiles.length < 1) return false;

for (File f : packageFiles) {

log("deleting " + f.getName());

f.delete();

}

return true;

}

3. 开机更新运营商信息

接收到开机广播后mHandler接收到EVENT_SYSTEM_UNLOCKED事件,对该事件的处理如下:

case EVENT_SYSTEM_UNLOCKED:

for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) {

// 如果是单卡,phoneId为0, 双卡:phoneId 为0,1

// 更新每个卡的运营商信息

updateConfigForPhoneId(i);

}

break;

更新内存中的运营商信息,如果特定运营商app不存在,那么清空对应的缓存:

private void updateConfigForPhoneId(int phoneId) {

// 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;

}

// 重新获取运营商信息

mHandler.sendMessage(mHandler.obtainMessage(EVENT_FETCH_DEFAULT, phoneId, -1));

}

首先从本地文件中读取配置信息,如果本地不能存在,那么尝试绑定android.service.carrier.CarrierService,绑定成功后,从该服务的接口中读取信息。

case EVENT_FETCH_DEFAULT:

iccid = getIccIdForPhoneId(phoneId);

// 从文件中读取默认的配置

config = restoreConfigFromXml(DEFAULT_CARRIER_CONFIG_PACKAGE, iccid);

if (config != null) {

log("Loaded config from XML. package=" + DEFAULT_CARRIER_CONFIG_PACKAGE

+ " phoneId=" + phoneId);

// xml文件存在并加载成功,发送加载默认配置成功事件

mConfigFromDefaultApp[phoneId] = config;

Message newMsg = obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1);

newMsg.getData().putBoolean("loaded_from_xml", true);

mHandler.sendMessage(newMsg);

} else {

// xml文件不存在,绑定android.service.carrier.CarrierService,该服务的实现不具体分析。

if (bindToConfigPackage(DEFAULT_CARRIER_CONFIG_PACKAGE,

phoneId, EVENT_CONNECTED_TO_DEFAULT)) {

sendMessageDelayed(obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1),

BIND_TIMEOUT_MILLIS);

} else {

// Send bcast if bind fails

// 告诉监听者,运营商信息已经发生了变化,这个时候,特定运营商信息为空。

broadcastConfigChangedIntent(phoneId);

}

}

break;

上面EVENT_BIND_DEFAULT_TIMEOUT事件比较简单, 首先unBind服务,再通过broadcastConfigChangedIntent通知监听者。

所以应该是在绑定服务成功后,就获取运营商信息,BIND_TIMEOUT_MILLIS是绑定服务的超时时间。下面看bindToConfigPackage:

/** Binds to the default or carrier config app. */

private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) {

log("Binding to " + pkgName + " for phone " + phoneId);

Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE);

carrierService.setPackage(pkgName);

// 很显然绑定成功后的逻辑在CarrierServiceConnection类里面。

mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);

try {

return mContext.bindService(carrierService, mServiceConnection[phoneId],

Context.BIND_AUTO_CREATE);

} catch (SecurityException ex) {

return false;

}

}

绑定服务成功后给mHandler发送了EVENT_CONNECTED_TO_DEFAULT事件:

case EVENT_CONNECTED_TO_DEFAULT:

// 移除超时事件。

removeMessages(EVENT_BIND_DEFAULT_TIMEOUT);

carrierId = getCarrierIdForPhoneId(phoneId);

conn = (CarrierServiceConnection) msg.obj;

// If new service connection has been created, unbind.

if (mServiceConnection[phoneId] != conn || conn.service == null) {

mContext.unbindService(conn);

break;

}

try {

ICarrierService carrierService = ICarrierService.Stub

.asInterface(conn.service);

// 从运营商服务中获取到配置。

config = carrierService.getCarrierConfig(carrierId);

iccid = getIccIdForPhoneId(phoneId);

// 保存配置到xml文件

saveConfigToXml(DEFAULT_CARRIER_CONFIG_PACKAGE, iccid, config);

// 更新内存中的配置

mConfigFromDefaultApp[phoneId] = config;

sendMessage(obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1));

} catch (Exception ex) {

// The bound app could throw exceptions that binder will pass to us.

loge("Failed to get carrier config: " + ex.toString());

} finally {

mContext.unbindService(mServiceConnection[phoneId]);

}

break;

无论是从本地xml文件中获取到运营商配置,还是从服务中获取到运营商配置,最终都会回到mHandler的EVENT_LOADED_FROM_DEFAULT事件:

case EVENT_LOADED_FROM_DEFAULT:

// If we attempted to bind to the app, but the service connection is null, then

// config was cleared while we were waiting and we should not continue.

// 我们是从服务中获取到的配置,但是服务却断开了,当然不能继续了。

if (!msg.getData().getBoolean("loaded_from_xml", false)

&& mServiceConnection[phoneId] == null) {

break;

}

carrierPackageName = getCarrierPackageForPhoneId(phoneId);

// 特定的运营商app存在,那么需要从特定的运营商中再次获取配置。

if (carrierPackageName != null) {

log("Found carrier config app: " + carrierPackageName);

sendMessage(obtainMessage(EVENT_FETCH_CARRIER, phoneId));

} else {

broadcastConfigChangedIntent(phoneId);

}

break;

获取特定运营商配置信息和获取默认配置信息的逻辑是一样的,代码就不具体列举了:

检查本地缓存文件,缓存存在>>通知变更

缓存不存在,那么从特定运营商的服务中获取对应的配置信息,然后缓存到本地,再通知变更。

4. 安装卸载更新运营商信息

理解了上面的更新一个SIM卡的运营商信息的流程,下面就比较简单了。安装卸载会给mHandler发送EVENT_PACKAGE_CHANGED事件:

case EVENT_PACKAGE_CHANGED:

carrierPackageName = (String) msg.obj;

// Only update if there are cached config removed to avoid updating config

// for unrelated packages.

// 清除掉被卸载的运营商app对应的保存在本地的xml文件。

if (clearCachedConfigForPackage(carrierPackageName)) {

int numPhones = TelephonyManager.from(mContext).getPhoneCount();

for (int i = 0; i < numPhones; ++i) {

updateConfigForPhoneId(i);

}

}

break;

上面的逻辑和开机更新运营商信息差不多,再结合前面的分析,我们知道大体的流程如下:

默认运营商配置更新

1.1 检查本地缓存文件, 缓存存在,不需要更新。

特定运营商配置更新

2.1 检查本地缓存文件,缓存不存在,需要从服务重新获取配置信息。同时发现特定运营商app不存在,清除特定运营商配置缓存。

2.2 检查特定运营商app,不存在,通知更新。

5. 主动更新

上面所说的都是carrier_config在接收到外部某个事件后,进行更新的逻辑。

carrier_config同样支持主动更新。它为主动更新提供了2个接口:

notifyConfigChangedForSubId(int subId) 主要是提供给 telephony services 更新它当前的运营商配置用的。

updateConfigForPhoneId(int phoneId, String simState) 根据提供的sim状态,决定清除该卡的运营商配置还是加载该卡的运营商配置。

6. 获取运营商配置的接口

仅仅是从内存缓存中读取配置信息,首先是读取内存预设好的配置,如果默认运营商配置存在,那么默认配置会覆盖预设配置,然后,如果特定运营商配置存在,那么特定配置覆盖默认配置。

PersistableBundle getConfigForSubId(int subId) {

try {

mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);

// SKIP checking run-time READ_PHONE_STATE since using PRIVILEGED

} catch (SecurityException e) {

mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, null);

}

int phoneId = SubscriptionManager.getPhoneId(subId);

// 优先级是 预设配置 < 默认配置 < 特定配置

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);

}

return retConfig;

}

7. 服务的调用

1) 因为服务加入到了ServiceManager里面,所以对于系统应用,可以通过ServiceManager.getService的方法获取到该服务的接口。

IBinder carrierConfig = ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE);

ICarrierConfigLoader loader = ICarrierConfigLoader.Stub.asInterface(carrierConfig);

try {

PersistableBundle defaultConfig = loader.getConfigForSubId(SubscriptionManager.getDefaultSubId());

} catch (RemoteException e) {

e.printStackTrace();

}

2) 因为该服务也注册到系统服务里面了,所以第三方应用可以获取该服务接口。

CarrierConfigManager ccm = (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);

PersistableBundle defaultConfig = ccm.getConfigForSubId(SubscriptionManager.getDefaultSubId());

总结

最后需要说明的是,carrier_config 服务自身有一套很完善的更新逻辑,调用者一般情况下不需要主动去触发更新。因为Telephony已经管理好了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值