Android 的电话子系统是平台中最复杂、分层最多的模块之一。它从任意应用都可以调用的公开 SDK API(TelephonyManager、SmsManager),经过拥有特权的系统服务(PhoneInterfaceManager)、内部的 phone 对象层级、向蜂窝调制解调器序列化请求的无线接口层(RIL),最终到由硬件厂商实现的 AIDL HAL 层。本章会追踪 AOSP 源码中整条调用链的每一个环节,讲解 SIM、SMS、IMS、运营商配置以及数据连接的内部机制,并提供实操练习,用于在真机或模拟器上探索整个协议栈。
36.1 电话架构
36.1.1 整体概览
Android 电话模块分为四大层,每一层运行在不同进程或者地址空间:
- 应用层:第三方应用或系统应用,调用公开的 TelephonyManager、SmsManager、SubscriptionManager 或 TelecomManager API。
- 框架层:运行在
com.android.phone进程内的电话服务,包含 PhoneInterfaceManager(ITelephony 的 Binder 存根)以及 Phone 对象层级。 - RIL 层:RIL.java 类,将高层命令转换为发往厂商无线守护进程的 AIDL/HIDL 调用。
- HAL / 调制解调器层:厂商提供的无线 HAL 实现(IRadioModem、IRadioSim、IRadioNetwork 等),负责和基带处理器通信。
电话框架代码分布在 AOSP 源码树的多个独立仓库中,关键源码路径如下:
| 分层 | 路径 | 说明 |
|---|---|---|
| 公开 API | frameworks/base/telephony/java/android/telephony/ | TelephonyManager(19705 行)、SubscriptionManager、SmsManager、CarrierConfigManager |
| 内部框架 | frameworks/opt/telephony/src/java/com/android/internal/telephony/ | Phone(5408 行)、GsmCdmaPhone(4333 行)、RIL(6017 行)、ServiceStateTracker、CommandsInterface |
| Phone 进程 | packages/services/Telephony/src/com/android/phone/ | PhoneInterfaceManager(14737 行)、PhoneGlobals、CarrierConfigLoader |
| 电话模块 | packages/modules/Telephony/ | Mainline 模块化电话代码(apex、framework、libs) |
| 无线 HAL | hardware/interfaces/radio/aidl/ | 基于 AIDL 的 HAL 接口:调制解调器、SIM、网络、数据、语音、消息、IMS |
| Telecom | packages/services/Telecomm/ | CallsManager、呼叫路由、InCallService 绑定 |
源码参考 —— 接收来自 TelephonyManager 所有 Binder 调用的顶层类:
// packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java public class PhoneInterfaceManager extends ITelephony.Stub {36.1.2 TelephonyManager —— 公开入口
TelephonyManager 是电话协议栈对外暴露的 SDK 入口,使用@SystemService注解:
// frameworks/base/telephony/java/android/telephony/TelephonyManager.java @SystemService(Context.TELEPHONY_SERVICE) public class TelephonyManager {应用通过Context.getSystemService(TelephonyManager.class)获取该实例。在内部,TelephonyManager 的每一个方法都会通过 Binder IPC 转发到ITelephony.Stub.Proxy,最终调用 phone 进程中的 PhoneInterfaceManager。
getNetworkOperatorName()调用简化流程:
TelephonyManager 主要公开 API 分组:
- 设备标识:
getImei()、getMeid()、getDeviceId() - SIM 信息:
getSimState()、getSimOperator()、getSimSerialNumber() - 网络状态:
getNetworkType()、getNetworkOperatorName()、getServiceState() - 呼叫状态:
getCallState()、listen()(已废弃)、registerTelephonyCallback() - 数据:
getDataState()、getDataNetworkType()、isDataEnabled() - 无线控制(需要特权):
setRadioPower()、setPreferredNetworkType()
36.1.3 PhoneInterfaceManager —— Binder 网关
PhoneInterfaceManager 位于packages/services/Telephony/,继承ITelephony.Stub。该类共 14737 行,是整个电话协议栈中代码量最大的类。它承担三项核心职责:
- 权限校验:每个方法都会校验调用方 UID,核对所需权限(READ_PHONE_STATE、MODIFY_PHONE_STATE、READ_PRIVILEGED_PHONE_STATE、运营商特权等)。
- Phone 实例选择:针对多 SIM 设备,通过 PhoneFactory 将调用方的订阅 ID 映射到正确的 Phone 对象。
- 请求转发:调用内部 Phone 层级对象并返回执行结果。
权限校验代码示例:
// packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java public String getImeiForSlot(int slotIndex, String callingPackage, String callingFeatureId) { enforceReadPrivilegedPermission("getImeiForSlot"); Phone phone = PhoneFactory.getPhone(slotIndex); return phone != null ? phone.getImei() : null; }36.1.4 Phone 类继承体系
内部抽象类 Phone 是电话框架的核心。它继承 Handler(用于处理调制解调器的异步响应),定义协议栈其余部分调用的通用接口。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java public abstract class Phone extends Handler implements PhoneInternalInterface {类继承关系:
GsmCdmaPhone 是 GSM 与 CDMA 网络的统一实现(Android7 中完成合并)。PhoneFactory 会为每一个 SIM 卡槽实例化该类:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java public class GsmCdmaPhone extends Phone { public static final String LOG_TAG = "GsmCdmaPhone"; ... public GsmCdmaCallTracker mCT; public ServiceStateTracker mSST; public EmergencyNumberTracker mEmergencyNumberTracker;ImsPhone 作为叠加层 Phone,处理 IMS(LTE/Wi‑Fi 语音)呼叫。呼叫控制委托给 ImsPhoneCallTracker:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/imsphone/ImsPhone.java package com.android.internal.telephony.imsphone;36.1.5 PhoneFactory —— 协议栈初始化
PhoneFactory 是静态工厂类,在开机阶段完成各组件的装配。PhoneGlobals.onCreate()调用PhoneFactory.makeDefaultPhones(),完成以下工作:
- 创建 CommandsInterface 数组(每个调制解调器对应一个 RIL 实例)。
- 创建 UiccController(UICC/SIM 单例管理器)。
- 创建 GsmCdmaPhone 数组(每个 SIM 卡槽对应一个实例)。
- 创建 PhoneSwitcher(用于多 SIM 数据切换)。
- 创建 SubscriptionManagerService。
- 创建 EuiccController(用于 eSIM 管理)。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java public class PhoneFactory { static private Phone[] sPhones = null; static private CommandsInterface[] sCommandsInterfaces = null; static private UiccController sUiccController; ... public static void makeDefaultPhones(Context context, @NonNull FeatureFlags featureFlags) {完整开机启动序列:
36.1.6 关键事件常量
Phone 基类定义大量事件常量,供 Handler 消息循环使用,驱动异步状态机:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java protected static final int EVENT_RADIO_AVAILABLE = 1; protected static final int EVENT_SSN = 2; protected static final int EVENT_SIM_RECORDS_LOADED = 3; private static final int EVENT_MMI_DONE = 4; protected static final int EVENT_RADIO_ON = 5; protected static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; protected static final int EVENT_USSD = 7; public static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; private static final int EVENT_GET_SIM_STATUS_DONE = 11; protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; protected static final int EVENT_CALL_RING = 14; private static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 16; private static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17; protected static final int EVENT_SET_CLIR_COMPLETE = 18; protected static final int EVENT_REGISTERED_TO_NETWORK = 19; protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 21; public static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 25; protected static final int EVENT_SRVCC_STATE_CHANGED = 31; protected static final int EVENT_CARRIER_CONFIG_CHANGED = 43; protected static final int EVENT_MODEM_RESET = 45; protected static final int EVENT_RADIO_STATE_CHANGED = 47; protected static final int EVENT_REGISTRATION_FAILED = 57; protected static final int EVENT_BARRING_INFO_CHANGED = 58; protected static final int EVENT_LINK_CAPACITY_CHANGED = 59; protected static final int EVENT_SUBSCRIPTIONS_CHANGED = 62; protected static final int EVENT_CELL_IDENTIFIER_DISCLOSURE = 72; protected static final int EVENT_SECURITY_ALGORITHM_UPDATE = 74; protected static final int EVENT_LAST = EVENT_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED_DONE;当前代码中事件编号最大到 75,历经多年迭代,从最初仅支持 GSM,逐步增加 CDMA、IMS、安全通知以及 5G NR 相关能力。
36.1.7 Phone 实例变量与子组件
Phone 基类持有大量子组件引用,分别管理电话各个业务模块:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java public CommandsInterface mCi; protected DataNetworkController mDataNetworkController; protected CarrierSignalAgent mCarrierSignalAgent; protected CarrierActionAgent mCarrierActionAgent; public SmsStorageMonitor mSmsStorageMonitor; public SmsUsageMonitor mSmsUsageMonitor; protected DeviceStateMonitor mDeviceStateMonitor; protected DisplayInfoController mDisplayInfoController; protected AccessNetworksManager mAccessNetworksManager; protected CarrierResolver mCarrierResolver; protected SignalStrengthController mSignalStrengthController; protected Phone mImsPhone = null; protected UiccController mUiccController = null;协议栈大量使用注册者模式实现观察者通知:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); private final RegistrantList mHandoverRegistrants = new RegistrantList(); private final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList(); private final RegistrantList mIncomingRingRegistrants = new RegistrantList(); protected final RegistrantList mDisconnectRegistrants = new RegistrantList(); private final RegistrantList mServiceStateRegistrants = new RegistrantList(); protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList(); protected final RegistrantList mMmiRegistrants = new RegistrantList();RegistrantList实现贯穿整个电话协议栈的观察者模式。组件调用registerForXxx()完成注册,事件触发时接收 Message 回调。
36.1.8 GsmCdmaPhone 构造函数 —— 组件装配
GsmCdmaPhone 构造函数演示所有子组件的创建与关联,通过 TelephonyComponentFactory 完成依赖注入:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory, ImsManagerFactory imsManagerFactory, @NonNull FeatureFlags featureFlags) { super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA", notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory, featureFlags); mPrecisePhoneType = precisePhoneType; mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this, featureFlags); mImsManagerFactory = imsManagerFactory; initOnce(ci); initRatSpecific(precisePhoneType); // CarrierSignalAgent构造依赖CarrierActionAgent,因此需要先创建CarrierActionAgent mCarrierActionAgent = mTelephonyComponentFactory.inject(CarrierActionAgent.class.getName()) .makeCarrierActionAgent(this); mCarrierSignalAgent = mTelephonyComponentFactory.inject(CarrierSignalAgent.class.getName()) .makeCarrierSignalAgent(this); mAccessNetworksManager = mTelephonyComponentFactory .inject(AccessNetworksManager.class.getName()) .makeAccessNetworksManager(this, getLooper(), featureFlags); mSignalStrengthController = mTelephonyComponentFactory.inject( SignalStrengthController.class.getName()).makeSignalStrengthController(this); mSST = mTelephonyComponentFactory.inject(ServiceStateTracker.class.getName()) .makeServiceStateTracker(this, this.mCi, featureFlags); ... mDataNetworkController = mTelephonyComponentFactory.inject( DataNetworkController.class.getName()) .makeDataNetworkController(this, getLooper(), featureFlags);工厂模式(TelephonyComponentFactory)允许测试代码注入 Mock 对象,这对完整的电话单元测试套件至关重要。
36.1.9 ServiceStateTracker —— 网络注册
ServiceStateTracker(SST)是最重要的子组件之一。持续监控并上报设备在蜂窝网络中的注册状态。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.javaSST 轮询调制解调器获取注册状态变更,处理网络主动上报事件,维护供协议栈其他模块查询的 ServiceState 对象。ServiceState 包含:
- 语音注册状态(服务可用、仅紧急呼叫、无服务)
- 数据注册状态
- 无线接入技术(LTE、NR、WCDMA 等)
- 漫游状态
- 运营商名称和 PLMN 编码
- 小区标识(小区 ID、TAC 等)
- NR 状态(已连接、无限制、受限)
36.1.10 电话模块(Mainline)
Android12 开始,部分电话协议栈组件模块化,作为 Mainline 模块:
packages/modules/Telephony/ apex/ -- Telephony APEX定义 framework/ -- 模块框架代码 libs/ -- 共享库 flags/ -- 功能开关 tests/ -- 模块测试用例Google 可以通过应用商店推送电话模块更新,无需完整系统升级。APEX 包含com.android.telephony模块,打包框架组件,可选择性包含电话服务。
36.1.11 安全相关说明
电话协议栈处理敏感数据(IMSI、手机号、SMS 内容),强制严格的权限边界:
| 权限 | 保护级别 | 授予能力 |
|---|---|---|
| READ_PHONE_STATE | dangerous | 手机号、呼叫状态、网络运营商 |
| READ_PHONE_NUMBERS | dangerous | 仅手机号读取 |
| CALL_PHONE | dangerous | 发起呼出呼叫 |
| SEND_SMS | dangerous | 发送短信 |
| READ_SMS | dangerous | 读取短信数据库 |
| RECEIVE_SMS | dangerous | 接收短信广播 |
| MODIFY_PHONE_STATE | signature|privileged | 无线开关、网络模式 |
| READ_PRIVILEGED_PHONE_STATE | signature|privileged | IMEI、IMSI |
| CARRIER_PRIVILEGES | 动态(基于 SIM 卡) | 运营商特权操作 |
新版 Android 增加蜂窝安全透明相关特性:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java protected static final int EVENT_CELL_IDENTIFIER_DISCLOSURE = 72; protected static final int EVENT_SECURITY_ALGORITHM_UPDATE = 74;当使用空加密套件或者检测到 IMSI 捕获器时通知用户。相关类:
frameworks/opt/telephony/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java frameworks/opt/telephony/src/java/com/android/internal/telephony/security/NullCipherNotifier.java frameworks/opt/telephony/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java36.2 无线接口层(RIL)
36.2.1 概述
无线接口层是 Java 电话框架和厂商调制解调器固件之间的桥梁。早期 RIL 是 C 语言守护进程 rild,通过 Unix 套接字、自定义二进制协议与框架通信。Android12 及以后迁移到稳定 AIDL HAL,把旧的单体 IRadio HIDL 接口拆分为多个按业务域划分的 AIDL 接口。
36.2.2 RIL.java —— Java 层实现
RIL.java 实现所有 Phone 对象调用的 CommandsInterface 接口,共 6017 行,负责异步请求‑响应流程的调度。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java public class RIL extends BaseCommands implements CommandsInterface { static final String RILJ_LOG_TAG = "RILJ"; static final String RILJ_WAKELOCK_TAG = "*telephony-radio*";该类为每个 HAL 业务域维护独立服务代理对象:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java private RadioResponse mRadioResponse; private RadioIndication mRadioIndication; private volatile IRadio mRadioProxy = null; private DataResponse mDataResponse; private DataIndication mDataIndication; private ImsResponse mImsResponse; private ImsIndication mImsIndication; private MessagingResponse mMessagingResponse; private MessagingIndication mMessagingIndication; private ModemResponse mModemResponse; private ModemIndication mModemIndication; private NetworkResponse mNetworkResponse; private NetworkIndication mNetworkIndication; private SimResponse mSimResponse; private SimIndication mSimIndication; private VoiceResponse mVoiceResponse; private VoiceIndication mVoiceIndication;全部服务代理保存在 SparseArray 中,以 HAL 服务类型作为 key:
private SparseArray<RadioServiceProxy> mServiceProxies = new SparseArray<>();36.2.3 CommandsInterface —— 抽象边界
CommandsInterface 定义电话框架可以向调制解调器发起的全部操作集合,包含同步请求命令,以及非主动上报事件的注册接口。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/CommandsInterface.java public interface CommandsInterface { // 呼叫转移常量 static final int CF_ACTION_DISABLE = 0; static final int CF_ACTION_ENABLE = 1; static final int CF_ACTION_REGISTRATION = 3; static final int CF_ACTION_ERASURE = 4; static final int CF_REASON_UNCONDITIONAL = 0; static final int CF_REASON_BUSY = 1; static final int CF_REASON_NO_REPLY = 2; static final int CF_REASON_NOT_REACHABLE = 3; static final int CF_REASON_ALL = 4; static final int CF_REASON_ALL_CONDITIONAL = 5; // IMS能力 int IMS_MMTEL_CAPABILITY_VOICE = 1 << 0; int IMS_MMTEL_CAPABILITY_VIDEO = 1 << 1; int IMS_MMTEL_CAPABILITY_SMS = 1 << 2; int IMS_RCS_CAPABILITIES = 1 << 3;主要请求命令分类:
| 分类 | 示例方法 |
|---|---|
| 语音 | dial()、acceptCall()、hangupConnection()、conference() |
| 数据 | setupDataCall()、deactivateDataCall()、getDataCallList() |
| 网络 | setNetworkSelectionModeAutomatic()、getAvailableNetworks()、setAllowedNetworkTypesBitmap() |
| SIM | getIccCardStatus()、supplyIccPin()、iccIO()、changeIccPin() |
| 短信 | sendSMS()、acknowledgeLastIncomingGsmSms()、writeSmsToSim() |
| 调制解调器 | setRadioPower()、getBasebandVersion()、getDeviceIdentity() |
36.2.4 HAL 版本演进
RIL 类维护支持的 HAL 版本,用于向后兼容:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java public static final HalVersion RADIO_HAL_VERSION_1_1 = new HalVersion(1, 1); public static final HalVersion RADIO_HAL_VERSION_1_2 = new HalVersion(1, 2); public static final HalVersion RADIO_HAL_VERSION_1_3 = new HalVersion(1, 3); public static final HalVersion RADIO_HAL_VERSION_1_4 = new HalVersion(1, 4); public static final HalVersion RADIO_HAL_VERSION_1_5 = new HalVersion(1, 5); public static final HalVersion RADIO_HAL_VERSION_1_6 = new HalVersion(1, 6); public static final HalVersion RADIO_HAL_VERSION_2_0 = new HalVersion(2, 0); public static final HalVersion RADIO_HAL_VERSION_2_1 = new HalVersion(2, 1); public static final HalVersion RADIO_HAL_VERSION_2_2 = new HalVersion(2, 2); public static final HalVersion RADIO_HAL_VERSION_2_3 = new HalVersion(2, 3); public static final HalVersion RADIO_HAL_VERSION_2_4 = new HalVersion(2, 4);1.x 版本使用传统单体 HIDL IRadio 接口;2.0 + 是现代拆分式 AIDL HAL。当 AIDL 服务不可用时,RIL 会自动降级回 HIDL,使用兼容映射表:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java private final ConcurrentHashMap<Integer, HalVersion> mCompatOverrides = new ConcurrentHashMap<>();36.2.5 AIDL 无线 HAL 接口
Android13 起,无线 HAL 由hardware/interfaces/radio/aidl/下一组 AIDL 接口定义。每个接口添加@VintfStability注解,保障厂商接口稳定性。
7 个业务域接口与源码路径:
| 接口 | 路径 | 职责 |
|---|---|---|
| IRadioModem | hardware/interfaces/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl | 无线电源、设备标识、基带版本、硬件配置 |
| IRadioSim | hardware/interfaces/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl | SIM PIN/PUK、ICC IO、电话本、运营商锁 |
| IRadioNetwork | hardware/interfaces/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl | 网络扫描、注册、信号强度、呼叫限制信息 |
| IRadioData | hardware/interfaces/radio/aidl/android/hardware/radio/data/IRadioData.aidl | 数据呼叫建立 / 释放、保活、QoS、网络切片 |
| IRadioVoice | hardware/interfaces/radio/aidl/android/hardware/radio/voice/IRadioVoice.aidl | 拨号、接听、挂断、DTMF、呼叫转移、USSD |
| IRadioMessaging | hardware/interfaces/radio/aidl/android/hardware/radio/messaging/IRadioMessaging.aidl | 短信收发、小区广播、MMS 支持 |
| IRadioIms | hardware/interfaces/radio/aidl/android/hardware/radio/ims/IRadioIms.aidl | IMS 注册信息、SRVCC、IMS 流量类型 |
每个业务域接口遵循三元组模式:
modem 域示例:
// hardware/interfaces/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl @VintfStability oneway interface IRadioModem { void enableModem(in int serial, in boolean on); void getBasebandVersion(in int serial); void getDeviceIdentity(in int serial); void getHardwareConfig(in int serial); void getModemActivityInfo(in int serial); ... }所有方法携带 serial 参数,框架用 serial 匹配异步响应;oneway代表单向调用,请求发出即返回,结果通过回调接口上报。
36.2.6 请求消息与非主动上报事件
RIL 通信模型分为两种流程:
- 请求消息:框架发出请求,等待对应响应。
- 非主动上报事件:调制解调器在没有收到请求的情况下主动推送通知。
常见非主动上报事件:
- radioStateChanged —— 调制解调器电源状态变更
- networkStateChanged —— 注册 / 漫游变更
- newSms —— 收到新短信
- callStateChanged —— 通话状态变更
- dataCallListChanged —— 数据承载状态变更
- simStatusChanged —— SIM 卡插拔状态变更
- signalStrengthUpdate —— 信号强度变化
36.2.7 唤醒锁管理
RIL 使用 Android 唤醒锁,在等待调制解调器响应期间保持设备唤醒。维护两组独立唤醒锁:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java public final WakeLock mWakeLock; // 请求/响应流程 public final WakeLock mAckWakeLock; // ack确认发送 ... private static final int DEFAULT_WAKE_LOCK_TIMEOUT_MS = 60000; private static final int DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS = 200;发送请求时获取请求唤醒锁;收到响应或超时后释放。待处理请求保存在 SparseArray:
SparseArray<RILRequest> mRequestList = new SparseArray<>();36.2.8 功能到服务映射
RIL 将 Android 功能标记映射到对应的 HAL 服务,当设备不支持某项能力时优雅降级:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java private static final Map<String, Integer> FEATURES_TO_SERVICES = Map.ofEntries( Map.entry(PackageManager.FEATURE_TELEPHONY_CALLING, HAL_SERVICE_VOICE), Map.entry(PackageManager.FEATURE_TELEPHONY_DATA, HAL_SERVICE_DATA), Map.entry(PackageManager.FEATURE_TELEPHONY_MESSAGING, HAL_SERVICE_MESSAGING), Map.entry(PackageManager.FEATURE_TELEPHONY_IMS, HAL_SERVICE_IMS) );HAL 服务常量定义在 TelephonyManager:
// frameworks/base/telephony/java/android/telephony/TelephonyManager.java public static final int HAL_SERVICE_RADIO = 0; public static final int HAL_SERVICE_DATA = 1; public static final int HAL_SERVICE_MESSAGING = 2; public static final int HAL_SERVICE_MODEM = 3; public static final int HAL_SERVICE_NETWORK = 4; public static final int HAL_SERVICE_SIM = 5; public static final int HAL_SERVICE_VOICE = 6; public static final int HAL_SERVICE_IMS = 7;36.2.9 死亡接收者与异常恢复
当无线 HAL 进程崩溃,RIL 通过 Binder 死亡接收者检测异常,尝试恢复:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java static final int EVENT_RADIO_PROXY_DEAD = 6; static final int EVENT_AIDL_PROXY_DEAD = 7;收到死亡通知后 RIL 执行:
- 将所有待处理请求标记为失败。
- 清空代理引用。
- 通知 ServiceStateTracker 与 DataNetworkController。
- 尝试重新绑定 HAL 服务。
36.2.10 RilHandler —— 内部事件处理
RIL 内部拥有独立 Handler 子类,处理超时、进程死亡事件:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java public class RilHandler extends Handler { @Override public void handleMessage(Message msg) { RILRequest rr; switch (msg.what) { case EVENT_WAKE_LOCK_TIMEOUT: // 没有收到上一次请求回复,判定不会收到响应,释放唤醒锁 synchronized (mRequestList) { if (msg.arg1 == mWlSequenceNum && clearWakeLock(FOR_WAKELOCK)) { if (mRadioBugDetector != null) { mRadioBugDetector.processWakelockTimeout(); } if (RILJ_LOGD) { int count = mRequestList.size(); riljLog("WAKE_LOCK_TIMEOUT mRequestList=" + count); for (int i = 0; i < count; i++) { rr = mRequestList.valueAt(i); riljLog(i + ": [" + rr.mSerial + "] " + RILUtils.requestToString(rr.mRequest)); } } } } break; case EVENT_ACK_WAKE_LOCK_TIMEOUT: if (msg.arg1 == mAckWlSequenceNum && clearWakeLock(FOR_ACK_WAKELOCK)) { if (RILJ_LOGV) riljLog("ACK_WAKE_LOCK_TIMEOUT"); } break; case EVENT_BLOCKING_RESPONSE_TIMEOUT: int serial = (int) msg.obj; rr = findAndRemoveRequestFromList(serial); if (rr == null) break; if (rr.mResult != null) { Object timeoutResponse = getResponseForTimedOutRILRequest(rr); AsyncResult.forMessage(rr.mResult, timeoutResponse, null); rr.mResult.sendToTarget(); } decrementWakeLock(rr); rr.release(); break; case EVENT_RADIO_PROXY_DEAD: // HIDL radio proxy died ... resetProxyAndRequestList(service); break; case EVENT_AIDL_PROXY_DEAD: // AIDL radio proxy died ... resetProxyAndRequestList(aidlService); break; } } }36.2.11 无线异常检测
RadioBugDetector 监控唤醒锁超时,自动检测调制解调器卡死:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java if (mRadioBugDetector != null) { mRadioBugDetector.processWakelockTimeout(); }调制解调器持续无响应时,检测器通过 AnomalyReporter 上报异常,触发诊断数据采集。
36.2.12 Binder 死亡处理
根据 HAL 绑定方式,RIL 使用两套死亡接收者机制:
HIDL(旧版):HwBinder.DeathRecipient
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java final class RadioProxyDeathRecipient implements HwBinder.DeathRecipient { @Override public void serviceDied(long cookie) { riljLog("serviceDied"); mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage( EVENT_RADIO_PROXY_DEAD, HAL_SERVICE_RADIO, 0, cookie)); } }AIDL(新版):IBinder.DeathRecipient
private final class BinderServiceDeathRecipient implements IBinder.DeathRecipient { private IBinder mBinder; private final int mService; @Override public void binderDied() { riljLog("Service " + serviceToString(mService) + " has died."); mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage( EVENT_AIDL_PROXY_DEAD, mService, 0, mLinkedFlags)); unlinkToDeath(); } }任意服务死亡后调用resetProxyAndRequestList():
- 清空服务代理引用。
- 为所有待处理请求返回错误响应。
- 释放全部持有的唤醒锁。
- 触发重连。
对于 AIDL 服务,一个服务重置会触发全部 AIDL 服务重置,因为它们通常运行在同一个厂商进程。
36.2.13 请求序列号与耗时统计
每一个 RIL 请求分配唯一 serial 编号。框架维护请求‑响应耗时直方图:
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java static SparseArray<TelephonyHistogram> sRilTimeHistograms = new SparseArray<>(); static final int RIL_HISTOGRAM_BUCKET_COUNT = 5; public static List<TelephonyHistogram> getTelephonyRILTimingHistograms() { List<TelephonyHistogram> list; synchronized (sRilTimeHistograms) { list = new ArrayList<>(sRilTimeHistograms.size()); for (int i = 0; i < sRilTimeHistograms.size(); i++) { TelephonyHistogram entry = new TelephonyHistogram(sRilTimeHistograms.valueAt(i)); list.add(entry); } } return list; }可通过TelephonyManager.requestModemActivityInfo()获取直方图,用于功耗统计和性能监控。
36.2.14 用于测试的 Mock 调制解调器
RIL 内置 Mock 调制解调器支持,无需真实硬件就可以做集成测试。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java private MockModem mMockModem;通过 TelephonyShellCommand 开启,把真实 HAL 服务代理替换为测试替身。MockModem 源码位置:
frameworks/opt/telephony/src/java/com/android/internal/telephony/MockModem.java测试脚本可实现:
- 模拟 SIM 卡插入 / 拔出
- 模拟网络注册状态变化
- 模拟来电、接收短信
- 模拟无线电源状态变更
36.2.15 从 HIDL 迁移到 AIDL
从 HIDL 到 AIDL 是一次重大架构变更:
HIDL 版本目录保留用于兼容:
hardware/interfaces/radio/1.0/ -- Android8(初代HIDL) hardware/interfaces/radio/1.1/ -- Android8.1 hardware/interfaces/radio/1.2/ -- Android9 hardware/interfaces/radio/1.3/ -- Android10 hardware/interfaces/radio/1.4/ -- Android10 hardware/interfaces/radio/1.5/ -- Android11 hardware/interfaces/radio/1.6/ -- Android12 hardware/interfaces/radio/aidl/ -- Android13+(拆分AIDL)AIDL 拆分带来的优势对比:
| 对比维度 | HIDL(单体) | AIDL(拆分) |
|---|---|---|
| 更新范围 | 任何改动都影响全部业务域 | 每个业务域独立升级 |
| 进程隔离 | 全部运行在单一进程 | 各服务可运行独立进程 |
| 稳定性 | VINTF 但扩展难度高 | @VintfStability,版本管理更清晰 |
| 类型安全 | 结构体 + 枚举 | 完整 AIDL Parcelable 支持 |
| 测试 | 必须 Mock 整个接口 | 可以单独 Mock 某一个业务域 |
36.3 SIM 管理
36.3.1 UICC 框架概览
通用集成电路卡(UICC)就是存放 SIM 应用的智能卡。Android 在frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/下通过一组类建模物理卡层级结构。
UiccController 是入口,在PhoneFactory.makeDefaultPhones()阶段创建的单例。
// frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/UiccController.java /** * 该类负责维护系统中所有通用集成电路卡(UICC,即SIM卡)相关信息 * * 通过make()函数创建UiccController,它是单例,make()只能调用一次。 * 创建完成后UiccController向RIL注册,接收"on"以及"unsol_sim_status_changed"通知。 */核心 UICC 类与文件:
| 类名 | 文件 | 作用 |
|---|---|---|
| UiccController | uicc/UiccController.java | 单例;管理全部卡槽与卡片 |
| UiccSlot | uicc/UiccSlot.java | 物理卡槽(实体 SIM 或 eSIM) |
| UiccPort | uicc/UiccPort.java | 卡槽上逻辑端口(用于 MEP 多激活配置文件) |
| UiccCard | uicc/UiccCard.java | 代表智能卡硬件本身 |
| UiccProfile | uicc/UiccProfile.java | 卡片上某一个运营商配置文件 |
| UiccCardApplication | uicc/UiccCardApplication.java | 卡上 SIM/USIM/ISIM 应用 |
| SIMRecords | uicc/SIMRecords.java | 读取并缓存 SIM 的 EF 基础文件 |
| IsimRecords | uicc/IsimRecords.java | ISIM 应用记录(用于 IMS) |
| IccFileHandler | uicc/IccFileHandler.java | 通过 ICC I/O 命令读写 SIM 文件 |
| PinStorage | uicc/PinStorage.java | 缓存 SIM PIN,支持无人 |