Binder异步队列
本文承接 oneway异步接口 和 Binder同步调用。BD070 解释编译器如何生成 TF_ONE_WAY;本文只解释驱动运行时收到这个 flag 后如何排队。关键结论是:同一个 Binder node 同时只派发一个异步事务,后续事务进入 node->async_todo,当前事务的 Binder buffer 释放时才唤醒下一个。这个串行化不等于所有 oneway 调用全局串行。
1. 异步状态
源码文件:kernel/common/drivers/android/binder.c
binder_node 保存 has_async_transaction 与 async_todo。前者表示该 node 已有异步事务占用派发槽位,后者是等待链表。事务自身的 is_async 和 buffer 的 async_transaction 让释放路径能找到对应 node。
2. 首个派发
源码文件:kernel/common/drivers/android/binder.c
if (oneway) {
BUG_ON(thread);
if (node->has_async_transaction)
pending_async = true;
else
node->has_async_transaction = true;
}
if (!thread && !pending_async)
thread = binder_select_thread_ilocked(proc);
if (thread)
binder_enqueue_thread_work_ilocked(thread, &t->work);
else if (!pending_async)
binder_enqueue_work_ilocked(&t->work, &proc->todo);
else
binder_enqueue_work_ilocked(&t->work, &node->async_todo);第一个 oneway 事务把 has_async_transaction 置 true,并尝试选择空闲线程;没有线程时进入目标进程 todo。第二个及后续事务不会再次选择线程,而是进入 node 专属 async_todo。
3. 串行释放
源码文件:kernel/common/drivers/android/binder.c
if (buffer->async_transaction && buffer->target_node) {
w = binder_dequeue_work_head_ilocked(&buf_node->async_todo);
if (!w) {
buf_node->has_async_transaction = false;
} else {
binder_enqueue_work_ilocked(w, &proc->todo);
binder_wakeup_proc_ilocked(proc);
}
}服务线程处理完事务并释放接收 buffer 后,驱动从队列头取下一项,转移到进程 todo 并唤醒进程。队列为空才清除 has_async_transaction。因此 FIFO 续接点是 buffer 释放,而不是服务方法刚进入或发送方写入完成。
4. 并行边界
串行化键是 binder_node,不是发送进程、目标进程或接口 descriptor。两个不同本地 Binder 对象,即使属于同一服务进程,也可以同时派发;同一 node 的 oneway 才共享 has_async_transaction。oneway 事务之间没有 reply,发送方无法通过返回值确认服务方法何时执行完毕。
5. 冻结队列
源码文件:kernel/common/drivers/android/binder.c
冻结目标进程时,异步事务仍可入队,返回 BR_TRANSACTION_PENDING_FROZEN;同步事务则被拒绝为 BR_FROZEN_REPLY。发送端的 waitForResponse 会把 pending 命令转换为日志并结束等待。目标解冻后,async_todo 中的事务才重新具备派发条件。
6. Buffer与额度
异步事务占用目标进程的 async buffer 配额。binder_free_buf 既回收 buffer,也触发队列续接;如果 buffer 释放失败或事务清理,驱动仍会走相应的失败释放路径,不能只从 async_todo 链表判断事务已完成。
7. 更新事务
驱动对带 TF_UPDATE_TXN 的冻结异步事务会在 async_todo 中查找旧事务并移除,让新事务 supersede 旧事务。这个优化只适用于明确可更新的异步请求,不能推广为普通 oneway 自动去重。
8. Spam检测
源码文件:kernel/common/drivers/android/binder.c
当异步 buffer 被判定为 oneway_spam_suspect,完成工作项变成 BR_ONEWAY_SPAM_SUSPECT,同时通过 netlink 上报。用户态 waitForResponse 记录告警,但 oneway 调用本身没有业务 reply;检测是观测/限流信号,不是把异步事务变成同步调用。
9. 测试路径
源码文件:frameworks/native/libs/binder/tests/binderLibTest.cpp
polling 服务的 delayed callback 测试先发送一个带延迟的 oneway,再立即发送第二个。服务端注释明确说明第二个应进入 async queue,并检查处理顺序;如果在处理第一个时已存在 callback,测试通过 callback 报错。这验证了单线程服务上同一 node 的排队,而不是抽象 FIFO 断言。
同一测试还用 BINDER_LIB_TEST_NOP_TRANSACTION 验证 oneway 方法返回的错误码会被忽略,说明发送方只能观察传输接收/冻结/spam 状态,不能取得服务方法的普通返回异常。
10. 时序图
11. 阅读检查
给定同一 node 的三个 oneway 事务,指出哪个时刻设置/清除 has_async_transaction,第二和第三项存在哪里,以及服务线程释放哪个 buffer 后第二项才会被唤醒。再换成两个不同 node,解释为什么可以并行执行。
