CarrierConfigManager解析

来源:互联网 发布:男士风衣品牌 知乎 编辑:程序博客网 时间:2024/06/15 01:04

最近做一个高通项目的移植,发现网络设置中的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没有配置。



原创粉丝点击