RIL处理命令和响应的方式是确保通信顺畅的关键。RIL实现了一个异步处理模型,命令发送和响应接收是分开进行的。命令发送之后,RIL等待无线模块的响应,响应到来时,RIL会根据响应数据的内容进行相应的处理。当有多个命令需要执行时,RIL会使用队列管理这些命令,确保它们按顺序执行。
处理命令和响应的过程大致如下:
命令队列 :所有待发送的命令放入队列中。
异步发送 :从队列中取出命令,并异步发送给硬件模块。
响应监听 :RIL监听来自硬件模块的响应。
结果回调 :当响应到达时,RIL将结果回调给发起请求的应用程序。
1. 核心数据结构
RequestInfo 结构体(待发送的命令信息)
// 来自 ril.cpp 第 126 行
static pthread_mutex_t s_pendingRequestsMutex = PTHREAD_MUTEX_INITIALIZER;
static RequestInfo *s_pendingRequests = NULL; // 待处理请求的链表头
RequestInfo 包含:
token- 唯一标识符,用于匹配请求和响应pCI- 指向 CommandInfo 结构体的指针socket_id- SIM 卡 ID(多卡支持)p_next- 链表指针,指向下一个待处理请求wasAckSent- 标志异步确认是否已发送
多 SIM 卡支持
// 多 SIM 卡的独立队列
#if (SIM_COUNT >= 2)
static pthread_mutex_t s_pendingRequestsMutex_socket2 = PTHREAD_MUTEX_INITIALIZER;
static RequestInfo *s_pendingRequests_socket2 = NULL;
#endif
#if (SIM_COUNT >= 3)
static pthread_mutex_t s_pendingRequestsMutex_socket3 = PTHREAD_MUTEX_INITIALIZER;
static RequestInfo *s_pendingRequests_socket3 = NULL;
#endif
// ...
2. 命令队列的完整流程
步骤 1: 命令入队 - addRequestToList()
RequestInfo *
addRequestToList(int serial, int slotId, int request) {
RequestInfo *pRI;
int ret;
RIL_SOCKET_ID socket_id = (RIL_SOCKET_ID) slotId;
// 根据 slotId 选择对应的互斥锁和队列
pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;
RequestInfo** pendingRequestsHook = &s_pendingRequests;
if (socket_id == RIL_SOCKET_2) {
pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2;
pendingRequestsHook = &s_pendingRequests_socket2;
}
// ... 其他 SIM 卡处理 ...
// 分配内存并初始化 RequestInfo
pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
if (pRI == NULL) {
RLOGE("Memory allocation failed for request %s", requestToString(request));
return NULL;
}
// 保存请求信息
pRI->token = serial; // 唯一标识
pRI->pCI = &(s_commands[request]); // 命令定义
pRI->socket_id = socket_id; // SIM 卡 ID
// 原子操作:将请求添加到队列头部
ret = pthread_mutex_lock(pendingRequestsMutexHook);
assert (ret == 0);
pRI->p_next = *pendingRequestsHook; // 新请求指向原来的头
*pendingRequestsHook = pRI; // 新请求成为新的头
ret = pthread_mutex_unlock(pendingRequestsMutexHook);
assert (ret == 0);
return pRI; // 返回用作 token
}
关键点:
- 使用互斥锁保护共享数据结构
- 使用链表(LIFO - 后进先出)存储待处理请求
token就是返回的RequestInfo指针本身
步骤 2: 异步发送命令
// ril_service.cpp 中的命令分发
bool dispatchVoid(int serial, int slotId, int request) {
// 1. 将请求加入队列(创建 RequestInfo)
RequestInfo *pRI = android::addRequestToList(serial, slotId, request);
if (pRI == NULL) {
return false;
}
// 2. 异步发送给硬件模块
CALL_ONREQUEST(request, NULL, 0, pRI, slotId);
// 这会调用到 vendor RIL 实现(如 QCRIL)
return true;
}
实际调用链:
dispatchVoid()
→ addRequestToList() 创建 RequestInfo 并加入队列
→ CALL_ONREQUEST() 调用 s_vendorFunctions->onRequest()
→ vendor RIL (QCRIL) 处理请求
→ 与硬件模块通信
→ 等待响应...
步骤 3: 响应监听和回调 - RIL_onRequestComplete()
extern "C" void
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
RequestInfo *pRI;
int ret;
RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
pRI = (RequestInfo *)t; // 从 token 恢复 RequestInfo
// 从队列中移除该请求
if (!checkAndDequeueRequestInfoIfAck(pRI, false)) {
RLOGE ("RIL_onRequestComplete: invalid RIL_Token");
return;
}
socket_id = pRI->socket_id;
// ... 异常处理 ...
if (pRI->cancelled == 0) {
int responseType;
// 判断响应类型
if (s_callbacks.version >= 13 && pRI->wasAckSent == 1) {
// 异步响应:先前发送过 ack,现在发送最终响应
responseType = RESPONSE_SOLICITED_ACK_EXP;
grabPartialWakeLock(); // 获取 wake lock
} else {
// 同步响应
responseType = RESPONSE_SOLICITED;
}
// 调用响应函数,返回给 Java 层
ret = pRI->pCI->responseFunction((int) socket_id,
responseType, pRI->token, e, response, responselen);
}
// 释放内存
free(pRI);
}
步骤 4: 移除请求 - checkAndDequeueRequestInfoIfAck()
static int
checkAndDequeueRequestInfoIfAck(struct RequestInfo *pRI, bool isAck) {
int ret = 0;
pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;
RequestInfo ** pendingRequestsHook = &s_pendingRequests;
if (pRI == NULL) {
return 0;
}
// 根据 socket_id 选择对应的队列
if (pRI->socket_id == RIL_SOCKET_2) {
pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2;
pendingRequestsHook = &s_pendingRequests_socket2;
}
// ...
pthread_mutex_lock(pendingRequestsMutexHook);
// 从链表中查找并移除该请求
for(RequestInfo **ppCur = pendingRequestsHook
; *ppCur != NULL
; ppCur = &((*ppCur)->p_next)
) {
if (pRI == *ppCur) {
ret = 1;
if (isAck) {
// 标记 ack 已发送(用于异步长时间请求)
pRI->wasAckSent = 1;
} else {
// 从链表中移除该请求
*ppCur = (*ppCur)->p_next;
}
break;
}
}
pthread_mutex_unlock(pendingRequestsMutexHook);
return ret;
}
3. 异步处理模型时间线
时间轴:
T0: 应用发起请求(如拨号)
↓
T1: addRequestToList() 创建 RequestInfo,加入 s_pendingRequests
│ [RequestInfo 已在队列中]
↓
T2: CALL_ONREQUEST() 发送命令给 vendor RIL
│ [命令异步发送,不等待]
↓
T3: Vendor RIL 与硬件通信,处理请求
│ [可能耗时几秒钟]
↓
T4a: 如果支持异步确认 (RIL version >= 13)
│ → RIL_onRequestAck() 被调用
│ → pRI->wasAckSent = 1(标记但不移除)
│ → 返回 ACK 给应用(让应用知道已收到)
│
↓ (几秒后)
│
T4b: 硬件响应,回调 RIL_onRequestComplete()
│ → checkAndDequeueRequestInfoIfAck(pRI, false)
│ → 从 s_pendingRequests 中移除
│ → 调用 responseFunction() 返回结果给 Java 层
│ → free(pRI) 释放内存
↓
T5: 应用收到最终响应
4. 多并发请求的处理
当多个请求同时到达时:
请求队列状态变化:
初始状态:
s_pendingRequests → NULL
请求 1 (拨号) 到达:
s_pendingRequests → [RequestInfo-1] → NULL
请求 2 (获取信号强度) 到达:
s_pendingRequests → [RequestInfo-2] → [RequestInfo-1] → NULL
请求 3 (设置网络) 到达:
s_pendingRequests → [RequestInfo-3] → [RequestInfo-2] → [RequestInfo-1] → NULL
请求 2 完成,响应:
checkAndDequeueRequestInfoIfAck(RequestInfo-2, false)
s_pendingRequests → [RequestInfo-3] → [RequestInfo-1] → NULL
(RequestInfo-2 被移除并释放)
请求 1 完成,响应:
s_pendingRequests → [RequestInfo-3] → NULL
5. 同步保护机制
互斥锁使用
// 关键的互斥保护
pthread_mutex_lock(pendingRequestsMutexHook);
// 原子操作:增加或遍历链表
pRI->p_next = *pendingRequestsHook;
*pendingRequestsHook = pRI;
pthread_mutex_unlock(pendingRequestsMutexHook);
保护的操作:
- ✓ 添加请求到队列
- ✓ 查找并移除请求
- ✓ 遍历列表查找特定请求
6. 异步应答机制(ACK)
对于耗时较长的请求(如拨号):
双阶段确认:
Phase 1: 快速 ACK
────────────────
请求来到时(T2)
↓
RIL_onRequestAck()
├─ pRI->wasAckSent = 1
├─ 调用 radio::acknowledgeRequest()
└─ 立即返回给应用
应用:「收到 ACK,知道正在处理」
Phase 2: 最终响应
─────────────────
硬件完成操作(T4b)
↓
RIL_onRequestComplete()
├─ responseType = RESPONSE_SOLICITED_ACK_EXP
├─ grabPartialWakeLock()
├─ 调用 responseFunction()
└─ 返回实际结果
应用:「收到最终响应」
7. 关键 API 总结
| API | 功能 | 调用方 |
|---|---|---|
addRequestToList() | 创建 RequestInfo,加入队列 | RIL Service (ril_service.cpp) |
CALL_ONREQUEST() | 异步发送命令给 vendor RIL | RIL Service |
RIL_onRequestAck() | Vendor RIL 发送快速确认 | Vendor RIL |
RIL_onRequestComplete() | Vendor RIL 发送最终响应 | Vendor RIL |
checkAndDequeueRequestInfoIfAck() | 从队列移除请求 | ril.cpp 内部 |
8. 超时和 Wake Lock 管理
// 获取 wake lock,防止系统休眠
static void grabPartialWakeLock() {
if (s_callbacks.version >= 13) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, ANDROID_WAKE_LOCK_NAME);
// 200ms 后自动释放(防止长期占用)
UserCallbackInfo *p_info =
internalRequestTimedCallback(wakeTimeoutCallback, NULL,
&TIMEVAL_WAKE_TIMEOUT);
s_last_wake_timeout_info = p_info;
}
}
总结
| 特性 | 实现方式 |
|---|---|
| 队列管理 | 链表 + 互斥锁 |
| 并发控制 | Pthread mutex |
| 请求标识 | Token (RequestInfo 指针) |
| 多 SIM 支持 | 每个 SIM 独立队列 + 互斥锁 |
| 异步处理 | 命令发送和响应分离 |
| 快速确认 | RIL_onRequestAck() |
| 最终响应 | RIL_onRequestComplete() |
| 系统睡眠保护 | Wake lock + 超时释放 |
这个设计确保了 RIL 能够高效地处理多个并发请求,同时保持通信的可靠性和系统的电源管理。