3. Binder驱动核心数据结构

Binder IPC 机制的实现依赖于驱动层精心设计的五个核心数据结构:binder_proc、binder_node、binder_ref、binder_buffer 和 binder_transaction。它们分别对应进程上下文、Binder 实体、Binder 引用、数据传输缓冲区以及事务描述。理解这五个结构体是掌握 Binder 驱动工作原理的基石。

学习提示: 这五个结构体在驱动源码 drivers/android/binder.c 和 drivers/android/binder_internal.h 中定义。建议读者在学习过程中对照源码阅读,以加深理解。

3.1 binder_proc:进程上下文管理者

binder_proc 结构体用于描述一个正在使用 Binder 通信的进程上下文。每个打开 Binder 设备文件的进程在内核中都会对应一个 binder_proc 实例。它管理着该进程的所有 Binder 资源,包括线程、节点、引用、缓冲区等。

核心字段与功能

字段名 类型 功能描述
proc_node struct rb_node 将当前 proc 挂入全局 proc 红黑树的节点
threads struct rb_root 红黑树根,管理该进程内所有 binder_thread
nodes struct rb_root 红黑树根,管理该进程创建的所有 binder_node
refs_by_desc struct rb_root 红黑树根,按描述符(handle)索引 binder_ref
refs_by_node struct rb_root 红黑树根,按目标节点索引 binder_ref
alloc struct binder_alloc 内存分配器,管理进程的 Binder 缓冲区池
pid pid_t 进程 PID
context struct binder_context * 指向 Binder 上下文(如 /dev/binder 或 /dev/hwbinder)
todo struct list_head 待处理事务链表,驱动将事务挂入此队列唤醒进程
关键设计: binder_proc 使用红黑树(rb_root)来管理线程、节点和引用,确保查找操作的时间复杂度为 O(log n)。缓冲区管理则通过 binder_alloc 结构体实现,采用预分配和按需映射的机制。
binder_proc 结构体核心关系图 binder_proc threads (rb_root) nodes (rb_root) refs_by_desc (rb_root) refs_by_node (rb_root) alloc (binder_alloc) todo (list_head) 说明: binder_proc 是进程级的总控结构,通过红黑树管理线程、节点和引用,通过 binder_alloc 管理缓冲区池,通过 todo 链表接收待处理事务。

3.2 binder_node:Binder 实体描述符

binder_node 代表一个 Binder 服务端实体。当一个进程通过 BC_ENTER_LOOPER 或 BINDER_SET_CONTEXT_MGR 注册服务时,驱动会为其创建一个 binder_node。该结构体描述了服务端提供的接口以及内核如何将事务路由到该服务。

核心字段与功能

字段名 类型 功能描述
proc struct binder_proc * 指向拥有该节点的进程
ptr binder_uintptr_t 用户空间服务端 Binder 对象的地址(弱引用)
cookie binder_uintptr_t 用户空间服务端附加数据地址
refs struct list_head 链表头,链接所有指向该节点的 binder_ref
internal_strong_refs atomic_t 内核持有的强引用计数
local_weak_refs atomic_t 本地弱引用计数
has_async_transaction int 标记是否有异步事务正在处理
rb_node struct rb_node 挂入 proc->nodes 红黑树的节点
注意: ptr 和 cookie 是用户空间地址,驱动不会直接解引用,而是通过 copy_from_user / copy_to_user 进行安全拷贝。引用计数机制确保在事务处理过程中节点不会被意外释放。
binder_node 与 binder_ref 映射关系 服务端进程 (Server) binder_node 客户端进程 A (Client) binder_ref (handle=1) 客户端进程 B (Client) binder_ref (handle=5) 关键映射关系: 1. 服务端进程创建 binder_node,驱动将其注册到 proc->nodes 红黑树。 2. 客户端进程通过 handle 持有 binder_ref,每个 ref 通过 node 指针指向唯一的 binder_node。 3. 一个 binder_node 可以被多个客户端进程引用,每个客户端拥有独立的 handle 值。

3.3 binder_ref:Binder 引用与句柄映射

binder_ref 是客户端视角的 Binder 引用。每个客户端进程通过一个整型句柄(handle)来标识远程服务,驱动内部将 handle 映射为 binder_ref,再通过 binder_ref 找到目标 binder_node。

核心字段与功能

