Android 运营商配置(CarrierConfig)完全指南

1 阅读6分钟

第1层:系统架构概述

用户应用/系统服务
      ↓
CarrierConfigManager.getConfigForSubId(subId)
      ↓
ICarrierConfigLoader Binder服务
      ↓
┌─────────────────────────────────────┐
│   CarrierConfigLoader               │
├─────────────────────────────────────┤
│ 1. 从DefaultApp获取配置             │
│ 2. 从Carrier App获取配置            │
│ 3. 缓存到XML文件                    │
│ 4. 合并配置优先级                   │
└─────────────────────────────────────┘
      ↓
PersistableBundle(配置数据)

第2层:配置优先级(最高到最低)

1️⃣ Test Override Configs      (测试覆盖)
         ↓
2️⃣ Persistent Override Configs (持久覆盖)
         ↓
3️⃣ Carrier App Config          (运营商App配置)
         ↓
4️⃣ Default App Config          (系统默认App配置)
         ↓
5️⃣ Platform Defaults           (平台硬编码默认值)

第3层:配置加载流程

// CarrierConfigManager.java - 公共API
public PersistableBundle getConfigForSubId(int subId, String... keys) {
    // 1. 校验subscriptionId
    if (!SubscriptionManager.isValidSubscriptionId(subId)) {
        return getDefaultConfig();
    }
    
    // 2. 调用Binder服务获取配置
    ICarrierConfigLoader service = 
        TelephonyFrameworkInitializer.getTelephonyServiceManager()
            .getCarrierConfigLoaderServiceManager()
            .getCarrierConfigLoader();
    
    // 3. 指定key过滤
    PersistableBundle result = service.getConfigForSubId(subId, keys);
    
    // 4. 返回配置束
    return result;
}

第4层:CarrierConfigLoader 的配置加载策略

Phase 1: 启动时的配置加载

// CarrierConfigLoader.java
public class CarrierConfigLoader {
    // 配置存储位置
    private PersistableBundle[] mConfigFromDefaultApp;    // /data/user/0/.../
    private PersistableBundle[] mConfigFromCarrierApp;    // 
    private PersistableBundle[] mPersistentOverrideConfigs; // 测试覆盖
    
    private void onBootOrUpdate() {
        for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
            // 1. 先尝试从缓存XML恢复
            PersistableBundle config = restoreConfigFromXml(
                mPlatformCarrierConfigPackage,  // "com.android.carrierconfig"
                "",
                phoneId
            );
            
            if (config != null) {
                // 缓存有效,使用缓存
                mConfigFromDefaultApp[phoneId] = config;
            } else {
                // 缓存失效或不存在,绑定到DefaultApp
                bindToConfigPackage(
                    mPlatformCarrierConfigPackage,
                    phoneId,
                    EVENT_CONNECTED_TO_DEFAULT
                );
            }
        }
    }
}

Phase 2: 配置文件格式

// XML缓存文件结构
File cacheFile = new File(
    context.getFilesDir(),
    "carrier_config_" + iccid + "_" + carrierId + ".xml"
);

// 内容格式: PersistableBundle
PersistableBundle config = new PersistableBundle();
config.putString("carrier_config_version_string", "1.0");
config.putBoolean("carrier_default_wfc_ims_enabled_bool", true);
config.putInt("carrier_default_wfc_ims_mode_int", 2);
config.putStringArray("carrier_metered_apn_types_strings", 
    new String[]{"default", "mms", "dun"});

// 序列化到文件
try (FileOutputStream out = new FileOutputStream(cacheFile)) {
    config.writeToStream(out);
}

第5层:默认配置定义

在 CarrierConfigManager.java 中定义的关键常量

public class CarrierConfigManager {
    // ===== VoLTE/IMS配置 =====
    public static final String KEY_CARRIER_VOLTE_ENABLED_BOOL = 
            "carrier_volte_enabled_bool";  // VoLTE是否启用
    
    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL =
            "carrier_default_wfc_ims_enabled_bool";  // WiFi通话是否默认启用
    
    public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT =
            "carrier_default_wfc_ims_mode_int";  // WiFi通话模式
    // 值: 0=仅WiFi, 1=优先移动网络, 2=优先WiFi
    
    // ===== 数据相关配置 =====
    public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS =
            "carrier_metered_apn_types_strings";  // 计费的APN类型
    
    public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY =
            "apn_settings_default_apn_types_string_array";  // 默认APN类型
    
    public static final String KEY_ALLOW_ADDING_APNS_BOOL =
            "allow_adding_apns_bool";  // 是否允许用户添加APN
    
    // ===== 通话功能配置 =====
    public static final String KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL =
            "carrier_allow_transfer_ims_call_bool";  // IMS通话转接
    
    public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL =
            "carrier_allow_deflect_ims_call_bool";  // IMS通话拒接
    
    // ===== 5G配置 =====
    public static final String KEY_CARRIER_NR_AVAILABILITY_INT =
            "carrier_nr_availability_int";  // 5G可用性
    // 值: CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA
    
