description: “RIL (Radio Interface Layer) 深度架构设计——Android 框架与 Modem 之间的唯一桥梁,涵盖 HIDL→AIDL 双栈适配、异步请求-响应模型、RILRequest 对象池、UNSOL 上行通知、WakeLock 防护、Radio HAL 版本回退兼容策略。”
RIL (Radio Interface Layer) 深度架构设计
RIL 是整个 Telephony 框架中最核心、最底层的组件。它位于 Framework 与 Vendor Modem 之间,承担着"翻译官"和"调度员"的双重角色——将 Java 层的调用翻译为硬件可以理解的 AT 命令/协议消息,并将 Modem 的响应和主动上报转发回 Framework。
没有 RIL,Phone 无法打电话、ServiceStateTracker 无法获取网络状态、DataNetwork 无法建立数据连接。 它是整条调用链的"最后一公里"。
设计理念: RIL 的设计是一个经典的"中间层"架构,Google 在此投入了大量工程努力来处理异步通信、跨进程边界(Treble)、电源管理(WakeLock)以及 HAL 版本兼容性。从 HIDL 到 AIDL 的迁移路径是整个 Android HAL 生态的缩影。
1. 核心职责
- 命令翻译与转发:将
CommandsInterface中的 Java 方法调用(如getVoiceRegistrationState())转换为 HAL 层调用 - 响应分发:将 HAL 层返回的数据分发给对应的
Message.callback - 主动上报 (UNSOL) 处理:Modem 主动上报的网络变化、来电、信号强度等事件分发到对应 Handler
- WakeLock 电源管理:确保在处理关键 RIL 请求时设备不会进入休眠
- HAL 服务生命周期管理:
RadioProxy的死亡监听、重连、服务禁用策略 - HAL 版本兼容:新旧 HAL 版本之间的 fallback 兼容策略
2. 核心类与源码锚点 (Source Code Anchors)
- [RIL.java](file:///d:/Resource/Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java):核心 RIL 实现类(11000+ 行)。继承
BaseCommands,实现CommandsInterface。 - [CommandsInterface.java](file:///d:/Resource/Android%2016/android-16/frameworks/base/telephony/java/com/android/internal/telephony/CommandsInterface.java):RIL 与上层模块之间的接口契约。
Phone模块只依赖此接口,不直接依赖RIL实现。 - [RILConstants.java](file:///d:/Resource/Android%2016/android-16/frameworks/base/telephony/java/com/android/internal/telephony/RILConstants.java):定义了所有
RIL_REQUEST_*、RIL_UNSOL_*常量及错误码。 - [RILRequest.java](file:///d:/Resource/Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/RILRequest.java)(内部类):封装单次 RIL 请求的数据结构,使用对象池(
sPool)复用。 - [RadioResponse.java](file:///d:/Resource/Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioResponse.java):HAL 层同步响应的回调接口实现。所有
process*Response()方法在此。 - [RadioIndication.java](file:///d:/Resource/Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java):HAL 层主动上报(UNSOL)的回调接口实现。
- [RadioServiceProxy.java](file:///d:/Resource/Android%2016/android-16/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioServiceProxy.java):HIDL 和 AIDL 的双栈代理,透明切换底层 HAL 版本。
- 硬件层:[rild.c](file:///d:/Resource/Android%2016/android-16/hardware/ril/rild/rild.c)(守护进程)、[ril_service.cpp](file:///d:/Resource/Android%2016/android-16/hardware/ril/libril/ril_service.cpp)(C++ 层 HAL 实现)
3. Google 设计技巧深入分析
3.1 8 大 HAL Service 拆分 — 关注点分离
Android 16 将原来的单一 IRadio HAL 接口拆分为 8 个独立服务:
public static final int MIN_SERVICE_IDX = HAL_SERVICE_RADIO; // 0
public static final int MAX_SERVICE_IDX = HAL_SERVICE_IMS; // 7
// HAL_SERVICE_RADIO, HAL_SERVICE_DATA, HAL_SERVICE_IMS,
// HAL_SERVICE_MESSAGING, HAL_SERVICE_MODEM, HAL_SERVICE_NETWORK,
// HAL_SERVICE_SIM, HAL_SERVICE_VOICE
每个服务对应独立的 Response 和 Indication 回调:
private RadioResponse mRadioResponse;
private RadioIndication mRadioIndication;
private DataResponse mDataResponse;
private DataIndication mDataIndication;
private ImsResponse mImsResponse;
private ImsIndication mImsIndication;
// ... 共 8 对 Response/Indication
Google设计技巧 #1 — 按功能域拆分的 HAL 服务 (Domain-Specific HAL Services):
将单一IRadio拆分为 8 个独立服务,每个服务拥有独立的getService()、独立的 DeathRecipient、独立的回调接口。这意味着:
- OEM 可以不实现
HAL_SERVICE_SIM而只实现HAL_SERVICE_VOICE(例如纯数据设备)- 某个服务 crash 后只需要重启该服务,不影响其他功能
- 并发性能更好——不同服务在不同 Binder 线程上独立处理
同时通过
FEATURES_TO_SERVICES映射表关联PackageManager.FEATURE_TELEPHONY_*,实现按设备能力启用/禁用对应服务。
3.2 RadioProxy — HIDL/AIDL 双栈适配
RIL.java 中同时存在两种 proxy 获取方式:
// HIDL 方式 (老路径)
private volatile IRadio mRadioProxy = null;
public synchronized IRadio getRadioProxy() {
if (mRadioProxy != null) return mRadioProxy;
// 从最新版本逐级回退
mRadioProxy = android.hardware.radio.V1_6.IRadio.getService(HIDL_SERVICE_NAME[mPhoneId], ...);
if (mRadioProxy == null) {
mRadioProxy = android.hardware.radio.V1_5.IRadio.getService(...);
}
if (mRadioProxy == null) {
mRadioProxy = android.hardware.radio.V1_4.IRadio.getService(...);
}
// ... 继续回退到 V1_0
}
而 AIDL 服务通过 RadioServiceProxy 统一封装:
private SparseArray<RadioServiceProxy> mServiceProxies = new SparseArray<>();
Google设计技巧 #2 — HIDL→AIDL 渐进迁移的双栈并行策略:
RadioServiceProxy是 HIDL 和 AIDL 的统一代理,内部持有IHwRadio和IRadioAidl两个引用,根据目标 HAL 版本自动选择使用哪个。这允许 OEM 逐步迁移:Voice 模块使用新 AIDL HAL,而 Data 模块仍使用旧 HIDL HAL 也无妨。RadioServiceProxy还支持isAidl()/getHidl()方法,让上层代码可以按需判断:if (serviceProxy.isAidl()) { IRadioAidl aidl = serviceProxy.getAidl(); aidl.someMethod(...); } else { IHwRadio hidl = serviceProxy.getHidl(); hidl.someMethod(...); }
3.3 RILRequest — 对象池复用的请求封装
RILRequest 是 RIL 中最精巧的数据结构设计:
static RILRequest obtain(int request, Message result, WorkSource workSource) {
RILRequest rr = null;
synchronized (sPoolSync) {
if (sPool != null) {
rr = sPool;
sPool = rr.mNext;
rr.mNext = null;
sPoolSize--;
}
}
if (rr == null) {
rr = new RILRequest();
}
rr.init(request, result, workSource);
return rr;
}
Google设计技巧 #3 — 对象池 (Object Pool) + WakeLock 绑定:
RILRequest使用单链表实现的对象池(sPool),而非每次new新对象。在高频场景下(如轮询信号强度每秒一次),这可以显著减少 GC 压力。每发送一个
RILRequest就持有一个 WakeLock,防止 CPU 在处理关键通信命令时休眠。mRequestList(SparseArray<RILRequest>) 按serial号索引所有未完成的请求:SparseArray<RILRequest> mRequestList = new SparseArray<>();
EVENT_WAKE_LOCK_TIMEOUT机制防止 WakeLock 被永久持有——如果 Modem 长时间无响应(DEFAULT_WAKE_LOCK_TIMEOUT_MS),系统会释放 WakeLock 并记录异常。
3.4 双向通道模型 — 同步响应 + 异步上报 (UNSOL)
RIL 使用双通道与 Modem 通信:
Framework (Java) Modem (C/C++)
┌──────────────┐ 下行命令 (SOLICITED) ┌──────────┐
│ RIL.java │ ────────setupDataCall()──────────→ │ rild │
│ (11000+ 行) │ │ daemon │
│ │ ←──────onDataCallListChanged()──── │ │
└──────────────┘ 上行通知 (UNSOLICITED) └──────────┘
- 下行命令 (Solicited):Framework → Modem。每条命令携带一个
serial号,Modem 处理完后通过RadioResponse回传结果 - 上行通知 (Unsolicited):Modem → Framework。无需 Framework 主动请求,Modem 通过
RadioIndication主动上报
// 发送下行命令
private void send(RILRequest rr) {
addRequest(rr); // 加入 mRequestList,获取 serial 号
895



被折叠的 条评论
为什么被折叠?



