2.3 RIL软件分析
| 模块 | 功能描述 |
|---|---|
| rild 主入口 | 解析启动参数(如 -l 指定库路径),通过 dlopen 加载 Vendor RIL 动态库,初始化事件循环,并建立与 Java 层的 Socket 通信通道(rild 与 rild-debug 两个 Socket)。 |
| 事件循环 (EventLoop) | 基于 select/epoll 的单线程事件驱动核心。管理三类事件:定时器事件(ril_timer)、文件描述符事件(如 AT 命令通道的读写)、待处理回调队列。所有来自 Vendor RIL 的主动上报和响应都需经过它调度。 |
| Vendor RIL 动态库 | 由芯片厂商(如高通、MTK)实现,封装与 Modem 的具体通信协议(AT 指令、共享内存 QMI、MBIM 等)。它必须实现 RIL_Init 入口函数,并向 RILD 提供一组回调函数指针(RIL_RadioFunctions)。 |
LibRIL和Vendor RIL通过接口分离,共同构成了RIL的核心。
LibRIL是Android原生代码的一部分(libril.so),与rild静态链接。它位于rild进程中,负责与上层Java框架的RILJ通过Socket通信。其核心是ril_event事件循环,同时,LibRIL定义了RIL_Env回调接口,并实现RIL_register来注册Vendor RIL提供的函数指针。
Vendor RIL是由芯片厂商(如高通、MTK)提供的动态库(.so)。它被rild通过dlopen动态加载。Vendor RIL需要实现并导出RIL_Init函数和RIL_RadioFunctions下行接口,并将Android框架层的请求转换为Modem能识别的AT指令或QMI消息。其内部通常会创建一个线程(如mainLoop),专门负责监听和读写Modem端口。
| 特性 | LibRIL (libril.so) | Vendor RIL (如 libqcril.so) |
|---|---|---|
| 提供者 | Android 开源项目 (AOSP) 的一部分 | 芯片厂商或设备制造商 |
| 主要功能 | 与上层Java框架通信、事件循环、请求分发 | 与Modem硬件通信、协议转换 |
| 提供的接口 | RIL_Env (供Vendor RIL回调) | RIL_Init (入口函数), RIL_RadioFunctions (供LibRIL调用) |
| 关键函数/组件 | RIL_startEventLoop, RIL_register, ril_event_loop | onRequest, mainLoop |
| 与Modem的交互 | 不直接交互,通过Vendor RIL进行 | 直接交互,通过串口/USB发送AT指令或QMI等协议消息 |
2.3.1 RIL 代码结构与层级关系
整个 RIL 主要分为三个部分,它们之间通过函数指针或动态加载的方式交互。
| 模块文件 | 编译产物 | 主要作用 |
|---|---|---|
| rild.c | rild守护进程 | 唯一的入口点,负责解析参数、加载动态库等顶层初始化工作。 |
| ril.cpp ril_event.cpp | libril.so | LibRIL,核心逻辑层。建立事件循环,管理上层通信,协调下层通信。 |
| reference-ril.c atchannel.c | libreference-ril.so | Vendor RIL,厂家适配层。实现具体的AT命令收发,与Modem硬件交互。 |
从代码依赖关系上看,rild是主程序,通过dlopen方式加载libreference-ril.so;而libril.so是rild编译时就链接的依赖库。

