绕不过去的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;

 void *ptr;

} target;

对于发送数据包的一方,该成员指明发送目的地。由于目的是在远端,所以这里填入的是对Binder实体的引用,存放在target.handle 中。如前述,Binder的引用在代码中也叫句柄(handle)。



当数据包到达接收方时,驱动已将该成员修改成Binder实体,即指向Binder对象内存的指针,使用target.ptr来获得。该指针是接收 方在将Binder实体传输给其它进程时提交给驱动的,驱动程序能够自动将发送方填入的引用转换成接收方Binder对象的指针,故接收方可以直接将其当 做对象指针来使用(通常是将其reinterpret_cast成相应类)。

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 {

  const void *buffer;

  const void *offsets;

 } ptr;

 uint8_t buf[8];

} data;

data.bufer存放要发送或接收到的数据;data.offsets指向Binder偏移位置数组,该数组可以位于data.buffer 中,也可以在另外的内存空间中,并无限制。buf[8]是为了无论保证32位还是64位平台,成员data的大小都是8个字节。


flat_binder_object

unsigned long type; 表明该Binder的类型,包括以下几种:



BINDER_TYPE_BINDER:表示传递的是Binder实体,并且指向该实体的引用都是强类型;


BINDER_TYPE_WEAK_BINDER:表示传递的是Binder实体,并且指向该实体的引用都是弱类型;


BINDER_TYPE_HANDLE:表示传递的是Binder强类型的引用


BINDER_TYPE_WEAK_HANDLE:表示传递的是Binder弱类型的引用


BINDER_TYPE_FD:表示传递的是文件形式的Binder,详见下节

unsigned long flags;


                    

该域只对第一次传递Binder实体时有效,因为此刻驱动需要在内核中创建相应的实体节点,有些参数需要从该域取出:



第0-7位:代码中用FLAT_BINDER_FLAG_PRIORITY_MASK取得,表示处理本实体请求数据包的线程的最低优先级。当一个应 用程序提供多个实体时,可以通过该参数调整分配给各个实体的处理能力。


第8位:代码中用FLAT_BINDER_FLAG_ACCEPTS_FDS取得,置1表示该实体可以接收其它进程发过来的文件形式的 Binder。由于接收文件形式的Binder会在本进程中自动打开文件,有些Server可以用该标志禁止该功能,以防打开过多文件。

union {

 void *binder;

 signed long handle;

};

当传递的是Binder实体时使用binder域,指向Binder实体在应用程序中的地址。



当传递的是Binder引用时使用handle域,存放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

T2->from_parent = T3

T3->to_parent = T1

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

BC&BR枚举

