modem中同样存储了APN,为啥

14 阅读5分钟

为什么 Modem 中也需要存储 APN?

1. 核心原因总结

Modem 中存储 APN 主要有以下关键原因

1.1 快速响应场景

场景为什么需要 Modem 存储 APN
Initial Attach(初始附着)设备开机后,Android 可能还未启动完成,但 Modem 需要立即连接到网络
飞行模式切换飞行模式关闭后,Modem 需要快速重新附着到网络
网络重选/切换网络切换时,Modem 需要快速建立数据连接
紧急呼叫即使 Android 系统崩溃,Modem 也能建立紧急数据连接

2. Initial Attach(初始附着)详解

2.1 什么是 Initial Attach?

Initial Attach 是设备开机后第一次连接到网络的过程,此时:

  • Android 系统可能还未完全启动
  • Framework 层的 APN 数据库还未读取
  • 但 Modem 必须立即连接到网络以注册到运营商

2.2 Initial Attach 的工作流程

┌──────────────────────────────────────────────────┐
│  1. 设备开机 / 飞行模式关闭                         │
└───────────────────┬──────────────────────────────┘
                    │
                    ↓
┌──────────────────────────────────────────────────┐
│  2. Modem 启动,需要附着到网络                      │
│     • Android 系统还未完全启动                     │
│     • Framework 层 APN 数据库未加载                │
└───────────────────┬──────────────────────────────┘
                    │
                    ↓
┌──────────────────────────────────────────────────┐
│  3. Modem 使用**存储在 Modem 中的 APN**            │
│     • 这些 APN 是之前通过 setInitialAttachApn()   │
│       同步到 Modem 的                              │
└───────────────────┬──────────────────────────────┘
                    │
                    ↓
┌──────────────────────────────────────────────────┐
│  4. Modem 成功附着到网络                           │
│     • 设备可以接收短信、来电                        │
│     • 基本数据连接建立                             │
└───────────────────┬──────────────────────────────┘
                    │
                    ↓
┌──────────────────────────────────────────────────┐
│  5. Android 系统完全启动后                         │
│     • Framework 重新评估 APN 配置                 │
│     • 如有必要,更新 Modem 中的 APN                │
└──────────────────────────────────────────────────┘

3. Persistent Data Profile(持久化数据配置)

3.1 什么是 Persistent?

// RILUtils.java
// profile id is only meaningful when it's persistent on the modem.
dpi.profileId = (dpi.persistent) ? dp.getProfileId()
        : android.hardware.radio.data.DataProfileInfo.ID_INVALID;

persistent 标志

  • true:该 APN 配置会存储在 Modem 的非易失性存储器
  • false:该 APN 配置仅在当前会话有效,重启后丢失

3.2 为什么需要 Persistent?

// DataProfileManager.java
/**
 * Update the data profile used for initial attach.
 */
private void updateInitialAttachDataProfileAtModem(boolean forceUpdateIa) {
    DataProfile initialAttachDataProfile = null;
    
    // 搜索支持 Initial Attach 的 APN
    for (int apnType : mDataConfigManager.getAllowedInitialAttachApnTypes()) {
        initialAttachDataProfile = allDataProfiles.stream()
                .filter(dp -> dp.canSatisfy(DataUtils.apnTypeToNetworkCapability(apnType)))
                .findFirst()
                .orElse(null);
        if (initialAttachDataProfile != null) break;
    }
    
    if (forceUpdateIa || !Objects.equals(mInitialAttachDataProfile, initialAttachDataProfile)) {
        mInitialAttachDataProfile = initialAttachDataProfile;
        logl("Initial attach data profile updated as " + mInitialAttachDataProfile);
        
        // 发送到 Modem,Modem 会持久化存储
        mWwanDataServiceManager.setInitialAttachApn(mInitialAttachDataProfile,
                mPhone.getServiceState().getDataRoamingFromRegistration(), null);
    }
}

关键点

  1. Android 选择合适的 Initial Attach APN
  2. 通过 setInitialAttachApn() 发送到 Modem
  3. Modem 持久化存储该 APN
  4. 下次开机时,Modem 直接使用存储的 APN

4. Profile ID 的作用

4.1 Profile ID 概念

// RILUtils.java (line 956-961)
dpi.persistent = dp.isPersistent();
dpi.preferred = dp.isPreferred();

// profile id is only meaningful when it's persistent on the modem.
dpi.profileId = (dpi.persistent) ? dp.getProfileId()
        : android.hardware.radio.V1_0.DataProfileId.INVALID;

Profile ID

  • 是 Modem 中 APN 配置的唯一标识符
  • 只有 persistent = true 的 Data Profile 才有有效的 Profile ID
  • 用于在 Modem 中快速查找和引用 APN 配置

4.2 Profile ID 的使用场景

// DataProfileManager.java
/**
 * Update the data profiles at modem.
 */
private void updateDataProfilesAtModem() {
    log("updateDataProfilesAtModem: set " + mAllDataProfiles.size() + " data profiles.");
    // 将所有 Data Profile 发送到 Modem
    mWwanDataServiceManager.setDataProfile(mAllDataProfiles,
            mPhone.getServiceState().getDataRoamingFromRegistration(), null);
}

Modem 会

  1. 接收所有 Data Profile
  2. persistent = true 的 Profile 分配 Profile ID
  3. 存储到 Modem 的非易失性存储器
  4. 在需要时通过 Profile ID 快速查找

5. 两层存储架构的对比

5.1 Android Framework 层存储

// DataProfileManager.java
// APN 数据库查询
Cursor cursor = mPhone.getContext().getContentResolver().query(
        Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/"
                + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID);