2.3.2 RIL的核心代码结构
| 核心概念 | 主要作用 | 代码表现 / 结构 |
|---|---|---|
| 命令映射 | 将请求 ID (RIL_REQUEST_*) 映射到对应处理函数 | s_commands (在 ril_commands.h) 静态数组,存储dispatchFunction和responseFunction。 |
| 主动上报映射 | 将主动上报 ID (RIL_UNSOL_*) 映射到封装函数 | s_unsolResponses (在 ril_unsol_commands.h) 静态数组。 |
| 事件列表 | 管理所有监听的文件描述符(fd)事件 | watch_table:select监听的所有fd;pending_list:触发待处理的事件;timer_list:定时器事件。 |
| 请求Token | 异步请求的唯一标识,用于匹配响应 | RIL_Token,本质是RequestInfo结构体指针,由LibRIL传入Vendor RIL。 |
| 跨线程唤醒 | 非主线程唤醒eventLoop线程的机制 | notify pipe:s_fdWakeupWrite唤醒,s_fdWakeupRead被epoll/select监听。 |
2.3.3 代码阅读分析
| 模块 | 文件 | 核心内容 | 与 rild.c 的关系 |
|---|---|---|---|
| LibRIL 核心 | ril.cpp | 实现 RIL_startEventLoop、RIL_register、RIL_onRequestComplete 等。定义 s_commands 和 s_unsolResponses。 | rild.c 调用这些函数,并依赖其中的全局状态。 |
| 事件循环 | ril_event.cpp (或 ril_event_epoll.cpp) | 实现 ril_event_loop、watch_table、pending_list、timer_list,以及 select/epoll 多路复用。 | RIL_startEventLoop 会创建线程并调用 ril_event_loop。 |
| Vendor RIL 示例 | reference-ril.c | 一个简单的 Vendor RIL 实现,展示如何实现 RIL_Init、onRequest 以及如何调用 RIL_Env 回调。 | rild.c 通过 dlopen 加载此类库,理解 RIL_Init 的实现就能明白双向通信。 |
| RIL 头文件 | include/telephony/ril.h | 定义所有 RIL_REQUEST_、RIL_UNSOL_、RIL_RadioFunctions、RIL_Token 等。 | rild.c 中使用的结构体类型均来自此头文件。 |
| Socket 通信 | ril.cpp 中的 listenCallback、processCommandBuffer | 负责与 RILJ 的 socket 交互,读取请求、发送响应。 | 事件循环检测到 socket 可读时,调用这些函数。 |
| 系统属性 | libcutils 中的 property_get | 读取 rild.libpath 等属性。 | rild.c 在未通过 -l 指定时依赖此接口。 |
C
推荐阅读顺序
先看 ril.h:了解常量和核心数据结构。
再看 ril.cpp 中的 RIL_register 和 RIL_startEventLoop:
理解 LibRIL 如何初始化事件循环和 socket 监听。
阅读 ril_event.cpp:掌握事件循环机制(select/epoll、三个队列)。
回到 rild.c:此时可以清楚知道 main 每一步调用的底层实现。
阅读一个简单的 Vendor RIL 实现(如 reference-ril.c):
理解 RIL_Init 内部如何创建 mainLoop线程、打开串口、处理请求。
最后阅读复杂厂商实现(如高通 libqcril.so 的对应源码):
这是实际手机中的代码,但核心思想与 reference-ril 一致,只是增加了异步队列、QMI 等高级特性。
C
android code:
hardware/ril/rild/rild.c
hardware/ril/libril/ril.cpp
hardware/ril/libril/ril_event.cpp
hardware/ril/reference-ril/reference-ril.c
hardware/ril/include/telephony/ril.h
Qualcomm libqcril.so code:
/vendor/qcom/proprietary/qcril/qcril_qmi
2.3.4 ril.h
C
hardware/ril/include/telephony/ril.h
ril.h是Android系统中无线接口层的定义头文件,它定义了一个与具体Modem无关的抽象接口,是整个RIL框架的核心与纽带。所有主要组件(rild守护进程、libril.so和Vendor RIL)都依赖这个文件进行通信。
2.3.4.1 核心数据结构
2.3.4.1.1 (RIL_RadioFunctions) ------ 厂商回调表(下发接口)
包含了 Vendor RIL 库必须实现的一系列函数指针。rild守护进程通过加载Vendor RIL库并调用RIL_Init函数来获取这个结构体的实例。
C++
typedef struct {
int version; // RIL接口的版本号,用于兼容性控制[reference:9]
RIL_RequestFunc onRequest; // 处理来自上层主动请求(solicited commands)[reference:10]
RIL_RadioStateRequest onStateRequest; // 查询当前无线射频状态
RIL_Supports supports; // 查询Vendor RIL是否支持某个特定的请求代码
RIL_Cancel onCancel; // 取消一个正在进行的请求
RIL_GetVersion getVersion; // 获取Vendor RIL实现的版本字符串
} RIL_RadioFunctions;
RIL_RadioFunctions 是厂商 RIL 库暴露给 libril.so 的核心函数表。它是一个"函数指针集合",就像一张跳转表。libril 不需要知道厂商 RIL 内部的具体实现,只需通过这个结构体就能调用到厂商实现的各项功能。
设计模式:函数表(Function Table / Jump Table)
这是一个纯虚函数表的C语言实现。
所有成员都是函数指针,指向厂商RIL库中具体的实现。
libril 拿到这个表后,无需关心厂商内部实现,只需通过表调用函数即可。
-
方向:libril → 厂商RIL(上层调用厂商实现)
-
作用:厂商RIL通过RIL_Init返回这个结构体,libril通过它调用厂商的具体函数。
| 成员 | 类型定义(来自 ril.h) | 参数说明 | 返回值 | 含义 |
|---|---|---|---|---|
| version | int | RIL接口的版本号 | 接口版本号,必须设置为 RIL_VERSION 宏。用于保证 libril 与厂商 RIL 的版本兼容。 | |
| onRequest | typedef void (*RIL_RequestFunc)(int request, void *data, size_t datalen, RIL_Token t); | request: 命令ID(如 RIL_REQUEST_DIAL) data: 命令参数结构体指针 datalen: 参数大小 t: 令牌,用于匹配响应 | void | 函数指针:void (*)(int request, void *data, size_t datalen, RIL_Token t)。核心入口:上层所有主动请求(拨号、发短信等)最终都通过这个函数传递给厂商 RIL 处理。 |
| onStateRequest | typedef RIL_RadioState (*RIL_RadioStateRequest)(void); | 无 | RIL_RadioState 枚举(如 RADIO_STATE_ON) | 函数指针:RIL_RadioState (*)(void)。用于查询当前 Modem 的射频状态(如无服务、正在注册、已注册等)。 |
| supports | typedef int (*RIL_Supports)(int requestCode); | requestCode: 命令ID | 1 支持,0 不支持 | 函数指针:int (*)(int requestCode)。用于询问厂商 RIL 是否支持某一个特定的请求命令(如 RIL_REQUEST_DIAL)。 |
| onCancel | typedef void (*RIL_Cancel)(RIL_Token t); | t: 要取消的请求令牌 | void | 函数指针:void (*)(RIL_Token t)。当上层需要取消某个正在执行的请求时调用。 |
| getVersion | typedef const char *(*RIL_GetVersion)(void); | 无 | 版本字符串指针(静态或常量) | 函数指针:const char ()(void)。返回厂商 RIL 的实现版本字符串(用于调试或日志)。 |