    // ===== 紧急呼救相关 =====
    public static final String KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY =
            "emergency_over_ims_supported_3gpp_network_types_int_array";
    
    // ===== Tethering热点配置 =====
    public static final String KEY_CARRIER_SUPPORTS_TETHERING_BOOL =
            "carrier_supports_tethering_bool";  // 运营商是否支持热点
}

第6层:完整的默认值集合

// CarrierConfigManager.java - sDefaults 初始化
private static void initDefaults() {
    sDefaults = new PersistableBundle();
    
    // 版本信息
    sDefaults.putString(KEY_CARRIER_CONFIG_VERSION_STRING, "1.0.0");
    
    // VoLTE/WiFi通话
    sDefaults.putBoolean(KEY_CARRIER_VOLTE_ENABLED_BOOL, false);
    sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
    sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 0);  // WiFi only
    
    // 数据APN
    sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
        new String[]{"default", "mms", "dun", "supl", "enterprise"});
    sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
        new String[]{"default", "mms", "dun", "supl", "enterprise"});
    
    // 通话功能
    sDefaults.putBoolean(KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL, false);
    sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false);
    
    // 5G
    sDefaults.putInt(KEY_CARRIER_NR_AVAILABILITY_INT, 
        CARRIER_NR_AVAILABILITY_NSA);
    
    // Tethering
    sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true);
    
    // MTU设置
    sDefaults.putInt(KEY_DEFAULT_MTU_INT, 1500);
    
    // APN设置
    sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
    sDefaults.putStringArray(KEY_READ_ONLY_APN_TYPES_STRING_ARRAY, 
        new String[]{"dun"});  // DUN为只读
    
    // 数据重试
    sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 
        3000);  // 3秒后重试
}

第7层:运营商App如何提供配置

开发运营商配置App的步骤

1. 继承 CarrierService

// com.example.carrier/CarrierConfigService.java
public class CarrierConfigService extends CarrierService {
    
    @Override
    public PersistableBundle onLoadConfig(int subscriptionId, 
            @Nullable CarrierIdentifier id) {
        
        PersistableBundle config = new PersistableBundle();
        
        if (id == null) {
            return config;
        }
        
        // 使用CarrierId而不是MCCMNC(更准确)
        int carrierId = id.getCarrierId();
        
        switch (carrierId) {
            case TelephonyManager.CARRIER_ID_CHINA_MOBILE:  // 中国移动
                config = getChinaMobileConfig();
                break;
            case TelephonyManager.CARRIER_ID_CHINA_UNICOM:  // 中国联通
                config = getChinaUnicomConfig();
                break;
            case TelephonyManager.CARRIER_ID_CHINA_TELECOM: // 中国电信
                config = getChinaTelecomConfig();
                break;
            default:
                // 使用MCCMNC作为备选
                String mccmnc = id.getMccMnc();
                if ("46000".equals(mccmnc)) {  // 中国移动
                    config = getChinaMobileConfig();
                }
                break;
        }
        
        return config;
    }
    
    private PersistableBundle getChinaMobileConfig() {
        PersistableBundle config = new PersistableBundle();
        
        // VoLTE/VoWiFi配置
        config.putBoolean("carrier_volte_enabled_bool", true);
        config.putBoolean("carrier_default_wfc_ims_enabled_bool", true);
        config.putInt("carrier_default_wfc_ims_mode_int", 2);  // 优先WiFi
        
        // APN配置
        config.putStringArray("carrier_metered_apn_types_strings",
            new String[]{"default", "mms", "dun", "supl"});
        
        // 功能配置
        config.putBoolean("carrier_allow_transfer_ims_call_bool", true);
        config.putBoolean("carrier_allow_deflect_ims_call_bool", true);
        
        // 5G配置
        config.putInt("carrier_nr_availability_int", 2);  // SA mode
        
        // 版本信息
        config.putString("carrier_config_version_string", 
            "ChinaMobile_v1.0_" + System.currentTimeMillis());
        
        return config;
    }
}

2. 在 AndroidManifest.xml 中声明

<service
    android:name=".CarrierConfigService"
    android:permission="android.permission.BIND_CARRIER_CONFIG_SERVICE"
    android:exported="true">
    <intent-filter>
        <action android:name="android.service.carrier.CarrierService" />
    </intent-filter>
</service>

第8层:配置更新和监听

通知配置变化

// 在运营商App中
CarrierConfigManager configManager = 
    context.getSystemService(CarrierConfigManager.class);

// 通知系统配置已更新
configManager.notifyConfigChangedForSubId(subscriptionId);

监听配置变化

// 在系统服务中
BroadcastReceiver configReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED
                .equals(intent.getAction())) {
            
            int slotIndex = intent.getIntExtra(
                CarrierConfigManager.EXTRA_SLOT_INDEX, -1);
            int subId = intent.getIntExtra(
                CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
            
            // 重新加载配置
            reloadCarrierConfig(subId);
        }
    }
};

