3. Binder驱动核心数据结构详解

Binder驱动在内核空间维护了五大数据结构——binder_proc、binder_thread、binder_node、binder_ref、binder_buffer,它们共同构成了Binder IPC的完整生命周期管理。理解这些结构体是进行多平台移植适配与参数调优的前提。

核心认知: 这五个结构体分别对应进程上下文、线程上下文、服务端实体、客户端引用、数据缓冲区。移植适配时,结构体成员的对齐方式、缓存行填充、原子操作类型是平台差异的关键点。

3.1 binder_proc —— 进程上下文

binder_proc 是Binder驱动中最重要的结构体,每个使用Binder的进程在内核中对应一个实例。它管理该进程的所有Binder资源:线程池、节点树、引用表、内存映射区等。

struct binder_proc {
    struct hlist_node proc_node;          // 全局proc链表节点
    struct rb_root threads;               // 红黑树:管理binder_thread
    struct rb_root nodes;                 // 红黑树:管理binder_node
    struct rb_root refs_by_desc;          // 红黑树:按handle查找binder_ref
    struct rb_root refs_by_node;          // 红黑树:按node查找binder_ref
    struct list_head waiting_threads;     // 等待线程链表
    int pid;                              // 进程PID
    struct task_struct *tsk;              // 对应task_struct
    struct files_struct *files;           // 文件描述符表
    struct vm_area_struct *vma;           // mmap映射区
    struct mm_struct *vma_vm_mm;          // 映射所属mm
    struct binder_alloc alloc;            // 内存分配器
    struct list_head todo;                // 待处理事务链表
    struct list_head delivered_death;     // 已送达死亡通知
    int max_threads;                      // 最大线程数
    int requested_threads;                // 已请求线程数
    int requested_threads_started;        // 已启动线程数
    struct dentry *debugfs_entry;         // debugfs调试入口
    bool oneway_spam_detection_enabled;   // 单向垃圾检测开关
};
移植关注点: struct binder_alloc alloc 成员在ARM64和x86_64平台下,其内部vma和buffer指针的地址空间布局不同,需要检查PAGE_SIZE宏定义是否与目标平台MMU页大小一致(常见4KB/16KB/64KB)。
binder_proc 结构体核心成员关系图 binder_proc (进程上下文) threads (红黑树) nodes (红黑树) refs_by_desc (红黑树) refs_by_node (红黑树) todo (事务链表) waiting_threads alloc (内存分配器) max_threads 移植适配关键点: • 红黑树节点对齐:ARM32/ARM64/x86_64下rb_node结构体大小不同 • alloc内存分配器:依赖PAGE_SIZE宏,需确认目标平台页大小 • max_threads默认值:不同平台建议初始值不同(ARM建议15,x86建议20)

3.2 binder_thread —— 线程上下文

每个参与Binder通信的线程在内核中对应一个binder_thread。它记录线程的当前状态、待处理事务、以及线程与进程的归属关系。

struct binder_thread {
    struct binder_proc *proc;             // 所属进程
    struct rb_node rb_node;               // 红黑树节点(挂入proc->threads)
    struct list_head waiting_thread_node; // 等待线程链表节点
    int pid;                              // 线程PID
    int looper;                           // looper状态标志
    bool looper_need_return;              // 是否需要退出looper
    struct binder_transaction *transaction_stack; // 事务栈
    struct list_head todo;                // 待处理事务链表
    bool process_todo;                    // 是否有待处理事务
    struct binder_error *return_error;    // 错误返回
    struct binder_error reply_error;      // 回复错误
    wait_queue_head_t wait;               // 等待队列
    struct binder_stats stats;            // 统计信息
};
成员 类型 作用 移植关注点
proc struct binder_proc * 指向所属进程 指针大小随平台变化(32位4字节/64位8字节)
looper int 线程looper状态(注册/就绪/退出) 状态机逻辑与平台无关,但需注意原子操作
transaction_stack struct binder_transaction * 嵌套事务栈顶指针 栈深度受内核栈大小限制(ARM64默认16KB)
wait wait_queue_head_t 线程阻塞等待队列 等待队列初始化需适配平台调度器
常见陷阱: 在RT-Linux或PREEMPT_RT内核上移植时,wait_queue_head_t的spinlock实现可能不同,需要检查wait.h头文件中的锁类型定义,避免死锁。

3.3 binder_node —— 服务端实体

binder_node 代表一个Binder服务端实体(通常对应一个ServiceManager注册的服务)。它维护服务的引用计数、死亡通知回调、以及跨进程的弱/强引用管理。

