【Telephony】multi_sim_config_changed

该文详细阐述了Android系统中如何注册并处理多SIM卡配置变化的事件。当配置改变时,一系列的更新和广播过程发生,包括更新SubscriptionInfo、读取配置文件、通知订阅者以及更新订阅信息。整个流程涉及多个组件如PhoneFactory、TelephonyComponentFactory、SubscriptionInfoUpdater和CarrierConfigLoader,确保系统能正确响应SIM卡状态的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值