IntentFilter filter = new IntentFilter(
    CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
context.registerReceiver(configReceiver, filter);

第9层:配置查询和使用

标准查询模式

public class MyTelephonyService {
    
    public void loadCarrierConfig(int subId) {
        CarrierConfigManager configManager = 
            context.getSystemService(CarrierConfigManager.class);
        
        // 方式1:获取全部配置
        PersistableBundle fullConfig = 
            configManager.getConfigForSubId(subId);
        
        // 方式2:仅获取指定的配置项
        PersistableBundle selectedConfig = 
            configManager.getConfigForSubId(subId,
                CarrierConfigManager.KEY_CARRIER_VOLTE_ENABLED_BOOL,
                CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL,
                CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITY_INT
            );
        
        // 方式3:获取默认配置(无SIM或配置不可用)
        PersistableBundle defaultConfig = 
            CarrierConfigManager.getDefaultConfig();
        
        // 检查配置是否来自已识别的运营商
        boolean isIdentified = 
            CarrierConfigManager.isConfigForIdentifiedCarrier(fullConfig);
        
        if (!isIdentified) {
            Log.w(TAG, "Config is from unknown carrier, using defaults");
        }
    }
    
    public void useCarrierConfig(PersistableBundle config) {
        // 读取配置值
        boolean volteEnabled = config.getBoolean(
            CarrierConfigManager.KEY_CARRIER_VOLTE_ENABLED_BOOL, 
            false  // 默认值
        );
        
        int wfcMode = config.getInt(
            CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT,
            0  // 默认为WiFi only
        );
        
        String[] meteredApnTypes = config.getStringArray(
            CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS
        );
        
        int nrAvailability = config.getInt(
            CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITY_INT,
            CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA
        );
        
        // 应用配置到系统行为
        applyVoLteSettings(volteEnabled);
        applyWiFiCallingMode(wfcMode);
        apply5GSettings(nrAvailability);
    }
}

第10层:主要配置分类参考表

分类配置项类型说明
VoLTE/IMSVOLTE_ENABLEDboolVoLTE是否启用
WFC_IMS_ENABLEDboolWiFi通话是否启用
WFC_IMS_MODEintWiFi优先/移动优先
数据/APNMETERED_APN_TYPESstr[]按流量计费的APN
ALLOW_ADDING_APNSbool允许用户添加APN
READ_ONLY_APN_TYPESstr[]只读APN类型
5G/网络NR_AVAILABILITYint5G支持(NSA/SA)
PREFERRED_NETWORK_MODEint首选网络模式
通话功能ALLOW_TRANSFER_IMS_CALLboolIMS通话转接
ALLOW_DEFLECT_IMS_CALLboolIMS通话拒接
热点/共享SUPPORTS_TETHERINGbool支持热点共享
REQUIRE_ENTITLEMENT_CHECKSbool热点权限检查
紧急呼救EMERGENCY_OVER_IMSint[]IMS紧急呼救
EMERGENCY_OVER_CSint[]CS紧急呼救
其他DEFAULT_MTUintMTU大小(字节)
CONFIG_VERSIONstr配置版本号

第11层:文件存储位置

/data/user/0/com.android.phone/
├── carrier_config_<ICCID>_<CARRIER_ID>.xml    # 缓存的运营商配置
├── carrier_config_default.xml                  # 默认配置缓存
└── no_sim_carrier_config_<CARRIER_ID>.xml     # 无SIM时的配置

第12层:常见问题处理

public class CarrierConfigDebug {
    
    // 问题1: 如何强制重新加载配置
    public void forceReloadConfig(Context context, int subId) {
        CarrierConfigManager ccm = 
            context.getSystemService(CarrierConfigManager.class);
        
        // 通知配置已变更,强制重新加载
        ccm.notifyConfigChangedForSubId(subId);
    }
    
    // 问题2: 如何检查是否使用了默认配置
    public boolean isUsingDefaultConfig(PersistableBundle config) {
        // 检查是否来自已识别的运营商
        return !CarrierConfigManager.isConfigForIdentifiedCarrier(config);
    }
    
    // 问题3: 如何查看当前加载的配置版本
    public String getConfigVersion(Context context, int subId) {
        CarrierConfigManager ccm = 
            context.getSystemService(CarrierConfigManager.class);
        
        PersistableBundle config = ccm.getConfigForSubId(subId);
        return config.getString(
            CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING,
            "Unknown"
        );
    }
    
    // 问题4: 调试日志输出
    public void dumpCarrierConfig(Context context, int subId, PrintWriter pw) {
        CarrierConfigManager ccm = 
            context.getSystemService(CarrierConfigManager.class);
        
        PersistableBundle config = ccm.getConfigForSubId(subId);
        pw.println("Carrier Config for subId=" + subId);
        pw.println("Is Identified: " + 
            CarrierConfigManager.isConfigForIdentifiedCarrier(config));
        pw.println("Version: " + 
            config.getString(KEY_CARRIER_CONFIG_VERSION_STRING));
        
        for (String key : config.keySet()) {
            Object value = config.get(key);
            pw.println("  " + key + " = " + value);
        }
    }
}

这就是完整的 Android CarrierConfig 系统!它是运营商定制行为的核心机制。