04 · 平台侧受理与执行(深入)

平台源码:/home/zbc/pangu/yu7/miui/frameworks/telephony/。 本篇回答一个问题:点了「中国移动」之后,平台到底干了什么?为什么”成功了”网却没切? 平台 telephony 对接人:庄员 zhuangyuan@xiaomi.com(2026-08-31 亲述确认)。

1. 调用链全景

sequenceDiagram
    autonumber
    participant APP as MiCarSettings<br/>TelephonyUtil(反射)
    participant EX as TelephonyManagerEx<br/>(抽象类 :117-118)
    participant IMPL as TelephonyManagerImpl<br/>:736-758
    participant AIDL as IAutoTelephony(binder)
    participant APIM as AutoPhoneInterfaceManager<br/>(radio 进程)
    participant MIRC as MultiInternetRouteController<br/>受理层
    participant SDCC as SmartDataChannelController<br/>执行层

    APP->>EX: setUserDefaultChannel(1)
    EX->>IMPL: (多实现之一)
    IMPL->>IMPL: getAutoTelephony()
    IMPL->>AIDL: manager.setUserDefaultChannel(1)<br/>异常→catch 返回 false(:742-745)
    AIDL->>APIM: binder 跨进程
    APIM->>MIRC: setUserDefaultChannel(1)
    MIRC->>MIRC: isValidChannel? (:394)<br/>否 → return false
    MIRC->>MIRC: ==当前值? (:398)<br/>是 → return false("already set")
    MIRC->>MIRC: 写 Settings.Global[HMI_DATA_SIM_APN]=1 (:402)
    alt channel == 2(智能双卡 WISDOM)
        MIRC-->>APP: return true(不触发切换,:405-406)
    else channel 0/1
        MIRC->>SDCC: setApnDefaultChannel(MULTI_INTERNET_2, 1, REASON_HMI_SET)
        SDCC->>SDCC: phoneId 无效→false<br/>rat 非 LTE/NR→false("ignore due to rat=0 !")<br/>否则 updateDataChannel 真切(:1709-1725)
        SDCC--xMIRC: 返回值被丢弃!
        MIRC-->>APP: **无条件 return true**(:409)
    end

2. 关键文件与行号

环节文件:行号要点
抽象 APItelephony/common/base/java/android/telephony/TelephonyManagerEx.java:117-118setUserDefaultChannel/getUserDefaultChannel 抽象方法
实现转发.../TelephonyManagerImpl.java:736-758经 getAutoTelephony() 拿 binder,异常兜底 false/-1
binder 接口.../base/java/android/telephony/IAutoTelephony.aidl跨进程接口
radio 侧入口.../telephony/auto/com/android/phone/AutoPhoneInterfaceManager.javaaidl 实现,转调控制器
受理层.../auto/com/android/phone/data/MultiInternetRouteController.java:388-410校验→写 key→转发→恒 true
执行层.../auto/com/android/phone/data/SmartDataChannelController.java:1709-1725rat 校验→updateDataChannel
key 常量MultiInternetRouteController.java:44-45DEFAULT_DATA_SIM_APN / HMI_DATA_SIM_APN

3. 受理层:MultiInternetRouteController.setUserDefaultChannel(:388-410)

public boolean setUserDefaultChannel(int channel) {
    if (!isValidChannel(channel)) return false;          // 非法值才 false
    if (getUserDefaultChannel() == channel) return false; // 重复设置才 false("already set")
    Settings.Global.putInt(cr, getHMIDefaultChannelSettingName(), channel);  // 先记偏好
    if (SmartDataChannelController.getInstance() != null) {
        if (channel == WISDOM_DATA_CHANNEL) {
            return true;                                  // 智能双卡:不触发即时切换
        }
        SmartDataChannelController.getInstance()
            .setApnDefaultChannel(MULTI_INTERNET_2, channel, REASON_HMI_SET);
        //              ↑↑↑ 返回值没!人!接!
    }
    return true;                                          // 恒 true(受理语义)
}

读侧(:416-418)就是把 HMI_DATA_SIM_APN 读出来,默认 WISDOM_DATA_CHANNEL(2):

public int getUserDefaultChannel() {
    return Settings.Global.getInt(cr, getHMIDefaultChannelSettingName(), WISDOM_DATA_CHANNEL);
}

4. 执行层:SmartDataChannelController.setApnDefaultChannel(:1709-1725)

public boolean setApnDefaultChannel(MultiInternetEnum item, int phoneId, int reason) {
    if (!isValidatePhoneId(phoneId)) return false;
    int rat = getCurRatByPhoneId(phoneId);          // 取该卡当前数据网络制式
    if (!isLteNrNwType(rat)) {                       // 必须是 LTE/NR(在网)
        localLog("setApnDefaultChannel ignore due to rat=" + rat + " !");
        return false;                                // 防护:无服务卡不切
    }
    updateDataChannel(item, phoneId, reason, isNowDsda() ? false : true);
    return true;
}

rat=0(无服务)防护是正确行为——强行把数据通道切到一张无服务的卡=整车断网。 问题不在防护本身,而在防护结果(false)没有回传给调用方。

5. 受理/执行分离:本模块最重要的设计事实

flowchart LR
    subgraph 受理["受理层(同步返回)"]
        A1[校验合法性] --> A2[写 HMI_DATA_SIM_APN]
        A2 --> A3[return true]
    end
    subgraph 执行["执行层(尽力而为)"]
        B1[rat 校验] -->|通过| B2[updateDataChannel<br/>真正切路由]
        B1 -->|rat=0 等| B3["localLog ignore<br/>return false → 被丢弃"]
    end
    受理 --> 执行
    A3 -. "UI 认为切换成功" .-> U["App Tab 选中保持"]
    B3 -. "实际路由没动" .-> N["网络仍在原卡<br/>右侧面板不变"]

契约缺陷的两层改进方向(N801PROB-138847 复盘结论):

层现状改进项
平台setApnDefaultChannel 的 false 没人接,无失败回调、无可用性查询 API执行失败回传(改 false 或回调)
App三 Tab 硬编码,无在位卡门控,点击不可达偏好零反馈按活跃 sub 数门控 Tab + 失败提示

6. 智能双卡(channel=2)的语义

  • App 选「智能双卡」→ 平台只写 HMI_DATA_SIM_APN=2,不做即时切换(:405-406)
  • 真正的自动倒换由平台策略引擎驱动:MultiInternetPolicyEvent(MODE_LOW_COST / MODE_CONCURRENCY 等模式,:230-250)+ SmartDataChannelController 监听两张卡的 rat/信号质量,满足条件时自动 updateDataChannel
  • 两套云端通道偏好写在 DEFAULT_DATA_SIM_APN{apnNumber} 系列 key(:266,:273-275)
  • 所以「智能双卡」模式下 UI 显示选中态和当前实际数据通道本来就解耦——右侧面板 显示哪张卡,取决于平台当前把路由放在哪张卡

7. DDS 与路由的关系(排障判据)

执行层真切了的话,dumpsys 里应该看到:

  • defaultDataSubId / activeDataSubId 迁移到目标 sub
  • current route map 中 MULTI_INTERNET_2=<目标 phoneId>

138847 案里这两项全程没动(defaultDataSubId=1 恒为电信、MULTI_INTERNET_2=0), 是”执行从未发生”的裁决性证据。排查命令见 06 篇速查卡。