531
查看绕不过去的binder的源代码
绕不过去的binder
0
←
绕不过去的binder
跳转至:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
你被禁止执行你刚才请求的操作。
您可以查看并复制此页面的源代码:
=== binder_proc === {| border="1" cellspacing="0" width="600px" |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 === {| border="1" cellspacing="0" width="600px" |union {<br> size_t handle;<br> void *ptr;<br> } target; |对于发送数据包的一方,该成员指明发送目的地。由于目的是在远端,所以这里填入的是对Binder实体的引用,存放在target.handle 中。如前述,Binder的引用在代码中也叫句柄(handle)。 <br> 当数据包到达接收方时,驱动已将该成员修改成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 {<br> struct {<br> const void *buffer;<br> const void *offsets;<br> } ptr;<br> uint8_t buf[8];<br> } data; |data.bufer存放要发送或接收到的数据;data.offsets指向Binder偏移位置数组,该数组可以位于data.buffer 中,也可以在另外的内存空间中,并无限制。buf[8]是为了无论保证32位还是64位平台,成员data的大小都是8个字节。 |} === flat_binder_object === {| border="1" cellspacing="0" width="600px" |unsigned long type; |表明该Binder的类型,包括以下几种: <br> BINDER_TYPE_BINDER:表示传递的是Binder实体,并且指向该实体的引用都是强类型; <br> BINDER_TYPE_WEAK_BINDER:表示传递的是Binder实体,并且指向该实体的引用都是弱类型; <br> BINDER_TYPE_HANDLE:表示传递的是Binder强类型的引用 <br> BINDER_TYPE_WEAK_HANDLE:表示传递的是Binder弱类型的引用 <br> BINDER_TYPE_FD:表示传递的是文件形式的Binder,详见下节 |- |unsigned long flags; <br> |该域只对第一次传递Binder实体时有效,因为此刻驱动需要在内核中创建相应的实体节点,有些参数需要从该域取出: <br> 第0-7位:代码中用FLAT_BINDER_FLAG_PRIORITY_MASK取得,表示处理本实体请求数据包的线程的最低优先级。当一个应 用程序提供多个实体时,可以通过该参数调整分配给各个实体的处理能力。 <br> 第8位:代码中用FLAT_BINDER_FLAG_ACCEPTS_FDS取得,置1表示该实体可以接收其它进程发过来的文件形式的 Binder。由于接收文件形式的Binder会在本进程中自动打开文件,有些Server可以用该标志禁止该功能,以防打开过多文件。 |- | union {<br> void *binder;<br> signed long handle;<br> }; |当传递的是Binder实体时使用binder域,指向Binder实体在应用程序中的地址。 <br> 当传递的是Binder引用时使用handle域,存放Binder在进程中的引用号。 |- |void *cookie; |extra data associated with local object |} === binder_transaction === {| border="1" cellspacing="0" width="600px" |int debug_id; |用于调试 |- |struct binder_work work; <br> | |- |struct binder_thread *from; |指向发起事务的线程 |- |struct binder_transaction *from_parent; |假设A发起了事务T1,而T1需要依赖于B,而B在处理T1时又要求C先处理T2,而C处理T2时又要求A先处理T3,则:<br> T1->from_parent = T2<br> T2->from_parent = T3<br> 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 [[binder_transaction.copy_from_user|进程间数据交换]] 参考资料: http://disanji.net/2011/02/28/android-bnder-design/ 罗升阳·《Android系统源代码情景分析》
返回
绕不过去的binder
。
导航菜单
个人工具
   
个人维基
注册
登录
名字空间
页面
变换
查看
阅读
查看源代码
统计
查看历史
操作
搜索
导航
首页
Ubuntu
Android
C&CPP
Java
Python
大杂烩
最近更改
工具箱
所有页面
文件列表
特殊页面