2. Binder驱动源码结构
Binder驱动是Android系统中进程间通信(IPC)的核心组件,以内核模块的形式存在于Linux内核源码树中。理解其源码结构、关键文件功能以及内核配置选项,是进行驱动移植与适配的基础。本章将深入剖析Binder驱动在内核中的位置、核心源文件的职责划分,以及如何通过内核配置启用Binder IPC功能。
2.1 Binder驱动在内核中的位置
在标准Linux内核源码树中,Binder驱动位于 drivers/android/ 目录下。该目录集中了Android相关的内核驱动,包括Binder、ashmem(已废弃)、ion(内存分配器)等。Binder驱动的主要源文件包括:
- binder.c:Binder驱动的核心实现,包含设备节点管理、ioctl处理、BC/BR协议解析、节点与引用的生命周期管理、线程管理、事务处理等主要逻辑。
- binder_alloc.c:Binder内存分配器,负责管理Binder事务中用于传递数据的内核缓冲区,包括物理页面的分配、映射、缓存与回收。
- binder_alloc.h:binder_alloc.c对应的头文件,定义内存分配器的内部数据结构与接口。
- binder_internal.h:Binder驱动的内部头文件,定义核心数据结构(如binder_proc、binder_node、binder_ref、binder_transaction等)以及内部函数声明。
- binder_trace.h:Binder驱动的tracepoint定义,用于性能追踪与调试。
移植要点: 在将Binder驱动移植到非标准内核(如RT-Linux、Xenomai、自定义嵌入式内核)时,需要将
drivers/android/ 整个目录复制到目标内核源码树中,并确保其依赖的通用内核机制(如miscdevice、waitqueue、rbtree、mmap、slab分配器)可用。
2.2 关键源文件功能解析
2.2.1 binder.c — 核心驱动逻辑
binder.c 是Binder驱动的主文件,代码量通常在8000~12000行之间(视内核版本而定)。它实现了Binder协议的全部核心逻辑,主要包括以下模块:
| 功能模块 | 核心函数/数据结构 | 职责描述 |
|---|---|---|
| 设备节点管理 | binder_open(), binder_release(), binder_mmap() |
管理 /dev/binder 设备的打开、关闭与内存映射;每个进程打开一次,获得独立的 binder_proc 实例。 |
| ioctl 处理 | binder_ioctl(), binder_ioctl_write_read() |
解析用户空间传入的 BINDER_WRITE_READ 等命令,分发到对应的处理函数。 |
| BC/BR 协议解析 | binder_thread_read(), binder_transaction() |
处理Binder命令码(BC_*)与响应码(BR_*),实现事务的发送与接收。 |
| 节点与引用管理 | binder_node, binder_ref, binder_new_node(), binder_get_ref_for_node() |
管理服务端节点(binder_node)与客户端引用(binder_ref)的创建、查找、计数与销毁。 |
| 线程管理 | binder_thread, binder_select_thread_ilocked() |
管理参与Binder通信的线程池,实现线程的分配与回收。 |
| 事务处理 | binder_transaction(), binder_transaction_buffer_release() |
核心事务处理逻辑,包括事务的构建、排队、传递、完成与资源释放。 |
| 调试与统计 | binder_stats, binder_debug_no_lock() |
提供调试接口与统计信息,可通过 /sys/kernel/debug/binder/ 访问。 |
关键数据结构关系:
binder_proc 代表一个使用Binder的进程;binder_thread 代表进程内的一个通信线程;binder_node 代表一个服务端Binder实体;binder_ref 代表客户端对某个Binder实体的引用;binder_transaction 代表一次IPC事务。这些结构体通过红黑树、链表等组织在一起,形成完整的Binder对象模型。
2.2.2 binder_alloc.c — 内存分配器
binder_alloc.c 是Binder驱动的内存管理模块,专门负责Binder事务中数据缓冲区的分配与回收。Binder IPC需要在内核空间与用户空间之间传递数据,这些数据通过 mmap() 映射的共享内存区域进行交换。binder_alloc.c 管理着这块共享内存的物理页面分配。
| 功能 | 核心函数 | 说明 |
|---|---|---|
| 缓冲区分配 | binder_alloc_new_buf() |
从进程的Binder内存池中分配一块指定大小的缓冲区,用于存放事务数据。 |
| 缓冲区释放 | binder_alloc_free_buf() |
释放已分配的缓冲区,回收物理页面或将其标记为空闲。 |
| 页面分配 | binder_alloc_alloc_page() |
当缓冲区不足时,从系统分配新的物理页面并映射到进程地址空间。 |
| 页面回收 | binder_alloc_free_page() |
回收不再使用的物理页面,返回给系统。 |
| 缓冲区查找 | binder_alloc_prepare_to_free() |
根据用户空间地址查找对应的内核缓冲区描述符。 |
| 调试接口 | binder_alloc_print_allocated() |
输出当前已分配的缓冲区列表,用于调试内存泄漏。 |
移植风险提示:
binder_alloc.c 对内存管理子系统的依赖较深,特别是 struct page、alloc_page()、kmap()、flush_dcache_page() 等接口。在移植到非标准架构(如ARM64、RISC-V、MIPS)或非标准内核时,需要验证这些接口的行为是否一致。此外,Binder内存分配器使用红黑树(rbtree)管理空闲缓冲区,需要确保目标内核支持rbtree。
2.3 内核配置选项:CONFIG_ANDROID_BINDER_IPC
在编译Linux内核时,需要通过内核配置选项启用Binder驱动。主要的配置选项如下:
| 配置选项 | 默认值 | 说明 |
|---|---|---|
CONFIG_ANDROID_BINDER_IPC |
n | 主开关,启用Binder IPC驱动。选择y(编译进内核)或m(编译为模块)。 |
CONFIG_ANDROID_BINDERFS |
n | 启用Binderfs文件系统,用于动态创建Binder设备节点(Android 10+ 推荐)。 |
CONFIG_ANDROID_BINDER_DEVICES |
"binder" | 指定Binder设备名称,多个设备用逗号分隔(如 "binder,hwbinder,vndbinder")。 |
在 drivers/android/Kconfig 文件中,这些选项的定义如下:
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
depends on MMU
default n
help
Binder is used by Android for inter-process communication.
This driver is required for Android userspace.
config ANDROID_BINDERFS
bool "Android Binderfs filesystem"
depends on ANDROID_BINDER_IPC
default n
help
Binderfs is a pseudo filesystem for dynamically creating
binder device nodes.
config ANDROID_BINDER_DEVICES
string "Binder device nodes"
depends on ANDROID_BINDER_IPC
default "binder"
help
List of binder device nodes to create, separated by commas.
配置建议:
- 对于Android 10及以上版本,建议同时启用
CONFIG_ANDROID_BINDERFS,以便动态管理多个Binder设备(binder、hwbinder、vndbinder)。 - 对于嵌入式或定制系统,如果只需要一个Binder设备,可以保持
CONFIG_ANDROID_BINDER_DEVICES="binder"。 - 如果使用模块方式(m),需要确保在Android用户空间启动前加载Binder模块,否则系统服务无法启动。
- Binder驱动依赖
MMU(内存管理单元),无MMU系统无法使用Binder。