字段名 类型 功能描述
proc struct binder_proc * 指向持有该引用的客户端进程
node struct binder_node * 指向被引用的 Binder 实体节点
desc u32 句柄值(handle),客户端通过此值识别服务
rb_node_desc struct rb_node 挂入 proc->refs_by_desc 红黑树的节点
rb_node_node struct rb_node 挂入 proc->refs_by_node 红黑树的节点
node_entry struct list_head 挂入 node->refs 链表的节点
death struct binder_ref_death * 死亡通知回调,用于监听服务端退出
设计亮点: binder_ref 同时维护了两个红黑树索引(按 desc 和按 node),使得驱动既可以通过 handle 快速查找引用,也可以在遍历节点时快速找到所有引用该节点的客户端。这种双索引设计是 Binder 高效路由的关键。

3.4 binder_buffer:数据传输缓冲区

binder_buffer 是 Binder 驱动中用于承载跨进程数据的核心结构。每个 binder_buffer 对应一块内核分配的物理连续内存,用于在进程间传递 Parcel 数据。

核心字段与功能

字段名 类型 功能描述
data void * 缓冲区在内核空间的虚拟地址
size size_t 缓冲区总大小(字节)
proc struct binder_proc * 指向拥有该缓冲区的进程
free int 标记缓冲区是否空闲
allow_user_free int 标记是否允许用户空间释放此缓冲区
async_transaction int 标记是否为异步事务分配的缓冲区
entry struct list_head 挂入 proc->alloc.buffers 链表的节点
transaction struct binder_transaction * 指向使用该缓冲区的事务
内存管理要点: Binder 缓冲区采用预分配策略,每个进程在打开 Binder 设备时,驱动会通过 binder_alloc 分配一块连续的内核虚拟地址空间(默认 4MB)。binder_buffer 从这块空间中按需分配,使用完毕后归还。这种设计避免了频繁的页分配开销,但也要求驱动必须正确处理缓冲区生命周期,防止内存泄漏。
binder_buffer 生命周期流程 1. 预分配 2. 分配 3. 数据拷贝 4. 释放 详细说明: 1. 预分配:进程打开 Binder 设备时,驱动通过 mmap 分配 4MB 内核虚拟地址空间。 2. 分配:发送事务时,驱动从空闲缓冲区列表中分配一个 binder_buffer,大小由数据量决定。 3. 数据拷贝:驱动通过 copy_from_user 将用户数据写入缓冲区,然后映射到接收进程的用户空间。 4. 释放:接收进程处理完数据后,通过 BC_FREE_BUFFER 命令通知驱动释放缓冲区。

3.5 binder_transaction:事务描述与路由

binder_transaction 是 Binder IPC 的核心工作单元,描述了一次完整的跨进程调用。它包含了从发送方到接收方的所有上下文信息,包括数据缓冲区、目标节点、线程状态等。

核心字段与功能

字段名 类型 功能描述
work struct binder_work 工作项,挂入目标线程或进程的 todo 链表
buffer struct binder_buffer * 指向承载事务数据的缓冲区
from struct binder_thread * 发送方线程(可能为 NULL,如来自内核)
to_thread struct binder_thread * 目标线程(如果已指定)
to_proc struct binder_proc * 目标进程
need_reply int 标记是否需要回复(同步调用为 1,异步为 0)
from_parent struct binder_transaction * 指向父事务(用于嵌套调用场景)
flags unsigned int 事务标志(如 TF_ONE_WAY、TF_ACCEPT_FDS)
code unsigned int 事务代码,标识具体操作(如 TRANSACTION_TYPE)
priority int 事务优先级,用于继承发送方优先级
事务路由机制: 驱动根据目标 handle 找到 binder_ref,再通过 binder_ref->node 找到 binder_node,最后根据 binder_node->proc 确定目标进程。如果目标进程有空闲线程,事务直接挂入线程的 todo 链表;否则挂入进程的 todo 链表,由进程调度线程处理。
binder_transaction 路由与处理流程 客户端进程 binder_thread Binder 驱动 binder_ref binder_node binder_transaction 服务端进程 binder_thread 事务路由步骤: 1. 客户端线程通过 ioctl(BC_TRANSACTION) 将事务数据传给驱动。 2. 驱动根据 handle 查找 binder_ref,再通过 binder_ref->node 找到 binder_node。 3. 驱动创建 binder_transaction,分配 binder_buffer 并拷贝数据。 4. 驱动将事务挂入目标线程的 todo 链表,唤醒目标线程处理。 5. 目标线程通过 ioctl(BR_TRANSACTION) 从驱动读取事务并处理。

3.6 五大结构体关系总结 ← 上一章 📖 返回目录 下一章 →