CarrierConfigManager解析

最近做一个高通项目的移植,发现网络设置中的cdma和gsm设置项目是同时出现的,之前mtk的项目也是遇到过同样的问题。修改起来很简单,不过要探究根源还是小费力气的。packages/services/Telephony/src/com/android/phone/MobileNetworkSettings.java

private void updateBody() {
        ...
        PersistableBundle carrierConfig =
                PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
        ...
        } else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL) == true) {
            prefSet.removePreference(mButtonEnabledNetworks);
            // set the listener for the mButtonPreferredNetworkMode list preference so we can issue
            // change Preferred Network Mode.
            mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this);

            mCdmaOptions = new CdmaOptions(this, prefSet, mPhone);
            mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet, phoneSubId);
        ...
}
发现走到了CarrierConfigManager.KEY_WORLD_PHONE_BOOL的分支,所以两个设置项全部会显示。

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

    public PersistableBundle getCarrierConfigForSubId(int subId) {
        return configLoader.getConfigForSubId(subId);
    }

PhoneGlobals只是简单跳转,真正工作在packages/services/Telephony/src/com/android/phone/CarrierConfigLoader.java

    @Override public
    @NonNull
    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]; //从默认app获取设置
            if (config != null)
                retConfig.putAll(config);
            config = mConfigFromCarrierApp[phoneId]; //从其它app获取设置
            if (config != null)
                retConfig.putAll(config);
        }
        return retConfig;
    }

可见设置值的来源有三处

1.初始设置

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

    public static PersistableBundle getDefaultConfig() {
        return new PersistableBundle(sDefaults);
    }
  /** The default value for every variable. */
    private final static PersistableBundle sDefaults;

    static {
        sDefaults = new PersistableBundle();
        sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
        sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
        sDefaults.putBoolean(KEY_ALLOW_LOCAL_DTMF_TONES_BOOL, true);
        ...
    }

是在代码中静态初始化的


2.默认app

packages/apps/CarrierConfig

首先看AndroidManifest.xml

        <service android:name=".DefaultCarrierConfigService"
                 android:permission="android.permission.BIND_CARRIER_SERVICES">
            <intent-filter>
                <action android:name="android.service.carrier.CarrierService" />
            </intent-filter>
        </service>
这个apk的核心就是一个服务,action是android.service.carrier.CarrierService,实现该action的apk都可以作为设置来源。该apk也只有一个java文件

packages/apps/CarrierConfig/src/com/android/carrierconfig/DefaultCarrierConfigService.java

读取配置的核心代码如下

    public PersistableBundle onLoadConfig(CarrierIdentifier id) {
        ...

        PersistableBundle config = null;
        try {
            synchronized (this) {
                if (mFactory == null) {
                    mFactory = XmlPullParserFactory.newInstance();
                }
            }

            XmlPullParser parser = mFactory.newPullParser();
            String fileName = "carrier_config_" + id.getMcc() + id.getMnc() + ".xml"; //从asets中读取配置
            parser.setInput(getApplicationContext().getAssets().open(fileName), "utf-8");
            config = readConfigFromXml(parser, id);
        }
        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); //从vendor.xml读取配置
        try {
            PersistableBundle vendorConfig = readConfigFromXml(vendorInput, id);
            config.putAll(vendorConfig);
        }
        catch (IOException | XmlPullParserException e) {
            Log.e(TAG, e.toString());
        }

        return config;
    }
分为两步,一是从assets目录依据mcc和mnc读取xml配置,例如中国移动的

packages/apps/CarrierConfig/assets/carrier_config_46000.xml

<carrier_config_list>
    <carrier_config>
        <boolean name="carrier_volte_available_bool" value="true" />
        <boolean name="hide_network_settings_bool" value="true" />
    </carrier_config>
</carrier_config_list>
其中之配置了两个项目。

二是从res中的vendor.xml读取,这个xml默认代码是空的。


3.其它app

    private String getCarrierPackageForPhoneId(int phoneId) {
        List<String> carrierPackageNames = TelephonyManager.from(mContext)
                .getCarrierPackageNamesForIntentAndPhone(
                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
        if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
            loge("carrierPackageNames = " + carrierPackageNames.get(0));
            return carrierPackageNames.get(0);
        } else {
            return null;
        }
    }
   public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
其中可以看出匹配action为android.service.carrier.CarrierService的apk就可以作为配置来源,这个就要厂商自己实现了,默认代码是没有的。


其中CarrierConfigManager.KEY_WORLD_PHONE_BOOL在初始配置中就是为true的,app没有配置。



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值