#define NAME(n) pr_err("%s:%d\n", #n, n)
const void print_cmd_name_value(void) {
    NAME(BR_ERROR);
    NAME(BR_OK);
    NAME(BR_TRANSACTION);
    NAME(BR_REPLY);
    NAME(BR_ACQUIRE_RESULT);
    NAME(BR_DEAD_REPLY);
    NAME(BR_TRANSACTION_COMPLETE);
    NAME(BR_INCREFS);
    NAME(BR_ACQUIRE);
    NAME(BR_RELEASE);
    NAME(BR_DECREFS);
    NAME(BR_ATTEMPT_ACQUIRE);
    NAME(BR_NOOP);
    NAME(BR_SPAWN_LOOPER);
    NAME(BR_FINISHED);
    NAME(BR_DEAD_BINDER);
    NAME(BR_CLEAR_DEATH_NOTIFICATION_DONE);
    NAME(BR_FAILED_REPLY);
    
    NAME(BC_TRANSACTION);
    NAME(BC_REPLY);
    NAME(BC_ACQUIRE_RESULT); 
    NAME(BC_FREE_BUFFER); 
    NAME(BC_INCREFS); 
    NAME(BC_ACQUIRE); 
    NAME(BC_RELEASE); 
    NAME(BC_DECREFS); 
    NAME(BC_INCREFS_DONE); 
    NAME(BC_ACQUIRE_DONE); 
    NAME(BC_ATTEMPT_ACQUIRE); 
    NAME(BC_REGISTER_LOOPER); 
    NAME(BC_ENTER_LOOPER); 
    NAME(BC_EXIT_LOOPER); 
    NAME(BC_REQUEST_DEATH_NOTIFICATION); 
    NAME(BC_CLEAR_DEATH_NOTIFICATION); 
    NAME(BC_DEAD_BINDER_DONE); 
}
<3>[  188.115681]<0> (0)[4134:dumpstate]binder: BR_ERROR:-2147192320
<3>[  188.115704]<0> (0)[4134:dumpstate]binder: BR_OK:29185
<3>[  188.115716]<0> (0)[4134:dumpstate]binder: BR_TRANSACTION:-2143260158
<3>[  188.115728]<0> (0)[4134:dumpstate]binder: BR_REPLY:-2143260157
<3>[  188.115740]<0> (0)[4134:dumpstate]binder: BR_ACQUIRE_RESULT:-2147192316
<3>[  188.115752]<0> (0)[4134:dumpstate]binder: BR_DEAD_REPLY:29189
<3>[  188.115763]<0> (0)[4134:dumpstate]binder: BR_TRANSACTION_COMPLETE:29190
<3>[  188.115775]<0> (0)[4134:dumpstate]binder: BR_INCREFS:-2146405881
<3>[  188.115787]<0> (0)[4134:dumpstate]binder: BR_ACQUIRE:-2146405880
<3>[  188.115799]<0> (0)[4134:dumpstate]binder: BR_RELEASE:-2146405879
<3>[  188.115810]<0> (0)[4134:dumpstate]binder: BR_DECREFS:-2146405878
<3>[  188.115822]<0> (0)[4134:dumpstate]binder: BR_ATTEMPT_ACQUIRE:-2145881589
<3>[  188.115833]<0> (0)[4134:dumpstate]binder: BR_NOOP:29196
<3>[  188.115845]<0> (0)[4134:dumpstate]binder: BR_SPAWN_LOOPER:29197
<3>[  188.115856]<0> (0)[4134:dumpstate]binder: BR_FINISHED:29198
<3>[  188.115868]<0> (0)[4134:dumpstate]binder: BR_DEAD_BINDER:-2146930161
<3>[  188.115881]<0> (0)[4134:dumpstate]binder: BR_CLEAR_DEATH_NOTIFICATION_DONE:-2146930160
<3>[  188.115892]<0> (0)[4134:dumpstate]binder: BR_FAILED_REPLY:29201
<3>[  188.115904]<0> (0)[4134:dumpstate]binder: BC_TRANSACTION:1077961472
<3>[  188.115916]<0> (0)[4134:dumpstate]binder: BC_REPLY:1077961473
<3>[  188.115928]<0> (0)[4134:dumpstate]binder: BC_ACQUIRE_RESULT:1074029314
<3>[  188.115939]<0> (0)[4134:dumpstate]binder: BC_FREE_BUFFER:1074291459
<3>[  188.115951]<0> (0)[4134:dumpstate]binder: BC_INCREFS:1074029316
<3>[  188.115963]<0> (0)[4134:dumpstate]binder: BC_ACQUIRE:1074029317
<3>[  188.115974]<0> (0)[4134:dumpstate]binder: BC_RELEASE:1074029318
<3>[  188.115986]<0> (0)[4134:dumpstate]binder: BC_DECREFS:1074029319
<3>[  188.115998]<0> (0)[4134:dumpstate]binder: BC_INCREFS_DONE:1074815752
<3>[  188.116010]<0> (0)[4134:dumpstate]binder: BC_ACQUIRE_DONE:1074815753
<3>[  188.116021]<0> (0)[4134:dumpstate]binder: BC_ATTEMPT_ACQUIRE:1074291466
<3>[  188.116033]<0> (0)[4134:dumpstate]binder: BC_REGISTER_LOOPER:25355
<3>[  188.116044]<0> (0)[4134:dumpstate]binder: BC_ENTER_LOOPER:25356
<3>[  188.116056]<0> (0)[4134:dumpstate]binder: BC_EXIT_LOOPER:25357
<3>[  188.116068]<0> (0)[4134:dumpstate]binder: BC_REQUEST_DEATH_NOTIFICATION:1074553614
<3>[  188.116080]<0> (0)[4134:dumpstate]binder: BC_CLEAR_DEATH_NOTIFICATION:1074553615
<3>[  188.116092]<0> (0)[4134:dumpstate]binder: BC_DEAD_BINDER_DONE:1074291472


进程间数据交换


参考资料:

http://disanji.net/2011/02/28/android-bnder-design/

罗升阳·《Android系统源代码情景分析》