C
RIL_RequestFunc onRequest: 所有主动请求的入口,当上层发起拨号、发送短信等操作时会被调用。
typedef void (*RIL_RequestFunc) (int request, void *data, size_t datalen, RIL_Token t);
request: 请求类型(如 RIL_REQUEST_DIAL),常见种类有:
SIM/卡相关操作(11个)
呼叫状态与处理(16个,包括拨号、接听、静音等)
网络状态查询(4个)
网络设置(12个,包括呼叫禁止、呼叫转移、网络选择等)
短信处理(3个)
PDP连接(4个)
电源与复位(2个)
补充服务(5个)
厂商自定义(4个)
data: 指向该请求特有参数的指针(如拨打的号码)。
t: 一个不透明的令牌(Token),用于在完成响应时匹配请求。
C
typedef RIL_RadioState (*RIL_RadioStateRequest)();
typedef int (*RIL_Supports)(int requestCode);
typedef void (*RIL_Cancel)(RIL_Token t);
typedef const char * (*RIL_GetVersion) (void);
RIL_RadioStateRequest onStateRequest: 用于查询Modem的当前状态(例如,无服务、正在搜索网络等)。
RIL_Supports supports: 用于检查Vendor RIL是否支持特定的请求代码。
RIL_Cancel onCancel: 用于取消一个已发出但尚未完成的请求。
RIL_GetVersion getVersion: 用于获取Vendor RIL实现的版本字符串。
2.3.4.1.2 RIL_Init ------ 厂商库的入口函数
C
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv);
-
RIL_Init 是厂商RIL库的唯一导出函数。rild 通过 dlopen 动态加载厂商库后,用 dlsym 找到这个函数并调用它。
-
它接受一个 RIL_Env 结构体指针,这个结构体是 libril 提供给厂商的回调环境(即反向接口)。
-
调用者:rild守护进程
-
作用:动态加载厂商RIL库后,调用RIL_Init,传入RIL_Env(由libril提供),厂商RIL保存该环境指针,并返回自己的RIL_RadioFunctions函数表。
2.3.4.1.2.1 其核心职责
-
接收 RIL_Env 回调环境:保存 env 指针,以便后续通过 env->OnRequestComplete 等回调将 Modem 的响应或主动上报事件返回给 libril。
-
初始化 Modem 硬件接口:打开串口、初始化 QMI 客户端、配置 AT 通道等。
-
返回函数表:将一个填充好的 RIL_RadioFunctions 结构体指针返回给调用者(rild),该结构体包含了厂商 RIL 实现的核心函数指针(如 onRequest、onStateRequest 等)。
| 参数 | 类型 | 说明 |
|---|---|---|
| env | const struct RIL_Env * | 回调环境指针,由 libril.so 提供。厂商 RIL 必须保存此指针,在请求处理完成或 Modem 主动上报事件时,通过 env 中的函数回调 libril。常见回调函数: env->OnRequestComplete(...):异步响应 env->OnUnsolicitedResponse(...):主动上报 |
| argc | int | 命令行参数个数,通常由 rild 启动脚本(如 init.rc)传递,例如 -d /dev/ttyS0 等 |
| argv | char ** | 命令行参数数组,内容与 argc 配套 |
返回值
-
类型:const RIL_RadioFunctions *
-
含义:指向厂商 RIL 提供的函数表(通常是一个静态全局的 RIL_RadioFunctions 结构体变量)的常量指针。
-
生命周期:该结构体的内容在整个 RIL 运行期间必须保持有效(通常定义为 static const 或全局变量)。
调用时序

