1、注册观察者
--> PhoneFactory.makeDefaultPhones()
--> TelephonyComponentFactory.makeSubscriptionInfoUpdater()
--> new SubscriptionInfoUpdater()
--> PhoneConfigurationManager.registerForMultiSimConfigChange(this, EVENT_MULTI_SIM_CONFIG_CHANGED, null)
--> sMultiSimConfigChangeRegistrants.addUnique(h, what, obj) 观察者注册到通知者中
到这步,注册了对 EVENT_MULTI_SIM_CONFIG_CHANGED 事件的观察,当收到通知者notify时,就由SubscriptionInfoUpdater这个Handler对象来处理事件。
其实只要某个类中调用了PhoneConfigurationManager.registerForMultiSimConfigChange(),就会产生一个观察者并注册到通知者中
比如下面这些类的方法中都有注册观察者
2、触发事件
--> PhoneInterfaceManager.switchMultiSimConfig()
--> RadioConfig.setNumOfLiveModems()
--> RadioConfigProxy.setNumOfLiveModems()
--> 下发modem请求
--> modem返回响应,回调处理事件 EVENT_SWITCH_DSDS_CONFIG_DONE
--> ConfigurationManagerHandler.handleMessage()
--> PhoneConfigurationManager.onMultiSimConfigChanged()
--> broadcastMultiSimConfigChange()
--> notifyMultiSimConfigChange()
--> sMultiSimConfigChangeRegistrants.notifyResult() 1.通知者通知观察者
--> SubscriptionInfoUpdater.handleMessage()
--> onMultiSimConfigChanged()
private void onMultiSimConfigChanged() {
int activeModemCount = ((TelephonyManager) sContext.getSystemService(
Context.TELEPHONY_SERVICE)).getActiveModemCount();
// For inactive modems, reset its states.
for (int phoneId = activeModemCount; phoneId < SUPPORTED_MODEM_COUNT; phoneId++) {
sIccId[phoneId] = null;
sSimCardState[phoneId] = TelephonyManager.SIM_STATE_UNKNOWN;
sSimApplicationState[phoneId] = TelephonyManager.SIM_STATE_UNKNOWN;
}
}
--> Intent intent = new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED); sendBroadcast(intent) 2.发送广播
--> ConfigLoaderBroadcastReceiver.onReceive()
--> sendMessge(EVENT_MULTI_SIM_CONFIG_CHANGED)
--> ConfigHandler.handleMessage()
--> CarrierConfigLoader.onMultiSimConfigChanged()
--> updateConfigForPhoneId()
--> sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1));
--> handleMessage(EVENT_DO_FETCH_DEFAULT)
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 {...}
== 读取xml配置文件 config = restoreConfigFromXml(mPlatformCarrierConfigPackage, “”, phoneId);==
private PersistableBundle restoreConfigFromXml(@Nullable String packageName,
@NonNull String extraString, int phoneId, boolean isNoSimConfig) {
if (packageName == null) {
loge("Cannot restore config with null packageName");
}
final String version = getPackageVersion(packageName);
if (version == null) {
loge("Failed to get package version for: " + packageName);
return null;
}
String fileName;
String iccid = null;
if (isNoSimConfig) {
fileName = getFilenameForNoSimConfig(packageName);
} else {
if (SubscriptionManager.getSimStateForSlotIndex(phoneId)
!= TelephonyManager.SIM_STATE_LOADED) {
loge("Skip restore config because SIM records are not loaded.");
return null;
}
iccid = getIccIdForPhoneId(phoneId);
final int cid = getSpecificCarrierIdForPhoneId(phoneId);
if (iccid == null) {
loge("Cannot restore config with null iccid.");
return null;
}
fileName = getFilenameForConfig(packageName, extraString, iccid, cid);
}
PersistableBundle restoredBundle = null;
File file = null;
FileInputStream inFile = null;
try {
file = new File(mContext.getFilesDir(),fileName);
inFile = new FileInputStream(file);
restoredBundle = PersistableBundle.readFromStream(inFile);
String savedVersion = restoredBundle.getString(KEY_VERSION);
restoredBundle.remove(KEY_VERSION);
if (!version.equals(savedVersion)) {
loge("Saved version mismatch: " + version + " vs " + savedVersion);
restoredBundle = null;
}
inFile.close();
} catch (FileNotFoundException e) {
// Missing file is normal occurrence that might occur with a new sim or when restoring
// an override file during boot and should not be treated as an error.
if (file != null) {
if (isNoSimConfig) {
logd("File not found: " + file.getPath());
} else {
String filePath = file.getPath();
filePath = getFilePathForLogging(filePath, iccid);
logd("File not found : " + filePath);
}
}
} catch (IOException e) {
loge(e.toString());
}
return restoredBundle;
}
--> handleMessage(EVENT_FETCH_DEFAULT_DONE)
case EVENT_FETCH_DEFAULT_DONE: {
// 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;
}
final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
if (carrierPackageName != null) {
logd("Found carrier config app: " + carrierPackageName);
sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1));
} else {
notifySubscriptionInfoUpdater(phoneId);
}
break;
}
--> handleMessage(EVENT_DO_FETCH_CARRIER)
case EVENT_DO_FETCH_CARRIER: {
final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
final PersistableBundle config =
restoreConfigFromXml(carrierPackageName, "", phoneId);
if (config != null) {
logd(
"Loaded config from XML. package="
+ carrierPackageName
+ " phoneId="
+ phoneId);
mConfigFromCarrierApp[phoneId] = config;
Message newMsg = obtainMessage(EVENT_FETCH_CARRIER_DONE, phoneId, -1);
newMsg.getData().putBoolean("loaded_from_xml", true);
sendMessage(newMsg);
} else {...}
--> handleMessage(EVENT_FETCH_CARRIER_DONE)
case EVENT_FETCH_CARRIER_DONE: {
// 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;
}
notifySubscriptionInfoUpdater(phoneId);
break;
}
--> CarrierConfigLoader.notifySubscriptionInfoUpdater(phoneId);
private void notifySubscriptionInfoUpdater(int phoneId) {
String configPackagename;
PersistableBundle configToSend;
int carrierId = getSpecificCarrierIdForPhoneId(phoneId);
// Prefer the carrier privileged carrier app, but if there is not one, use the platform
// default carrier app.
if (mConfigFromCarrierApp[phoneId] != null) {
configPackagename = getCarrierPackageForPhoneId(phoneId);
configToSend = mConfigFromCarrierApp[phoneId];
} else {
configPackagename = mPlatformCarrierConfigPackage;
configToSend = mConfigFromDefaultApp[phoneId];
}
if (configToSend == null) {
configToSend = new PersistableBundle();
}
// mOverrideConfigs is for testing. And it will override current configs.
PersistableBundle config = mOverrideConfigs[phoneId];
if (config != null) {
configToSend = new PersistableBundle(configToSend);
configToSend.putAll(config);
}
mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
phoneId, configPackagename, configToSend,
mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
}
注意:这里Message事件EVENT_SUBSCRIPTION_INFO_UPDATED,后面会发送
--> SubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete()
/**
* Called by CarrierConfigLoader to update the subscription before sending a broadcast.
*/
public void updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId,
String configPackageName, PersistableBundle config, Message onComplete) {
post(() -> {
//首先,SubscriptionInfoUpdater 更新 subscription
updateSubscriptionByCarrierConfig(phoneId, configPackageName, config);
onComplete.sendToTarget();
});
}
首先,SubscriptionInfoUpdater 更新 subscription
-->updateSubscriptionByCarrierConfig(phoneId, configPackageName, config)
/**
* Update the currently active Subscription based on information from CarrierConfig
*/
@VisibleForTesting
public void updateSubscriptionByCarrierConfig(
int phoneId, String configPackageName, PersistableBundle config) {
if (!SubscriptionManager.isValidPhoneId(phoneId)
|| TextUtils.isEmpty(configPackageName) || config == null) {
if (DBG) {
logd("In updateSubscriptionByCarrierConfig(): phoneId=" + phoneId
+ " configPackageName=" + configPackageName + " config="
+ ((config == null) ? "null" : config.hashCode()));
}
return;
}
int currentSubId = mSubscriptionController.getSubIdUsingPhoneId(phoneId);
if (!SubscriptionManager.isValidSubscriptionId(currentSubId)
|| currentSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
if (DBG) logd("No subscription is active for phone being updated");
return;
}
SubscriptionInfo currentSubInfo = mSubscriptionController.getSubscriptionInfo(currentSubId);
if (currentSubInfo == null) {
loge("Couldn't retrieve subscription info for current subscription");
return;
}
ContentValues cv = new ContentValues();
ParcelUuid groupUuid = null;
// carrier certificates are not subscription-specific, so we want to load them even if
// this current package is not a CarrierServicePackage
String[] certs = config.getStringArray(
CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY);
UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRulesFromCarrierConfig(
certs);
cv.put(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS,
UiccAccessRule.encodeRules(carrierConfigAccessRules));
if (!isCarrierServicePackage(phoneId, configPackageName)) {
loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName);
} else {
boolean isOpportunistic = config.getBoolean(
CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
if (currentSubInfo.isOpportunistic() != isOpportunistic) {
if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic);
cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0");
}
String groupUuidString =
config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
if (!TextUtils.isEmpty(groupUuidString)) {
try {
// Update via a UUID Structure to ensure consistent formatting
groupUuid = ParcelUuid.fromString(groupUuidString);
if (groupUuid.equals(REMOVE_GROUP_UUID)
&& currentSubInfo.getGroupUuid() != null) {
cv.put(SubscriptionManager.GROUP_UUID, (String) null);
if (DBG) logd("Group Removed for" + currentSubId);
} else if (mSubscriptionController.canPackageManageGroup(
groupUuid, configPackageName)) {
cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
cv.put(SubscriptionManager.GROUP_OWNER, configPackageName);
if (DBG) logd("Group Added for" + currentSubId);
} else {
loge("configPackageName " + configPackageName + " doesn't own grouUuid "
+ groupUuid);
}
} catch (IllegalArgumentException e) {
loge("Invalid Group UUID=" + groupUuidString);
}
}
}
final int preferredUsageSetting =
config.getInt(
CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT,
SubscriptionManager.USAGE_SETTING_UNKNOWN);
@UsageSetting int newUsageSetting = calculateUsageSetting(
currentSubInfo.getUsageSetting(),
preferredUsageSetting);
if (newUsageSetting != currentSubInfo.getUsageSetting()) {
cv.put(SubscriptionManager.USAGE_SETTING, newUsageSetting);
if (DBG) {
logd("UsageSetting changed,"
+ " oldSetting=" + currentSubInfo.getUsageSetting()
+ " preferredSetting=" + preferredUsageSetting
+ " newSetting=" + newUsageSetting);
}
} else {
if (DBG) {
logd("UsageSetting unchanged,"
+ " oldSetting=" + currentSubInfo.getUsageSetting()
+ " preferredSetting=" + preferredUsageSetting
+ " newSetting=" + newUsageSetting);
}
}
if (cv.size() > 0 && sContext.getContentResolver().update(SubscriptionManager
.getUriForSubscriptionId(currentSubId), cv, null, null) > 0) {
mSubscriptionController.refreshCachedActiveSubscriptionInfoList();
mSubscriptionController.notifySubscriptionInfoChanged();
MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid);
}
}
然后再发送Message
public void updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId,
String configPackageName, PersistableBundle config, Message onComplete) {
post(() -> {
updateSubscriptionByCarrierConfig(phoneId, configPackageName, config);
//然后再发送Message
onComplete.sendToTarget();
});
}
--> handleMessage(EVENT_SUBSCRIPTION_INFO_UPDATED)
case EVENT_SUBSCRIPTION_INFO_UPDATED:
broadcastConfigChangedIntent(phoneId);
break;
--> broadcastConfigChangedIntent(phoneId);
private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) {
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
Intent.FLAG_RECEIVER_FOREGROUND);
if (addSubIdExtra) {
int simApplicationState = TelephonyManager.SIM_STATE_UNKNOWN;
int[] subIds = SubscriptionManager.getSubId(phoneId);
if (!ArrayUtils.isEmpty(subIds)) {
TelephonyManager telMgr = TelephonyManager.from(mContext)
.createForSubscriptionId(subIds[0]);
simApplicationState = telMgr.getSimApplicationState();
}
logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId
+ " simApplicationState " + simApplicationState);
// Include subId/carrier id extra only if SIM records are loaded
if (simApplicationState != TelephonyManager.SIM_STATE_UNKNOWN
&& simApplicationState != TelephonyManager.SIM_STATE_NOT_READY) {
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
intent.putExtra(TelephonyManager.EXTRA_SPECIFIC_CARRIER_ID,
getSpecificCarrierIdForPhoneId(phoneId));
intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, getCarrierIdForPhoneId(phoneId));
}
}
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
intent.putExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK,
mFromSystemUnlocked[phoneId]);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
int[] subIds = SubscriptionManager.getSubId(phoneId);
if (subIds != null && subIds.length > 0) {
logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId + ", subId=" + subIds[0]);
} else {
logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
}
mHasSentConfigChange[phoneId] = true;
mFromSystemUnlocked[phoneId] = false;
}
--> Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
--> mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
比如 CarrierConfigTracker.java
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
updateFromNewCarrierConfig(intent);
} else if (TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) {
updateDefaultDataSubscription(intent);
}
}
private void updateFromNewCarrierConfig(Intent intent) {
final int subId = intent.getIntExtra(
CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
return;
}
final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
if (config == null) {
return;
}
synchronized (mCallStrengthConfigs) {
mCallStrengthConfigs.put(subId, config.getBoolean(
CarrierConfigManager.KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL));
}
synchronized (mNoCallingConfigs) {
mNoCallingConfigs.put(subId, config.getBoolean(
CarrierConfigManager.KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL));
}
synchronized (mCarrierProvisionsWifiMergedNetworks) {
mCarrierProvisionsWifiMergedNetworks.put(subId, config.getBoolean(
CarrierConfigManager.KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL));
}
synchronized (mShowOperatorNameConfigs) {
mShowOperatorNameConfigs.put(subId, config.getBoolean(
CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL));
}
notifyCarrierConfigChanged();
}
private void notifyCarrierConfigChanged() {
for (CarrierConfigChangedListener l : mListeners) {
l.onCarrierConfigChanged();
}
}