binder_procs
- static HLIST_HEAD(binder_procs);
在binder_open中每一个新创建的binder_proc都通过binder_proc->proc_node链接到这个双向链表;在binder_deferred_release函数释放binder_proc前,从binder_procs删除这个proc节点
flat_binder_object
我们把进程之间传递的数据称之为Binder对象,分为Binder实体和Binder引用,对应于数据结构flat_binder_obejct。一个transaction中可能包含有多个Binder object。
- 42 /*
- 43 * This is the flattened representation of a Binder object for transfer
- 44 * between processes. The 'offsets' supplied as part of a binder transaction
- 45 * contains offsets into the data where these structures occur. The Binder
- 46 * driver takes care of re-writing the structure type and data as it moves
- 47 * between processes.
- 48 */
- 49 struct flat_binder_object {
- 50 /* 8 bytes for large_flat_header. */
- 51 unsigned long type;
- 52 unsigned long flags;
- 53
- 54 /* 8 bytes of data. */
- 55 union {
- 56 void *binder; /* local object */
- 57 signed long handle; /* remote object */
- 58 };
- 59
- 60 /* extra data associated with local object */
- 61 void *cookie;
- 62 };
@type描述的是Binder的类型
- 29 enum {
- 30 BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
- 31 BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
- 32 BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
- 33 BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
- 34 BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
- 35 };
BINDER_TYPE_BINDER表示数据就是一个Binder本地对象
BINDER_TYPE_HANDLE表示数据是一个远程handler
BINDER_TYPE_FB表示传输的数据中存储的是文件描述符
BINDER_TYPE_WEAK_BANDER
BINDER_TYPE_WEAK_HANDLE
@flags字段表示传输方式,比如同步异步,和binder_transaction_data中flags 有相同的含义
- 110 enum transaction_flags {
- 111 TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
- 112 TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
- 113 TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
- 114 TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
- 115 };
@TF_ONE_WAY表示单向传递,隐含着操作是异步的,不需要返回;
@TF_ROOT_OBJECT表示内容是一个组建的根对象,对应类型为本地对象Binder
@TF_STATUS_CODE 表示内容是一个32位的状态码,对应类型为远程对象的引用(即句柄handle)
@TF_ACCEPT_FDS表示可以接收一个文件描述符,对应的类型为文件(BINDER_TYPE_FD),即handle中存储的为文件描述符
无论是Binder引用还是Binder实体都从属于某一个进程,所以该结构不恩你个透明的在进程之间传输,必须经过驱动翻译。例如当Server把Binder实体传递给Client时,在发送数据流时binder实体通过Binder dirver,Binder driver发现flat_binder_object中的type是BINDER_TYPE_BINDER,说明binder指向的是server进程用户空间地址。把这个直接传送给client是毫无用处的,驱动必须要对数据流中的这个Binder进行修改,将type改为BINDER_TYPE_HANDLE,同时为这个Binder实体在接收进程中创建位于内核的Binder引用,并将引用号填入handle中。同样如果数据流中包含的是Binder引用(type 为BINDER_TYPE_HANDLE),那么要找到这个引用对应和的内核实体binder_node,然后用binder_node->ptr替换@binder,并且修改type为BINDER_TYPE_BINDER。这样接收进程接收到的就是一个进程本地地址。
这样做有两个好处:
1. 保证唯一性:使用Binder实体的用户空间地址并不能保证唯一性,其他server的Binder实体可能使用相同的地址
2. 保证安全性:应用程序无法随便猜测一个引用号填入target.handle来申请服务了,因为驱动还没有为application在内核中为Client进程创建相应的Binder引用,必定会被拒绝。只有经过Binder driver为Client生成的Binder引用才能使用
binder_transaction_data
Binder使用binder_transaction_data传输实际内容,其定义如下
- 117 struct binder_transaction_data {
- 118 /* The first two are only used for bcTRANSACTION and brTRANSACTION,
- 119 * identifying the target and contents of the transaction.
- 120 */
- 121 union {
- 122 size_t handle; /* target descriptor of command transaction */
- 123 void *ptr; /* target descriptor of return transaction */
- 124 } target;
- 125 void *cookie; /* target object cookie */
- 126 unsigned int code; /* transaction command */
- 127
- 128 /* General information about the transaction. */
- 129 unsigned int flags;
- 130 pid_t sender_pid;
- 131 uid_t sender_euid;
- 132 size_t data_size; /* number of bytes of data */
- 133 size_t offsets_size; /* number of bytes of offsets */
- 134
- 135 /* If this transaction is inline, the data immediately
- 136 * follows here; otherwise, it ends with a pointer to
- 137 * the data buffer.
- 138 */
- 139 union {
- 140 struct {
- 141 /* transaction data */
- 142 const void *buffer;
- 143 /* offsets from buffer to flat_binder_object structs */
- 144 const void *offsets;
- 145 } ptr;
- 146 uint8_t buf[8];
- 147 } data;
- 148 };
@handle 对于发送数据包的一方,该成员指明发送目的地,这里填入的是对Binder实体的引用,根据此handle,当数据到达接收方时,驱动已经将该成员修改为Binder实体,即指向Biner对象在应用进程中的指针,使用target.ptr来获取。该指针是接收发在将Binder实体传输给其他进程时提交给驱动的,驱动程序会自动将发送方填入的引用转换成接收方Binder对象的指针,故接收方直接将其当作对象指针来使用。
@ptr 对于响应方,@target联合使用ptr字段,以便找到需要处理此事件的对象。因此handle和ptr是同一件事的两种表达方式,驱动要负责handle和ptr之间的转换,当然驱动一定要维护二者之间的转换关系。
@cookie 表示target字段所附加的额外数据,发送方忽略该成员,接收方在收到数据包时,该成员存放的是接收方创建Binder实体时定义的任意数值,作为与Binder指针相关的额外信息放在驱动中。
@code 是一个命令,它描述了请求对象要执行的命令码,这是一个服务特定的字段,驱动完全不关心该成员的内容。不同的服务有不同的命令集,以servicemanager服务为例,支持的命令码为
- SVC_MGR_GET_SERVICE = 1,
- SVC_MGR_CHECK_SERVICE,
- SVC_MGR_ADD_SERVICE,
- SVC_MGR_LIST_SERVICES,
@flags 与交互相关的标志位,其中最总要的是TF_ONE_WAY位。如果该位置上表明这次交互是异步的,Server端不会返回任何数据。驱动力用该位来决定是否构建与返回相关的数据结构。
@sender_pid: @sender_euid表示进程的UID和PID,由驱动负责填入,接收方可以读取该成员获知发送方的身份
@data_size: 表示data.buffer指向的缓冲区存放数据的长度
@offsets_size:驱动一般不会关心data.buffer里面存放的数据,但是如果数据中包含binder,那么需要通过@offset来告知驱动binder在data.buffer中的偏移位置。在data.buffer中可能存在多个Binder,因此需要多个偏移位置来表示,@offset_size就是表示偏移位置占用的字节数。也就是说如果有两个offset,那么@offset_size值为8
@data.ptr.buffer:存放要发送或者接收到的数据;
@data.ptr.offsets:指向Binder偏移位置数组,该数组可以存在于data.buffer中,也可以在另外的内存空间中,并无限制。
之所以引入offsets_size和ptr.offsets这两个成员,是和Binder驱动的工作机制相关的。在Binder通信中,一个Binder实体可以发送给其他进程从而建立许多跨进程的引用;另外这些引用也可以在进程之间传递,就像java里面将一个引用赋值给另外一个引用一样。为Binder在不同进程中建立引用必须有驱动的参与,由驱动在内核创建并注册相关的数据结构后接收方才能使用该引用。而且这些引用可以是强类型,需要驱动为其维护引用计数。然而这些跨进成传递的Binder实体或引用保存在应用程序的数据包里,数据格式由用户定义。因此需要通过一种方法通知驱动,否则驱动无法从数据中提取Binder实体或引用。于是就使用数组data.ptr.offsets存放数据中每个Binder相对data.buffer的偏移量,用offsets_size表示这个数组的大小。驱动在转发数据包时会根据data.offset和offset_size将data.ptr.buffer中的Binder实体和Binder引用找出来,做相应的处理。
binder_write_read
- struct binder_write_read {
- signed long write_size; /* bytes to write */
- signed long write_consumed; /* bytes consumed by driver */
- unsigned long write_buffer;
- signed long read_size; /* bytes to read */
- signed long read_consumed; /* bytes consumed by driver */
- unsigned long read_buffer;
- };
@write_size @write_consumed @write_buffer仅当这是个请求命令时有效
@read_size @read_consumed @read_buffer仅当读(返回操作结果)时有效
@write_buffer包含了一系列请求 线程执行的Binder命令
@write_size 表示写入的数据大小
@write_consumed 表示被消耗的写数据的大小
@read_buffer包含了一系列线程执行后填充的返回值
@read_size表示读取数据的大小
@read_consumed表示被消耗的读数据的大小
binder_proc
binder_proc结构体用于保存调用Binder的各个进程或者线程的信息,每当线程或者进程调用binder_open时都会创建一个新的proc结构
- 282 struct binder_proc {
- 283 struct hlist_node proc_node;
- 284 struct rb_root threads;
- 285 struct rb_root nodes;
- 286 struct rb_root refs_by_desc;
- 287 struct rb_root refs_by_node;
- 288 int pid;
- 289 struct vm_area_struct *vma;
- 290 struct task_struct *tsk;
- 291 struct files_struct *files;
- 292 struct hlist_node deferred_work_node;
- 293 int deferred_work;
- 294 void *buffer;
- 295 ptrdiff_t user_buffer_offset;
- 296
- 297 struct list_head buffers;
- 298 struct rb_root free_buffers;
- 299 struct rb_root allocated_buffers;
- 300 size_t free_async_space;
- 301
- 302 struct page **pages;
- 303 size_t buffer_size;
- 304 uint32_t buffer_free;
- 305 struct list_head todo;
- 306 wait_queue_head_t wait;
- 307 struct binder_stats stats;
- 308 struct list_head delivered_death;
- 309 int max_threads;
- 310 int requested_threads;
- 311 int requested_threads_started;
- 312 int ready_threads;
- 313 long default_priority;
- 314 struct dentry *debugfs_entry;
- 315 };
@proc_node:双向链表,所有的proc都通过这个成员链接在一起。
@threads:和这个进程相关的线程都在这棵树下
@nodes:每个进程都维护一棵红黑树,以Binder实体(binder_node)的用户空间指针作为索引。这样驱动可以通过Binder实体在用户空间的地址找到Binder实体在kernel空间的表示binder_node
@refs_by_desc:每个进程都维护一棵红黑树,以Binder ref的desc作为索引,管理这个进程的所有binder索引
@refs_by_node:每个进程都维护一棵红黑树,进程所有的binder引用,以对应的Binder实体在驱动中的内存地址为索引填入该树中
@pid:该进程的group pid
@vma:
@tsk:这个线程的task_struct结构
@files:这个结构是当前进程的打开文件表结构,在处理文件类型Binder时会用到这个结构,在下面会详细描述文件类型binder
@deffer_work_node:
@deffer_work:
@buffer:是内核为了mmap映射在kernel保留的一块内核地址空间,以便应用层地址和kernel地址能指向同一块物理内存,这样在应用层和内核之间就可以共享同一块内存。
@user_buffer_offset:是user映射地址和kernel 地址之间的偏移量,通过这个值就可以从user地址推算出相应的kernel地址,反之也可以推算出user地址。
@buffers
Binder_thread
binder_thread结构体用于存储每一个单独的线程的信息
- 326 struct binder_thread {
- 327 struct binder_proc *proc;
- 328 struct rb_node rb_node;
- 329 int pid;
- 330 int looper;
- 331 struct binder_transaction *transaction_stack;
- 332 struct list_head todo;
- 333 uint32_t return_error; /* Write failed, return error code in read buf */
- 334 uint32_t return_error2; /* Write failed, return error code in read */
- 335 /* buffer. Used when sending a reply to a dead process that */
- 336 /* we are also waiting on */
- 337 wait_queue_head_t wait;
- 338 struct binder_stats stats;
- 339 };
@proc字段表示当前线程属于哪一个Binder进程
@pid表示binder thread的pic
@looper 表示当前线程的状态
@transaction_stack表示要接收和发送的线程信息,其结构体为binder_transaction
@stats 用来表示Binder状态信息。
Binder 对象
Binder对象在驱动中分为两类:Binder实体,Binder引用
驱动是Binder驱动的核心,系统中所有的Binder实体以及每个实体在各个进程中的引用都登记在驱动中;驱动需要记录Binder引用和Binder实体之间的多对一关系;通过Binder引用找到对应的Binder实体;在某个进程中创建Binder实体,查找或者创建对应的Binder引用;记录Binder实体和Binder引用的归属。
驱动里的Binder是什么时候创建的呢?为了实现Binder的实名注册,系统为serverManager创建了实名注册Binder实体:binder_context_mgr_node。驱动将所有进程的0号引用都预留给了这个Binder实体,也就是说所有进程的0号Binder引用都指向了binder_context_mgr_node。接着随着应用程序(包括client和server)不断的访问实名Binder,则这个Binder_context_mgr_node的引用不断的被创建出来。而随着Server向ServerManager注册Binder,则越来越多的Binder实体被创建出来,Client向ServerManager请求实名服务,则会创建Binder实体的Binder引用。当然这个创建过程对Application来说是透明的。
binder_node
驱动中Binder实体的表示,也成为节点,隶属于提供Binder实体的进程,比如binder_context_mgr_node就隶属于ServiceManager进程。
- 218 struct binder_node {
- 219 int debug_id;
- 220 struct binder_work work;
- 221 union {
- 222 struct rb_node rb_node;
- 223 struct hlist_node dead_node;
- 224 };
- 225 struct binder_proc *proc;
- 226 struct hlist_head refs;
- 227 int internal_strong_refs;
- 228 int local_weak_refs;
- 229 int local_strong_refs;
- 230 void __user *ptr;
- 231 void __user *cookie;
- 232 unsigned has_strong_ref:1;
- 233 unsigned pending_strong_ref:1;
- 234 unsigned has_weak_ref:1;
- 235 unsigned pending_weak_ref:1;
- 236 unsigned has_async_transaction:1;
- 237 unsigned accept_fds:1;
- 238 unsigned min_priority:8;
- 239 struct list_head async_todo;
- 240 };
@debug_id 用于调试目的,和ref的debug_id共用一个整数空间
@work
@rb_node 每个进程都维护一棵红黑树,以Binder实体在用户空间的指针,即本结构的ptr成员为索引存放该进程所有的Binder实体。这样驱动可以根据Binder实体在用户空间的指针很快找到其位于内核的节点。rb_node用于将本节点链入该红黑树中。
@dead_node 销毁时必须将rb_node从红黑树中摘除,如果本节点还有引用切断,就用dead_node将节点隔离到另外一个链表中,直到通知所有进程切断该节点的引用后,该节点才可能被销毁。
@proc 本成员指向节点所属的进程,即提供该节点的进程。
@refs 本成员是队列头,所有指向本节点的引用都连接到该队列里,这些引用可能属于不同的进程。通过该对列可以遍历指向该节点的所有引用。
@internal_strong_refs 用来实现强指针的计数器:产生一个指向本节点的强引用,该计数器则加1
@local_weak_refs 驱动为传输中的Binder设置的弱引用计数器。如果一个Binder打包在数据包中从一个进程发送到另外一个进程,驱动会为该Binder增加引用计数,知道接收进程通过BC_FREE_BUFFER通知驱动释放该数据包的数据区为止。
@local_strong_refs 驱动为传输中的Binder设置的强引用计数,同上
@ptr 指向用户空间Binder实体的指针,来自于flat_binder_object的binder成员。
@cookie 指向用户空间的附加指针,来自于flat_binder_object的cookie成员
@has_strong_ref, @pending_strong_ref, @has_weak_ref,@pending_weak_ref :这一组标志用于控制驱动与Binder实体所在进程交互式修改引用计数。
每个进程都有一棵红黑树用于存放创建好的节点,以Binder在用户空间的指针作为索引,每当在传输数据中侦测到一个代表Binder实体的flat_binder_object,先以该结构的binder指针为索引搜索红黑树;如果没有找到就创建一个新节点添加到树中。对于同一个进程来说,内存地址是惟一的,所以不会重复建设造成混乱。
binder_ref
和Binder实体一样,Binder的引用也是驱动根据传输数据的flat_binder_object创建的,隶属于获得该引用的进程。
- 247 struct binder_ref {
- 248 /* Lookups needed: */
- 249 /* node + proc => ref (transaction) */
- 250 /* desc + proc => ref (transaction, inc/dec ref) */
- 251 /* node => refs + procs (proc exit) */
- 252 int debug_id;
- 253 struct rb_node rb_node_desc;
- 254 struct rb_node rb_node_node;
- 255 struct hlist_node node_entry;
- 256 struct binder_proc *proc;
- 257 struct binder_node *node;
- 258 uint32_t desc;
- 259 int strong;
- 260 int weak;
- 261 struct binder_ref_death *death;
- 262 };
@debug_id 调试用id,和binder_node的debug_id共用整数空间。
@rb_node_desc 每个进程有一棵红黑树,进程所有引用以引用号为索引填入该树中。本成员用做连接到该树的一个节点。
@rb_node_node:每个进程又有一棵红黑树,进程所有引用以节点实体在驱动中的内存地址为索引填入该树中,本成员用做连接到该树的一个节点。
@node_entry:该域将本引用作为节点链入所指向的Binder实体结构binder_node中的refs队列
@proc:本引用所述的进程
@node:本引用所指向的节点(Binder实体)
@desc:本结构的引用号
@strong:强引用计数
@weak:弱引用计数
就像一个对象有很多指针一样,同一个Binder实体可能有很多引用,不同的是这些引用可能分布在不同的进程中。和实体一样,每个进程使用红黑树存放所有进程正在使用的引用。但Binder引用可以通过两个键值索引:
所对应实体的内核地址:
注意这里使用的是驱动创建于内核中的binder_node结构的地址,而不是Binder实体在用户进程中的地址。实体在内核中的地址是惟一的,用做索引不会产生二义性;实体可能来自不同的用户进程,来自不同进程的实体地址可能相同,因此不能使用实体用户地址做索引。驱动利用该红黑树在一个进程中快速查找某个Binder实体所对应的引用(一个实体在一个应用中只建立一个索引)
引用号
引用号是驱动为引用分配的一个32位标始,在一个进程内是惟一的,而在不同的进程内可能有相同的值,这有点类似打开文件号。每个进程的打开文件号是可能重复的。引用号是要返回给应用程序的,可以看作是Binder引用在用户进程中的句柄。除了0号引用在所有进程中都保留给SMgr,其他的值由驱动在创建引用时动态分配。向Binder发送数据包时,应用程序通过将引用号填入binder_trasaction_data结构的target.handle域来表明该数据包的目的Binder。驱动根据该引用号在红黑树中找到引用的的binder_ref结构,进而通过其node域知道目标Binder实体所在的进程及其它相关信息,实现数据包的路由。