第2章 Binder驱动关键数据结构

Binder驱动运行在内核空间,是用户空间IPC请求的最终执行者。驱动维护了五类核心结构体——binder_proc、binder_node、binder_ref、binder_transaction、binder_buffer。它们构成Binder通信的底层骨架:进程上下文、实体对象、远程引用、事务记录、数据缓冲区。理解这些结构体是掌握Binder原理和AIDL性能调优的前提。

2.1 binder_proc——进程上下文

每个打开Binder设备的进程在驱动内对应一个binder_proc实例。它记录该进程的所有Binder资源:已注册的实体节点、持有的引用、待处理的事务队列以及内存映射信息。

字段类型说明
tsktask_struct *关联的内核进程描述符
vmastruct vm_area_struct *用户空间映射的虚拟内存区域
nodesrb_root红黑树,索引该进程创建的binder_node
refs_by_descrb_root红黑树,按照句柄(handle)查找binder_ref
refs_by_noderb_root红黑树,按照目标节点索引binder_ref
todostruct list_head等待该进程处理的待办事务链表
pidpid_t用户空间进程ID

2.2 binder_node——服务端实体

当服务端通过BINDER_SET_CONTEXT_MGR或AIDLaddService()注册对象时,驱动创建一个binder_node。它代表一个可被远程调用的Binder实体,内部保存对象接口方法指针、弱/强引用计数和链接到binder_proc的回指指针。

  • ptr:服务端用户空间对象的虚拟地址(实际只用作唯一标识)
  • cookie:注册时传入的附加数据,通常指向服务端对象本身
  • proc:所属的binder_proc
  • refs:所有指向该节点的引用红黑树根
  • internal_strong_refs:内部强引用计数
  • local_weak_refs:本地弱引用计数

2.3 binder_ref——远程引用(句柄)

客户端通过getService()获取远程Binder对象时,驱动在客户端进程的binder_proc中插入一条binder_ref,同时分配整数句柄(handle)。后续IPC调用使用句柄代替完整节点地址,提高效率。

句柄值从0开始,0通常保留给ServiceManager的Binder节点。每个进程的句柄空间独立。
字段说明
desc整数句柄,用户空间传递的引用标识
node指向对应的binder_node
death死亡通知回调列表

2.4 binder_transaction——事务记录

一次Binder调用(包括方法参数、返回值、BR_TRANSACTION/BC_TRANSACTION命令)被封装为一个binder_transaction。事务在工作队列间传递,驱动通过它跟踪调用链、嵌套深度和返回路径。

  • work:链接到proc->todo等列表
  • buffer:指向binder_buffer,存储实际数据
  • from:发起端binder_proc
  • to_proc:目标端binder_proc
  • to_thread:目标线程(可选)
  • code:AIDL方法编号
  • flags:一次性/异步/无返回等标记

2.5 binder_buffer——数据缓冲区

驱动通过进程的mmap共享内存(通常128KB)分配binder_buffer块。每次事务的数据空间都来自这块预映射内存,避免内核-用户空间拷贝。缓冲区被划分为多个小片,采用最佳适配算法管理。

// binder_buffer 在 binder.c 中的定义
struct binder_buffer {
    struct list_head entry;   // 挂在空闲链表或已分配链表
    struct rb_node rb_node;   // 红黑树节点(按地址排序)
    unsigned free : 1;        // 是否空闲
    unsigned allow_user_free : 1;
    unsigned async_transaction : 1;
    struct binder_transaction *transaction; // 所属事务
    struct binder_node *target_node;
    size_t data_size;         // 有效数据大小
    size_t offsets_size;      // 对象偏移表大小
    uint8_t data[0];          // 变长数据开始
};

2.6 数据结构关系图

Binder驱动关键数据结构关系 binder_proc binder_node binder_ref binder_transaction binder_buffer nodes红黑树 refs_by_desc/refs_by_node node字段指向 from(源proc) to_proc(目标proc) buffer binder_proc binder_node binder_ref binder_transaction binder_buffer

2.7 内核源码中的定义示例

以下摘取自Android 12内核的/drivers/staging/android/binder.c和binder_internal.h,展示了主要结构体字段的声明方式(为简洁只保留关键成员)。

// binder_internal.h
struct binder_proc {
    struct hlist_node proc_node;
    struct rb_root nodes;
    struct rb_root refs_by_desc;
    struct rb_root refs_by_node;
    struct list_head waiting_threads;
    struct list_head todo;
    pid_t pid;
    struct mm_struct *mm;
    struct vm_area_struct *vma;
    struct task_struct *tsk;
    ...
};

struct binder_node {
    struct rb_node rb_node;
    struct hlist_node dead_node;
    struct binder_proc *proc;
    uintptr_t ptr;
    uintptr_t cookie;
    unsigned int has_strong_ref;
    unsigned int pending_strong_ref;
    unsigned int has_weak_ref;
    unsigned int pending_weak_ref;
    int internal_strong_refs;
    int local_weak_refs;
    ...
};

struct binder_ref {
    struct rb_node rb_node_desc;
    struct rb_node rb_node_node;
    struct hlist_node dead_node;
    struct binder_proc *proc;
    struct binder_node *node;
    struct binder_ref_death *death;
    uint32_t desc;
    ...
};

struct binder_transaction {
    struct binder_work work;
    struct binder_thread *from;
    struct binder_transaction *from_parent;
    struct binder_proc *to_proc;
    struct binder_thread *to_thread;
    struct binder_transaction *to_parent;
    struct binder_buffer *buffer;
    unsigned int code;
    unsigned int flags;
    ...
};

struct binder_buffer {
    struct list_head entry;
    struct rb_node rb_node;
    struct binder_transaction *transaction;
    struct binder_node *target_node;
    size_t data_size;
    size_t offsets_size;
    uint8_t data[0];
};

2.8 调试与注意事项

引用计数泄漏风险:每个binder_node维护内部强引用计数(internal_strong_refs),当客户端获取引用后未正确释放(AIDL中未断开IBinder.DeathRecipient),会导致节点无法回收乃至进程OOM。使用adb shell cat /sys/kernel/debug/binder/proc/*可以查看当前各进程的节点和引用计数。
事务栈深度:binder_transaction中的from_parent/to_parent字段形成调用栈。嵌套调用超过32层(BINDER_MAX_THREADS_PER_PROC)将触发BR_FAILED_REPLY。遇到TransactionTooLargeException时优先检查事务数据大小是否超出binder_buffer的单片容量(通常1MB减去头开销)。
章节知识点调试命令/检查点
binder_proc: nodes/refs红黑树adb shell ls /sys/kernel/debug/binder/proc/<pid>
binder_node: 强/弱引用adb shell cat /sys/kernel/debug/binder/proc/<pid>/nodes
binder_transaction: 未完成事务adb shell cat /sys/kernel/debug/binder/transaction
binder_buffer: 共享内存使用量adb shell cat /proc/<pid>/maps | grep /dev/binder
用户态与内核态数据结构的不对称:binder_buffer中的data[0]是可变长度数组,实际数据紧跟在结构体头部之后。在AIDL传递大对象(如Bitmap)时,务必注意Parcel的setDataPosition和setDataCapacity应与驱动分配的大小对齐,否则会导致binder通过计算段错误或截断。