struct binder_node {
    struct binder_proc *proc;             // 所属进程
    struct rb_node rb_node;               // 红黑树节点(挂入proc->nodes)
    struct hlist_node dead_node;          // 死亡节点链表
    struct binder_work work;              // 死亡通知工作项
    struct rb_root refs;                  // 指向该node的所有ref
    struct list_head async_todo;          // 异步事务链表
    __u32 ptr;                            // 用户空间服务对象地址
    __u32 cookie;                         // 用户空间附加数据
    __u32 flags;                          // 节点标志(如单例/允许继承)
    __u8 sched_policy;                    // 调度策略
    __u8 min_priority;                    // 最小优先级
    bool has_async_transaction;           // 是否有异步事务
    int accept_fds;                       // 是否接受文件描述符
    int inherit_rt;                       // 是否继承实时优先级
};
binder_node 与 binder_ref 引用关系图 服务端进程 (proc A) binder_node 客户端进程 (proc B) binder_ref 客户端进程 (proc C) binder_ref 一个binder_node可以被多个binder_ref引用,每个ref对应一个客户端进程的handle句柄

3.4 binder_ref —— 客户端引用

binder_ref 是客户端进程持有的服务端引用,通过整数句柄(handle)在用户空间标识一个服务。它维护了引用计数、死亡通知注册、以及指向对应binder_node的指针。

struct binder_ref {
    struct binder_proc *proc;             // 所属客户端进程
    struct rb_node rb_node_desc;          // 按handle排序的红黑树节点
    struct rb_node rb_node_node;          // 按node排序的红黑树节点
    struct hlist_node node_entry;         // 挂入node->refs链表
    struct binder_node *node;             // 指向服务端实体
    struct binder_ref_death *death;       // 死亡通知回调
    uint32_t desc;                        // 用户空间handle句柄
    int32_t strong;                       // 强引用计数
    int32_t weak;                         // 弱引用计数
    struct binder_ref_data data;          // 引用数据(debug用)
};
成员 说明 调试参数
desc 用户空间看到的handle句柄,从0开始递增 通过/sys/kernel/debug/binder/proc/[pid]/refs查看
strong/weak 强/弱引用计数,控制node生命周期 计数异常时检查BINDER_DEBUG_REF调试开关
death 注册的死亡通知回调函数指针 回调函数栈大小需适配平台(建议≥4KB)
rb_node_desc/rb_node_node 同时维护两棵红黑树索引 红黑树旋转操作在SMP平台需加锁保护

3.5 binder_buffer —— 数据缓冲区

binder_buffer 是Binder IPC数据传输的载体,位于进程mmap映射的物理内存中。它管理缓冲区的分配、释放、以及事务数据的序列化/反序列化。

struct binder_buffer {
    struct list_head entry;               // 缓冲区链表节点
    struct rb_node rb_node;               // 红黑树节点(按地址排序)
    unsigned int free:1;                  // 是否空闲
    unsigned int allow_user_free:1;       // 是否允许用户释放
    unsigned int async_transaction:1;     // 是否为异步事务
    unsigned int debug_id:29;             // 调试ID
    struct binder_transaction *transaction; // 关联的事务
    struct binder_node *target_node;      // 目标节点
    size_t data_size;                     // 数据大小
    size_t offsets_size;                  // 偏移数组大小
    size_t extra_buffers_size;            // 额外缓冲区大小
    void *user_data;                      // 用户空间数据起始地址
};
内存管理关键参数:
  • buffer_size:mmap映射大小,默认4MB,可通过/sys/module/binder/parameters/binder_size调整
  • max_threads:每个进程最大Binder线程数,默认15,影响并发缓冲区分配
  • debug_id:29位调试ID,用于追踪缓冲区生命周期,在dmesg中定位内存泄漏
binder_buffer 内存布局与事务关联图 进程mmap映射区 (默认4MB) 物理页框通过页表映射到用户空间和内核空间 空闲缓冲区 (free=1) 已分配缓冲区 (free=0) binder_transaction data_size (4B) offsets_size (4B) extra_buffers_size (4B) user_data (可变长度) 缓冲区分配策略:首次适配(First Fit) → 最佳适配(Best Fit) → 伙伴系统(Buddy) 移植时需关注:页大小对齐、DMA一致性、缓存刷新指令

3.6 五大数据结构关系总结

五个结构体通过指针和红黑树形成完整的引用网络,理解它们的关系是Binder驱动移植的核心基础。

结构体 所属关系 索引方式 生命周期 平台差异影响
binder_proc 每个进程一个 全局hlist 进程打开/dev/binder到关闭 高
binder_thread 挂入proc->threads 红黑树按pid 线程注册到注销 中
binder_node 挂入proc->nodes 红黑树按ptr 服务注册到销毁 低
binder_ref 挂入proc->refs_by_desc/node 双红黑树 获取引用到释放 中
binder_buffer 挂入proc->alloc 红黑树按地址 分配到释放 高
移植优先级: binder_buffer > binder_proc > binder_thread > binder_ref > binder_node。缓冲区管理涉及MMU页表操作和DMA一致性,是移植工作量最大的部分;节点和引用的红黑树操作逻辑与平台无关,只需关注指针大小和原子操作。