绕不过去的binder
目录 |
binder_proc
struct hlist_node proc_node; | 当一个进程通过open打开binder设备文件/dev/binder时,binder驱动将会为其创建一个binder_proc对象,然后通过proc_node挂载到全局哈希表binder_procs中 |
struct rb_root threads; | 每个使用了Binder的进程都有一个线程池,这是以线程id为索引构成的各线程红黑树 |
struct rb_root nodes; | 此进程中各binder实体对象的红黑树,以binder_node中ptr变量为索引 |
struct rb_root refs_by_desc; | 以引用号为索引构成的binder引用红黑树 |
struct rb_root refs_by_node; | 以binder实体地址为索引构成的binder引用红黑树 |
int pid; | 此进程的pid |
struct vm_area_struct *vma; | binder内核缓冲区mmap到用户空间的地址 |
struct task_struct *tsk; | 指向进程的任务控制块 |
struct files_struct *files; | 打开文件的结构体数组 |
struct hlist_node deferred_work_node; | 通过这里挂载到全局哈希表binder_deferred_list中 |
int deferred_work; | 需要延迟执行的工作项的类型 |
void *buffer; | binder内核缓冲区内核空间地址 |
ptrdiff_t user_buffer_offset; | binder内核缓冲区内核地址和用户空间地址的偏移值 |
struct list_head buffers; | 为了便于管理,将内核缓冲区分成若干个binder_buffer来管理,按照地址从小到大的顺序保存在此列表中 |
struct rb_root free_buffers; | 未使用的binder_buffer(即未分配了物理页面)构成的红黑树 |
struct rb_root allocated_buffers; | 已使用的binder_buffer(即已分配了物理页面)构成的红黑树 |
size_t free_async_space; | 当前可以用来保存异步事务数据的内核缓冲区大小 |
struct page **pages; | |
size_t buffer_size; | |
uint32_t buffer_free; | 为当前空闲内核缓冲区大小 |
struct list_head todo; | 进程间通信请求的链表头 |
wait_queue_head_t wait; | 线程池中的空闲线程会睡眠在这个等待队列中,当收到新的进程间通信请求时,binder驱动程序会唤醒这些线程 |
struct binder_stats stats; | 用于统计进程数据,如进程接收到进程间通信请求的次数 |
struct list_head delivered_death; | 死亡通知链表头 |
int max_threads; | binder驱动程序可以请求进程注册的线程的最大数目(当然这与线程池中最大线程数目无任何关系,这里说的只是binder驱动的最大请求数) |
int requested_threads; | binder驱动程序向当前进程已请求的线程数 |
int requested_threads_started; | binder驱动程序向当前进程已请求且已启动的线程数 |
int ready_threads; | 当前线程池中空闲的进程数 |
long default_priority; | 线程的默认优先级,一般初始化为宿主进程的优先级 |
struct dentry *debugfs_entry; | 用于debug |
binder_transaction_data
union { size_t handle; |
对于发送数据包的一方,该成员指明发送目的地。由于目的是在远端,所以这里填入的是对Binder实体的引用,存放在target.handle 中。如前述,Binder的引用在代码中也叫句柄(handle)。
|
void *cookie; | target object cookie, executeCommand中用其转化为BBinder |
unsigned int code; | 该成员存放收发双方约定的命令码,驱动完全不关心该成员的内容。通常是Server端定义的公共接口函数的编号。 |
unsigned int flags; | 与交互相关的标志位,其中最重要的是TF_ONE_WAY位。如果该位置上表明这次交互是异步的,接收方不会返回任何数据。驱动利用该位来决定是否 构建与返回有关的数据结构。另外一位TF_ACCEPT_FDS是出于安全考虑,如果发起请求的一方不希望在收到的回复中接收文件形式的Binder可以 将该位置上。因为收到一个文件形式的Binder会自动为接收方打开一个文件,使用该位可以防止打开文件过多。 |
pid_t sender_pid; | 存放发送方的进程ID |
uid_t sender_euid; | 该成员存放发送方的用户ID,由驱动负责填入,接收方可以读取该成员获知发送方的身份。 |
size_t data_size; | 该成员表示data.buffer指向的缓冲区存放的数据长度。发送数据时由发送方填入,表示即将发送的数据长度;在接收方用来告知接收到数据的长度。 |
size_t offsets_size; | 驱动一般情况下不关心data.buffer里存放什么数据,但如果有Binder在其中传输则需要将其相对data.buffer的偏移位置指出 来让驱动知道。有可能存在多个Binder同时在数据中传递,所以须用数组表示所有偏移位置。本成员表示该数组的大小。 |
union { struct { |
data.bufer存放要发送或接收到的数据;data.offsets指向Binder偏移位置数组,该数组可以位于data.buffer 中,也可以在另外的内存空间中,并无限制。buf[8]是为了无论保证32位还是64位平台,成员data的大小都是8个字节。 |
flat_binder_object
unsigned long type; | 表明该Binder的类型,包括以下几种:
|
unsigned long flags;
|
该域只对第一次传递Binder实体时有效,因为此刻驱动需要在内核中创建相应的实体节点,有些参数需要从该域取出:
|
union { void *binder; |
当传递的是Binder实体时使用binder域,指向Binder实体在应用程序中的地址。
|
void *cookie; | extra data associated with local object |
binder_transaction
int debug_id; | 用于调试 |
struct binder_work work;
|
|
struct binder_thread *from; | 指向发起事务的线程 |
struct binder_transaction *from_parent; | 假设A发起了事务T1,而T1需要依赖于B,而B在处理T1时又要求C先处理T2,而C处理T2时又要求A先处理T3,则: T1->from_parent = T2 |
struct binder_proc *to_proc; | 指向负责处理此事务的进程 |
struct binder_thread *to_thread; | 指向负责处理此事务的线程 |
struct binder_transaction *to_parent; | 见from_parent |
unsigned need_reply:1; | 标明此事务为同步还是异步 |
struct binder_buffer *buffer; | extra data associated with local object |
unsigned int code; | 与 binder_transaction_data.code一致 |
unsigned int flags; | 与 binder_transaction_data.flags一致 |
long priority; | 发起此事务的源线程的优先级 |
long saved_priority; | 在修改线程优先级前会把其原来的优先级保存在此 |
uid_t sender_euid; | 发起此事务的源线程的uid |
binder驱动使用 debugfs_create_dir创建了不少调试文件,默认情况下,debugfs会被挂载在目录/sys/kernel/debug之下,如果您的发行版里没有自动挂载,可以用如下命令手动完成(或者 '无 debugfs 则是在 /proc/binder/transaction_log'):
# mount -t debugfs none /your/debugfs/dir
参考资料:
http://disanji.net/2011/02/28/android-bnder-design/
罗升阳·《Android系统源代码情景分析》