存储位置

  • 数据库/data/user_de/0/com.android.providers.telephony/databases/telephony.db
  • 表名carriers
  • 特点
    • ✅ 灵活,易于修改
    • ✅ 支持复杂查询和过滤
    • ❌ 依赖 Android 系统启动
    • ❌ 系统崩溃后无法访问

5.2 Modem 层存储

存储位置

  • Modem 的非易失性存储器(NVRAM/EFS)
  • 由 Modem Firmware 直接管理

特点

  • 独立于 Android 系统
  • 开机即可用,无需等待系统启动
  • 紧急场景可用(如系统崩溃)
  • ❌ 存储容量有限(通常只存储几个关键 APN)
  • ❌ 修改需要通过 RIL 接口

6. 实际应用场景

6.1 场景 1:设备首次开机

时间线:
T0: 用户按下电源键
T1: Modem 固件启动(Android 未启动)
T2: Modem 需要附着到网络
    → 使用 Modem 中存储的 Initial Attach APN ✅
T3: Android 系统启动
T4: Framework 读取 APN 数据库
T5: Framework 评估并更新 Modem 中的 APN(如有需要)

如果没有 Modem 存储

  • T2 时刻,Modem 无法附着到网络 ❌
  • 用户在 T2-T5 期间无法接收短信和来电

6.2 场景 2:飞行模式快速切换

// 用户:飞行模式 ON → OFF
1. Modem 重新启动
2. Modem 立即使用存储的 APN 附着到网络 ✅
3. 用户几秒内就能上网

如果没有 Modem 存储

  • Modem 需要等待 Android Framework 重新配置 APN
  • 用户体验延迟 5-10 秒 ❌

6.3 场景 3:紧急呼叫(Emergency Call)

// DataProfileManager.java
// 添加默认 EIMS APN
if (dataProfile == null) {
    profiles.add(new DataProfile.Builder()
            .setApnSetting(buildDefaultApnSetting("DEFAULT EIMS", "sos",
                    ApnSetting.TYPE_EMERGENCY))
            .setTrafficDescriptor(new TrafficDescriptor("sos", null))
            .build());
    log("Added default EIMS data profile.");
}

Emergency APN (sos)

  • 必须存储在 Modem 中
  • 即使 Android 系统崩溃,Modem 也能建立紧急连接
  • 用于紧急呼叫的 IMS 注册

7. 同步机制

7.1 Android → Modem 同步

// DataProfileManager.java
private void updateDataProfiles(boolean forceUpdateIa) {
    // 1. 从数据库读取所有 APN
    List<DataProfile> profiles = new ArrayList<>();
    Cursor cursor = mPhone.getContext().getContentResolver().query(...);
    
    // 2. 更新 Initial Attach APN
    updateInitialAttachDataProfileAtModem(forceUpdateIa);
    
    // 3. 更新所有 Data Profile 到 Modem
    updateDataProfilesAtModem();
}

同步时机

  • SIM 卡插入
  • APN 数据库变化
  • 运营商配置更新
  • 用户手动修改 APN

7.2 Preferred Data Profile 同步

// DataProfileManager.java
private void setPreferredDataProfile(@Nullable DataProfile dataProfile) {
    logl("setPreferredDataProfile: " + dataProfile);
    
    // 1. 保存到 Android 数据库
    Uri uri = Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, subId);
    resolver.insert(uri, values);
    
    // 2. 标记为 preferred
    dataProfile.setPreferred(true);
    
    // 3. 同步到 Modem
    updateDataProfilesAtModem();
}

8. 存储限制和优化

8.1 Modem 存储容量限制

典型限制

  • 最多存储 10-20 个 Data Profile
  • Initial Attach APN:1 个
  • Emergency APN:1 个
  • 其他常用 APN:5-10 个

8.2 优先级策略

// DataProfileManager.java
// 排序优先级:preferred > IA > IMS > emergency > default
List<DataProfile> allDataProfiles = mAllDataProfiles.stream()
        .sorted(Comparator.comparing((DataProfile dp) -> !dp.equals(mPreferredDataProfile)))
        .toList();

Modem 只存储

  1. ✅ Initial Attach APN
  2. ✅ Preferred APN
  3. ✅ IMS APN(VoLTE)
  4. ✅ Emergency APN
  5. ✅ 最近成功连接的 APN

9. 总结

9.1 为什么需要双层存储?

存储位置优势劣势用途
Android Framework灵活、易修改、容量大依赖系统启动管理所有 APN,动态选择
Modem独立、快速、开机即用容量有限、修改困难Initial Attach、紧急场景

9.2 关键设计原则

  1. 快速响应:Modem 存储确保开机后立即可用
  2. 容错性:即使 Android 崩溃,Modem 仍能工作
  3. 紧急保障:Emergency APN 必须在 Modem 中
  4. 同步一致性:Android 定期同步关键 APN 到 Modem

9.3 核心要点

┌─────────────────────────────────────────────────────┐
│  为什么 Modem 需要存储 APN?                         │
│                                                     │
│  1.Initial Attach 需要                          │
│     • 开机时 Android 未启动,Modem 需要立即附着    │
│                                                     │
│  2. 🚨 紧急场景需要                                 │
│     • 系统崩溃时仍能紧急呼叫                        │
│                                                     │
│  3. 🚀 快速恢复需要                                 │
│     • 飞行模式切换快速重连                          │
│                                                     │
│  4. 🔄 网络切换需要                                 │
│     • 网络重选时快速建立连接                        │
└─────────────────────────────────────────────────────┘

希望这个详细解析帮助您深入理解为什么 Modem 中也需要存储 APN!这是 Android Telephony 架构中的一个重要设计决策。🚀