-
依赖注入:libril 通过 RIL_Env 将回调函数"注入"到厂商 RIL,厂商 RIL 无需关心 libril 内部细节。
-
对称性:RIL_Init 返回 RIL_RadioFunctions(供 libril 调用),同时接收 RIL_Env(供厂商回调),形成双向接口。
-
单例模式:每个 RIL 实例(可能支持多 SIM)调用一次 RIL_Init,返回的函数表在整个进程生命周期中保持不变。
-
版本兼容:s_callbacks.version 必须设置为 RIL_VERSION,libril 会根据该版本决定是否调用某些新功能。
C
RIL_Init 由厂商 RIL 库实现,libril 并不包含该函数。
rild 必须先将函数表通过 RIL_register 注册到 libril后,libril 才会开始监听 Socket 并处理请求。
RIL_Env 是 libril 提供的,厂商 RIL 接收并保存。
RIL_Init 是 Android RIL 架构中厂商适配层的"入口点"。它通过简洁的接口完成了双向依赖的解耦:
-
libril 获得厂商的函数表(RIL_RadioFunctions)
-
厂商获得 libril 的回调环境(RIL_Env)
这种设计使得 Android 系统能够在不修改框架代码的前提下,适配不同厂商、不同硬件的 Modem。
2.3.4.1.2.2 RIL_Env ------ libril 提供的回调环境(上报表)
C
struct RIL_Env {
void (*OnRequestComplete)(RIL_Token t, RIL_Errno e, void *response,
size_t responselen);
void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,
size_t datalen);
void (*RequestTimedCallback)(RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime);
};
-
方向:厂商RIL → libril(厂商调用libril提供的回调)
-
作用:厂商RIL在请求处理完成或接收到Modem主动事件时,通过RIL_Env中的函数指针将结果或事件上报给libril。
-
厂商RIL通过 env->OnRequestComplete 上报请求结果。
-
通过 env->OnUnsolicitedResponse 上报Modem主动事件。
2.3.4.1.2.3 函数含义
-
env:RIL_Env 结构体指针。RIL_Env 是 libril 提供给厂商 RIL 的回调环境,里面包含 OnRequestComplete、OnUnsolicitedResponse 等函数指针。厂商 RIL 利用这些回调把结果或事件传回 libril。
-
argc, argv:命令行参数(通常由 rild 启动脚本传递,如设备节点路径等)。
-
返回值:返回一个常量指针,指向厂商 RIL 自己实现的 RIL_RadioFunctions 结构体实例(通常是静态全局变量)。该结构体中的函数指针就是厂商 RIL 实际功能函数。
-
典型实现(厂商库内部):
C++
// reference-ril.c
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION, // .version = RIL_VERSION
onRequest, // .onRequest = onRequest
currentState, // .onStateRequest = currentState
onSupports, // .supports = onSupports
onCancel, // .onCancel = onCancel
getVersion // .getVersion = getVersion
};
const RIL_RadioFunctions *RIL_Init(const RIL_Env *env, int argc, char **argv) {
// 保存 env 到全局变量,供后续回调使用
g_env = env;
// 打开串口、初始化Modem等
return &s_funcs;
}
2.3.4.1.2.4 数据结构交互图(初始化阶段)

2.3.4.1.2.5 RIL_Init 与 RIL_Env 关系的时序图与结构图
时序图:初始化与回调流程

结构关系图:双向依赖

| 元素 | 角色 | 方向 |
|---|---|---|
| RIL_Env | libril 提供的回调接口 | libril → rild → VendorRIL |
| RIL_Init | 厂商 RIL 的入口函数,接收 env | rild 调用 VendorRIL |
| g_env | 厂商 RIL 内部静态变量,保存 env | VendorRIL 内部存储 |
| RIL_RadioFunctions | 厂商 RIL 提供的函数表 | VendorRIL → rild → libril |
核心关系:
RIL_Init 是桥梁,它让 libril 的回调环境 (RIL_Env) 流入厂商 RIL,同时让厂商 RIL 的函数表 (RIL_RadioFunctions) 流回 libril,形成双向通信通道。
2.3.4.1.3 s_commands\[\]
s_commands\[\] 数组 + ril_commands.h 的组合是 Android RIL 中命令路由的核心机制。它将协议号与具体的业务处理函数绑定,使得 libril 能够以统一的方式处理所有请求,同时保持代码的简洁和可扩展性。
C
typedef struct {
int requestNumber; *// 请求号(如 RIL_REQUEST_DIAL)*
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI); *// 分发函数指针*
int(*responseFunction) (Parcel &p, void *response, size_t responselen);*// 响应函数指针*
} CommandInfo;
/*
requestNumber:与 ril.h 中定义的请求宏对应的整数值,用于标识命令类型。
dispatchFunction:指向分发函数,负责将来自 RILJ 的 Parcel 数据解析成 C 结构体,并调用厂商 RIL 的 onRequest。
responseFunction:指向响应函数,负责将 Modem 返回的原始数据(response)封装成 Parcel 格式,以便通过 Socket 发送回 RILJ。
*/
/** Index == requestNumber */
static CommandInfo s_commands[] = {
#include "ril_commands.h"
};
/*
s_commands 是一个全局静态数组,元素类型为 CommandInfo。
#include "ril_commands.h" 是预处理指令,会将 ril_commands.h 文件的内容直接文本插入到数组初始化位置。
注释 /** Index == requestNumber */ /*表明:该数组的索引 与 requestNumber 相等(或者存在某种直接映射关系,例如 index = requestNumber - RIL_FIRST_COMMAND_ID)。
*/
//ril_commands.h
......
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
{RIL_REQUEST_GET_IMSI, dispatchStrings, responseString},
{RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
......
/*
每个花括号内的三个元素依次对应 CommandInfo 的三个成员:
请求宏(如 RIL_REQUEST_DIAL)
分发函数名(如 dispatchDial)
响应函数名(如 responseVoid)
预处理器展开后,s_commands[] 数组的内容就变成了这些初始化器。
*/
这段代码是 Android RIL 中 libril.so 的核心命令映射表,用于将上层的请求号(如 RIL_REQUEST_DIAL)映射到对应的分发函数(dispatch function) 和响应函数(response function)。
dispatchFunction 的职责
-
从 Parcel 中读取参数(例如电话号码 等)。
-
将参数填充到对应的结构体(如 RIL_Dial)中。
-
调用 s_callbacks.onRequest(requestNumber, &struct, size, pRI)。
-
负责释放动态分配的内存(如字符串)。
responseFunction 的职责
-
被 RIL_onRequestComplete 调用。
-
将 response 指针指向的原始数据(如字符串、整数数组)写入 Parcel。
-
将 Parcel 通过 Socket 发送给 RILJ。
-
返回值通常表示操作状态(0 成功,负数错误)。
常见的响应函数
-
responseVoid:不携带数据,只返回成功/失败状态。用于不需要返回数据的情况(如拨号、挂断)。只返回成功/失败状态。
-
responseString:返回一个以 \0 结尾的字符串。返回一个字符串(如 IMSI)。
-
responseStrings:返回多个字符串(以 NULL 结尾的数组)(如运营商列表)。
-
responseInts:返回整数数组(如信号强度)。
-
responseCallList:返回通话列表(用于 RIL_REQUEST_GET_CURRENT_CALLS)。
这些函数在 ril.cpp 中实现,内部通过 sendResponse 将数据打包成 Parcel 并通过 Socket 发送给 RILJ。
数据映射关系简图

工作流程

从接收到请求 到 调用响应函数 的完整流程:

-
CommandInfo 是一个命令路由条目,将请求号、解析函数、响应函数绑定在一起。
-
s_commands\[\] 数组通过 #include "ril_commands.h" 的方式初始化,所有命令的路由信息集中维护。
-
查找方式:通常使用 requestNumber - RIL_FIRST_COMMAND_ID 作为数组下标,直接定位到对应的 CommandInfo。
-
分工明确:dispatchFunction 负责"向下传递",responseFunction 负责"向上回传"。
这种设计使得 RIL 层能够以统一、高效的方式处理数十种不同类型的电话、短信、网络等请求,是 Android 电话栈中一个经典的"表驱动"编程范例。
2.3.4.1.4 RIL_register ------ 注册函数表到 libril
C
void RIL_register (const RIL_RadioFunctions *callbacks);
RIL_register 是 libril.so 提供的函数,不是厂商库导出的。rild 在得到厂商的 RIL_RadioFunctions 后调用它,将这个函数表注册到 libril 内部全局变量(如 s_callbacks)中。
-
它把厂商函数表保存下来,使得 libril 内部在处理请求时可以调用 s_callbacks.onRequest(...) 来传递请求给厂商。
-
同时,RIL_register 还会创建 RILJ 通信的 Socket,并启动事件循环,让整个 RIL 开始工作。
注册后的数据流向

2.3.4.1.5 数据结构关系图

2.3.4.1.6 数据走向与调用时序图
阶段1:初始化(建立双向通道)

阶段2:主动请求(上层 → Modem,以拨号为例)

阶段3:主动上报(Modem → 上层,如来电)

| 方向 | 调用起点 | 调用终点 | 使用的接口 |
|---|---|---|---|
| 下发(主动请求) | RILJ → Socket → libril | 厂商RIL | RIL_RadioFunctions.onRequest |
| 上报(请求响应) | 厂商RIL | libril → Socket → RILJ | RIL_Env.OnRequestComplete |
| 上报(主动事件) | 厂商RIL | libril → Socket → RILJ | RIL_Env.OnUnsolicitedResponse |
时序说明
-
rild 动态加载厂商RIL库,获取 RIL_Init 函数入口。
-
rild 调用 RIL_Init,传入 RIL_Env 回调环境。
-
厂商RIL 保存 env 并返回自己的 RIL_RadioFunctions 结构体指针。
-
rild 将函数表指针传给 libril 的 RIL_register 函数。
-
libril 保存函数表,创建 Socket 监听,启动事件循环,准备处理请求。
-
运行阶段,当有请求(如拨号)到来时,libril 通过保存的函数表指针调用厂商的 onRequest 函数。
-
厂商RIL 处理完成后,通过之前保存的 env 回调 OnRequestComplete 将结果返回给 libril。
-
libril 将结果通过 Socket 返回给 RILJ。
2.3.4.1.7 数据流向图

2.3.4.1.8 设计思想
| 元素 | 角色 | 提供方 | 消费方 | 设计模式 |
|---|---|---|---|---|
| RIL_RadioFunctions | 函数表(抽象接口) | 厂商RIL实现 | libril | 接口/函数表 |
| RIL_Init | 工厂函数 | 厂商RIL | rild | 工厂模式 |
| RIL_register | 注册函数 | libril | rild | 依赖注入 |
| RIL_Env | 回调环境 | libril | 厂商RIL | 观察者/回调 |
-
依赖反转:libril 只依赖 RIL_RadioFunctions 接口,不依赖具体厂商实现。
-
控制反转:libril 提供 RIL_Env 回调环境,厂商RIL主动调用这些回调将结果返回。
-
对称性:RIL_RadioFunctions 负责向下调用,RIL_Env 负责向上回调,形成完整双工通道。
-
单一全局状态:厂商RIL内部通常保存 g_env 静态指针;libril 内部保存 s_callbacks 静态函数表。
这种设计使得 Android RIL 层可以轻松替换不同 Modem 方案,而无需修改 libril 和上层 Java 代码。
2.3.4.2 错误处理与版本控制
错误码
-
RIL_Errno:所有操作的标准错误码(如 RIL_E_SUCCESS、RIL_E_GENERIC_FAILURE、RIL_E_RADIO_NOT_AVAILABLE 等)。
-
RIL_RadioState:无线状态(无服务、正在搜索、已注册等)。
-
RIL_CallState:通话状态(空闲、拨出、振铃、通话中等)
这些错误码有助于提升问题排查效率。
版本控制
ril.h内部通过一系列宏定义(如 RIL_VERSION、RIL_VERSION_12 等)对接口版本号进行管理,确保了接口的向前和向后兼容性。
2.3.4.3 请求和响应的宏定义
ril.h使用宏为所有请求和事件定义了唯一的标识符。这些宏分为两类:
- 主动请求命令 (Solicited Commands): 前缀为 RIL_REQUEST_。这些是上层(Framework)主动发起的操作请求,如 RIL_REQUEST_DIAL(拨打电话)、RIL_REQUEST_HANGUP(挂断电话)等。
Markdown
/**
* RIL_REQUEST_DIAL
*
* Initiate voice call
*
* "data" is const RIL_Dial *
* "response" is NULL
*
* This method is never used for supplementary service codes
*
* Valid errors:
* SUCCESS
* RADIO_NOT_AVAILABLE (radio resetting)
* DIAL_MODIFIED_TO_USSD
* DIAL_MODIFIED_TO_SS
* DIAL_MODIFIED_TO_DIAL
* GENERIC_FAILURE
*/
#define RIL_REQUEST_DIAL 10
- 被动请求命令 (Unsolicited Responses): 前缀为 RIL_UNSOL_。这些是Modem主动上报的事件,如 RIL_UNSOL_CALL_STATE_CHANGED(通话状态改变)、RIL_UNSOL_NEW_SMS(收到新短信)等
C++
/**
* RIL_UNSOL_CALL_RING
*
* Ring indication for an incoming call (eg, RING or CRING event).
* There must be at least one RIL_UNSOL_CALL_RING at the beginning
* of a call and sending multiple is optional. If the system property
* ro.telephony.call_ring.multiple is false then the upper layers
* will generate the multiple events internally. Otherwise the vendor
* ril must generate multiple RIL_UNSOL_CALL_RING if
* ro.telephony.call_ring.multiple is true or if it is absent.
*
* The rate of these events is controlled by ro.telephony.call_ring.delay
* and has a default value of 3000 (3 seconds) if absent.
*
* "data" is null for GSM
* "data" is const RIL_CDMA_SignalInfoRecord * if CDMA
*/
#define RIL_UNSOL_CALL_RING 1018
2.3.4.4 业务结构体
| 功能域 | 结构体名称 | 用途 |
|---|---|---|
| 拨号 | RIL_Dial | 包含拨打的号码、CLIR 设置等。 |
| 通话控制 | RIL_Call | 记录通话的索引、状态、号码、类型等。 |
| 短信 | RIL_SMS_WriteArgs | 写短信时的参数(状态、PDU 等)。 |
| 数据连接 | RIL_Data_Call_Response_v11 | 数据呼叫的响应(IP 地址、网关、DNS 等)。 |
| SIM 卡 | RIL_SimRefresh | SIM 卡刷新事件参数。 |
| 信号强度 | RIL_SignalStrength_v6 / RIL_CDMA_SignalStrength | 信号强度值(GSM、CDMA 等不同制式)。 |
| 网络信息 | RIL_OperatorInfo | 运营商名称(长名、短名、MCC/MNC)。 |
| 呼叫转移 | RIL_CallForwardInfo | 呼叫转移的配置(状态、号码、时间等)。 |
| 来电显示 | RIL_CDMA_CallWaiting | CDMA 来电等待信息。 |
| 设备标识 | RIL_DeviceIdentity | IMEI、MEID、ESN 等。 |
| 小区信息 | RIL_NeighboringCell | 相邻小区信息(用于网络选择)。 |
2.3.4.5 类型定义与联合体
C
typedef void * RIL_Token;
//RIL_Token:不透明句柄,实际是 void*。
typedef struct {
int dbm; /* Valid values are positive integers. This value is the actual RSSI value
* multiplied by -1. Example: If the actual RSSI is -75, then this response
* value will be 75.
*/
int ecio; /* Valid values are positive integers. This value is the actual Ec/Io multiplied
* by -10. Example: If the actual Ec/Io is -12.5 dB, then this response value
* will be 125.
*/
} RIL_CDMA_SignalStrength;
//RIL_CDMA_SignalStrength 等特定制式的联合体。

- ril.h 定义了函数接口与电话、短信、网络、SIM 卡等业务相关的结构体、枚举和常量等等,这些是 RIL 层真正传输的数据格式。任何厂商实现 RIL 时,都必须按照这些数据结构填充或解析数据,才能与 Android Telephony 框架正常通信。
ril.h在整个RIL架构中扮演了核心枢纽的角色,它定义了上游(Framework)和下游(Modem)之间的合约,确保了各层组件之间能够无缝协作。从架构上看,ril.h 连接了以下几个部分:
-
rild 守护进程: ril.h定义了它们之间通信的Socket协议和数据格式,rild通过RIL_RadioFunctions调用厂商实现。
-
libril 辅助库: ril.h是连接rild和Vendor RIL的桥梁。rild通过dlopen加载Vendor RIL库,并使用RIL_Init函数获取RIL_RadioFunctions函数指针表。
-
Vendor RIL: ril.h是厂商实现Modem通信库时必须遵循的接口规范。
-
上层应用: ril.h定义了上层应用(RILJ)与rild之间进行Socket通信时使用的命令和数据类型格式。
ril.h文件是Android RIL系统的核心契约,它定义了通信框架和API,扮演着承上启下的关键角色。它通过定义标准化的数据结构和接口,使得Android的Telephony框架和底层的硬件Modem得以解耦,从而实现了高度的兼容性和可移植性。
2.3.4.6 结构图和时序图总结
2.3.4.6.1 结构图(模块关系与数据流向)

-
RIL_Init:qcril.so 的工厂函数,在启动时被 rild 调用,接收 RIL_Env 并返回 RIL_RadioFunctions。
-
RIL_Env:libril 提供的回调环境,qcril 保存其指针,用于上报结果或事件。
-
RIL_RadioFunctions:qcril 返回的函数表,libril 通过它调用 qcril 的 onRequest 等函数。
2.3.4.6.2 MO(主叫)时序图

2.3.4.6.3 MT(被叫)时序图

| 组件 | 角色 | 方向 |
|---|---|---|
| RIL_Env | libril 提供的回调环境 | libril → qcril(通过 RIL_Init 参数传入) |
| RIL_Init | qcril 的工厂函数 | rild → qcril,返回 RIL_RadioFunctions |
| RIL_RadioFunctions | qcril 的函数表 | qcril → rild → libril |
| s_callbacks.onRequest | libril 调用 qcril 的入口 | libril → qcril |
| g_env->OnRequestComplete | qcril 回调 libril 返回请求结果 | qcril → libril |
| g_env->OnUnsolicitedResponse | qcril 上报 Modem 主动事件 | qcril → libril |