binder_node
结构体binder_node用来描述一个Binder实体对象。每一个Service组件在Binder驱动程序中都对应有一个Binder实体对象,用来描述它在内核中的状态。Binder驱动程序通过强引用计数和弱引用计数技术来维护它们的生命周期。
binder_proc
结构体binder_proc用来描述一个正在使用Binder进程间通信机制的进程。当一个进程调用函数open来打开设备文件/dev/binder时,Binder驱动程序就会为它创建一个binder_proc结构体,并且将它保存在一个全局的hash列表中
proc_node :hash列表中的当前节点。
delivered_death : 当一个进程所引用的Service组件死亡时,Binder驱动程序就会向该进程发送一个死亡通知。这个正在发出的死亡通知被封装成一个类型为BINDER_WORK_DEAD_BINDER或者BINDER_WORK_DEAD_BINDER_AND_CLEAR的工作项,并且保存在由成员变量delivered_death所描述的一个队列中,表示Binder驱动程序正在向进程发送的死亡通知。当进程接收到这个死亡通知之后,它便会通知Binder驱动程序,这时候Binder驱动程序就会将对应的工作项从成员变量delivered_death所描述的队列中删除。
stats : 进程binder通信统计数据
pid: 进程组id
task: 进程的任务控制块(linux的内容)
files:
default_priority:进程默认的优先级,当一个线程处理一个工作项时,它的线程优先级有可能会被设置为其宿主进程的优先级。
buffer_size ,buffer , vma ,user_buffer_offset , pages : 进程打开了设备文件/dev/binder之后,还必须调用函数mmap将它映射到进程的地址空间来,实际上是请求Binder驱动程序为它分配一块内核缓冲区,以便可以用来在进程间传输数据。Binder驱动程序为进程分配的内核缓冲区的大小保存在成员变量buffer_size中。这些内核缓冲区有两个地址,其中一个是内核空间地址,另外一个是用户空间地址。内核空间地址是在Binder驱动程序内部使用的,保存在成员变量buffer中,而用户空间地址是在应用程序进程内部使用的,保存在成员变量vma中。这两个地址相差一个固定的值,保存在成员变量user_buffer_offset中。这样,给定一个用户空间地址或者一个内核空间地址,Binder驱动程序就可以计算出另外一个地址的大小。
注意:这两个地址指的都是虚拟地址,它们对应的物理页面保存在成员变量pages中。成员变量pages是类型为struct page*的一个数组,数组中的每一个元素都指向一个物理页面。Binder驱动程序一开始时只为该内核缓冲区分配一个物理页面,后面不够使用时,再继续分配。
-------------------------------------------
buffers , allocated_buffers,free_buffers,buffer_free,free_async_space : 成员变量buffer指向的是一块大的内核缓冲区,Binder驱动程序为了方便对它进行管理,会将它划分成若干个小块。这些小块的内核缓冲区就是使用结构体binder_buffer来描述,它们保存在一个列表中,按照地址值从小到大的顺序来排列。成员变量buffers指向的便是该列表的头部。列表中的小块内核缓冲区有的是正在使用的,即已经分配了物理页面;有的是空闲的,即还没有分配物理页面,它们分别组织在两个红黑树中,其中,前者保存在成员变量allocated_buffers所描述的红黑树中,而后者保存在成员变量free_buffers所描述的红黑树中。此外,成员变量buffer_free保存了空闲内核缓冲区的大小,而成员变量free_async_space保存了当前可以用来保存异步事务数据的内核缓冲区的大小。
-------------------------------------------
threads, max_threads,ready_threads,requested_threads,requested_threads_started : 每一个使用了Binder进程间通信机制的进程都有一个Binder线程池,用来处理进程间通信请求,这个Binder线程池是由Binder驱动程序来维护的。结构体binder_proc的成员变量threads是一个红黑树的根节点,它以线程ID作为关键字来组织一个进程的Binder线程池。进程可以调用函数ioctl将一个线程注册到Binder驱动程序中,同时,当进程没有足够的空闲线程在处理进程间通信请求时,Binder驱动程序也可以主动要求进程注册更多的线程到Binder线程池中。Binder驱动程序最多可以主动请求进程注册的线程的数量保存在成员变量max_threads中,而成员变量ready_threads表示进程当前的空闲Binder线程数目。
注意:成员变量max_threads并不是表示Binder线程池中的最大线程数目,进程本身可以主动注册任意数目的线程到Binder线程池中。Binder驱动程序每一次主动请求进程注册一个线程时,都会将成员变量requested_threads的值加1;而当进程响应这个请求之后,Binder驱动程序就会将成员变量requested_threads的值减1,而且将成员变量requested_threads_started的值加1,表示Binder驱动程序已经主动请求进程注册了多少个线程到Binder线程池中。
-------------------------------------------
todo :当进程接收到一个进程间通信请求时,Binder驱动程序就将该请求封装成一个工作项,并且加入到进程的待处理工作项队列中,这个队列使用成员变量todo来描述。
wait :Binder线程池中的空闲Binder线程会睡眠在由成员变量wait所描述的一个等待队列中,当它们的宿主进程的待处理工作项队列增加了新的工作项之后,Binder驱动程序就会唤醒这些线程,以便它们可以去处理新的工作项。
---------------------------------------------
nodes ,refs_by_desc, refs_by_node :一个进程内部包含了一系列的Binder实体对象(结构体binder_node)和Binder引用对象(结构体binder_ref),进程使用三个红黑树来组织它们,其中,成员变量nodes所描述的红黑树是用来组织Binder实体对象的,它以Binder实体对象的成员变量ptr作为关键字;而成员变量refs_by_desc和refs_by_node所描述的红黑树是用来组织Binder引用对象的,前者以Binder引用对象的成员变量desc作为关键字,而后者以Binder引用对象的成员变量node作为关键字。
---------------------------------------------
成员变量deferred_work_node是一个hash列表,用来保存进程可以延迟执行的工作项。这些延迟工作项有三种类型,见:binder_deferred_state。如果一个进程有延迟执行的工作项,那么成员变量deferred_work_node就刚好是该hash列表中的一个节点,并且使用成员变量deferred_work来描述该延迟工作项的具体类型。
struct binder_proc {
struct hlist_node proc_node;
struct rb_root threads;
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
int pid;
struct vm_area_struct *vma;
struct mm_struct *vma_vm_mm;
struct task_struct *tsk;
struct files_struct *files;
struct hlist_node deferred_work_node;
int deferred_work;
void *buffer;
ptrdiff_t user_buffer_offset;
struct list_head buffers;
struct rb_root free_buffers;
struct rb_root allocated_buffers;
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;
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;
int requested_threads;
int requested_threads_started;
int ready_threads;
long default_priority;
struct dentry *debugfs_entry;
};
binder_deferred_state
enum binder_deferred_state {
BINDER_DEFERRED_PUT_FILES = 0x01,
BINDER_DEFERRED_FLUSH = 0x02,
BINDER_DEFERRED_RELEASE = 0x04,
};
Binder驱动程序为进程分配内核缓冲区时,会为这个内核缓冲区创建一个文件描述符,进程可以通过这个文件描述符将该内核缓冲区映射到自己的地址空间。当进程不再需要使用Binder进程间通信机制时,它就会通知Binder驱动程序关闭该文件描述符,并且释放之前所分配的内核缓冲区。由于这不是一个马上就需要完成的操作,因此,Binder驱动程序就会创建一个BINDER_DEFERRED_PUT_FILES类型的工作项来延迟执行该操作。
前面提到,Binder线程池中的空闲Binder线程是睡眠在一个等待队列中的,进程可以通过调用函数flush来唤醒这些线程,以便它们可以检查进程是否有新的工作项需要处理。这时候Binder驱动程序就会创建一个BINDER_DEFERRED_FLUSH类型的工作项,以便可以延迟执行唤醒空闲Binder线程的操作。
当进程不再使用Binder进程间通信机制时,它就会调用函数close来关闭设备文件/dev/binder,这时候Binder驱动程序就会释放之前为它分配的资源,例如,释放进程结构体binder_proc、Binder实体对象结构体binder_node以及Binder引用对象结构体binder_ref等。由于资源的释放操作是一个比较耗时的操作,因此,Binder驱动程序会创建一个BINDER_DEFERRED_RELEASE类型的事务来延迟执行它们。
binder_buffer
结构体binder_buffer用来描述一个内核缓冲区,它是用来在进程间传输数据的。
entry :每一个使用Binder进程间通信机制的进程在Binder驱动程序中都有一个内核缓冲区列表,用来保存Binder驱动程序为它所分配的内核缓冲区,而成员变量entry正好是这个内核缓冲区列表的一个节点。
free , rb_node : 进程又使用了两个红黑树来分别保存那些正在使用的内核缓冲区,以及空闲的内核缓冲区。如果一个内核缓冲区是空闲的,即它的成员变量free的值等于1,那么成员变量rb_node就是空闲内核缓冲区红黑树中的一个节点;否则,成员变量rb_node就是正在使用内核缓冲区红黑树中的一个节点。
transaction , target_node : 成员变量transaction 和 target_node用来描述一个内核缓冲区正在交给哪一个事务以及哪一个Binder实体对象使用。
allow_user_free :是否允许释放缓冲区,见下文
async_transaction :如果与一个内核缓冲区关联的是一个异步事务,那么Binder驱动程序就会将该内核缓冲区的成员变量async_transaction的值设置为1;否则,就将它的值设置为0。Binder驱动程序限制了分配给异步事务的内核缓冲区的大小,这样做的目的是为了保证同步事务可以优先得到内核缓冲区,以便可以快速地对该同步事务进行处理。
data , offsets_size , data_size : 成员变量data指向一块大小可变的数据缓冲区,它是真正用来保存通信数据的。数据缓冲区保存的数据划分为两种类型,其中一种是普通数据,另一种是Binder对象。Binder驱动程序不关心数据缓冲区中的普通数据,但是必须要知道里面的Binder对象,因为它需要根据它们来维护内核中的Binder实体对象和Binder引用对象的生命周期。例如,如果数据缓冲区中包含了一个Binder引用,并且该数据缓冲区是传递给另外一个进程的,那么Binder驱动程序就需要为另外一个进程创建一个Binder引用对象,并且增加相应的Binder实体对象的引用计数,因为它也被另外的这个进程引用了。由于数据缓冲区中的普通数据和Binder对象是混合在一起保存的,它们之间并没有固定的顺序,因此,Binder驱动程序就需要额外的数据来找到里面的Binder对象。在数据缓冲区的后面,有一个偏移数组,它记录了数据缓冲区中每一个Binder对象在数据缓冲区中的位置。偏移数组的大小保存在成员变量offsets_size中,而数据缓冲区的大小保存在成员变量data_size中。
debug_id : 最后,成员变量debug_id用来标志一个内核缓冲区的身份,它是用来帮助调试Binder驱动程序的。
struct binder_buffer {
struct list_head entry; /* free and allocated entries by address */
struct rb_node rb_node; /* free entry by size or allocated entry */
/* by address */
unsigned free:1;
unsigned allow_user_free:1;
unsigned async_transaction:1;
unsigned debug_id:29;
struct binder_transaction *transaction;
struct binder_node *target_node;
size_t data_size;
size_t offsets_size;
uint8_t data[0];
};
Binder驱动程序使用一个binder_transaction结构体来描述一个事务,每一个事务都关联有一个目标Binder实体对象。Binder驱动程序将事务数据保存在一个内核缓冲区中,然后将它交给目标Binder实体对象处理,而目标Binder实体对象再将该内核缓冲区的内容交给相应的Service组件处理。Service组件处理完成该事务之后,如果发现传递给它的内核缓冲区的成员变量allow_user_free的值为1,那么该Service组件就会请求Binder驱动程序释放该内核缓冲区。
binder_driver_command_protocol
从server进程和client进程传递给binder驱动程序的命令码:
enum binder_driver_command_protocol {
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
/*
* binder_transaction_data: the sent command.
*/
BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
/*
* not currently supported
* int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
* Else you have acquired a primary reference on the object.
*/
BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
/*
* void *: ptr to transaction data received on a read
*/
BC_INCREFS = _IOW('c', 4, __u32),
BC_ACQUIRE = _IOW('c', 5, __u32),
BC_RELEASE = _IOW('c', 6, __u32),
BC_DECREFS = _IOW('c', 7, __u32),
/*
* int: descriptor
*/
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
/*
* not currently supported
* int: priority
* int: descriptor
*/
BC_REGISTER_LOOPER = _IO('c', 11),
/*
* No parameters.
* Register a spawned looper thread with the device.
*/
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
/*
* No parameters.
* These two commands are sent as an application-level thread
* enters and exits the binder loop, respectively. They are
* used so the binder can have an accurate count of the number
* of looping threads it has available.
*/
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14,
struct binder_handle_cookie),
/*
* int: handle
* void *: cookie
*/
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15,
struct binder_handle_cookie),
/*
* int: handle
* void *: cookie
*/
BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
/*
* void *: cookie
*/
};
BC_TRANSACTION ,BC_REPLY : 命令协议代码BC_TRANSACTION和BC_REPLY后面跟的通信数据使用一个结构体binder_transaction_data来描述。当一个进程请求另外一个进程执行某一个操作时,源进程就使用命令协议代码BC_TRANSACTION来请求Binder驱动程序将通信数据传递到目标进程;当目标进程处理完成源进程所请求的操作之后,它就使用命令协议代码BC_REPLY来请求Binder驱动程序将结果数据传递给源进程。
BC_FREE_BUFFER : 命令协议代码BC_FREE_BUFFER后面跟的通信数据是一个整数,它指向了在Binder驱动程序内部所分配的一块内核缓冲区。Binder驱动程序通过内核缓冲区将源进程的通信数据传递到目标进程的。当目标进程处理完成源进程的通信请求之后,它就会使用命令协议代码BC_FREE_BUFFER来通知Binder驱动程序释放这个内核缓冲区。
BC_INCREFS、BC_ACQUIRE、BC_RELEASE和BC_DECREFS : 通信数据是一个整数,它描述了一个Binder引用对象的句柄值,其中,命令协议代码BC_INCREFS和BC_DECREFS分别用来增加和减少一个Binder引用对象的弱引用计数;而命令协议代码BC_ACQUIRE和BC_RELEASE分别用来增加和减少一个Binder引用对象的强引用计数。
BC_INCREFS_DONE和BC_ACQUIRE_DONE :命令协议代码BC_INCREFS_DONE和BC_ACQUIRE_DONE后面跟的通信数据使用一个结构体binder_ptr_cookie来描述。Binder驱动程序第一次增加一个Binder实体对象的强引用计数或者弱引用计数时,就会使用返回协议代码BR_ACQUIRE或者BR_INCREFS来请求对应的Server进程增加对应的Service组件的强引用计数或者弱引用计数。当Server进程处理完成这两个请求之后,就会分别使用命令协议代码BC_INCREFS_DONE和BC_ACQUIRE_DONE将操作结果返回给Binder驱动程序。
命令协议代码BC_REGISTER_LOOPER、BC_ENTER_LOOPER和BC_EXIT_LOOPER后面不需要指定通信数据。一方面,当一个线程将自己注册到Binder驱动程序之后,它接着就会使用命令协议代码BC_ENTER_LOOPER来通知Binder驱动程序,它已经准备就绪处理进程间通信请求了;另一方面,当Binder驱动程序主动请求进程注册一个新的线程到它的Binder线程池中来处理进程间通信请求之后,新创建的线程就会使用命令协议代码BC_REGISTER_LOOPER来通知Binder驱动程序,它准备就绪了。最后,当一个线程要退出时,它就使用命令协议代码BC_EXIT_LOOPER从Binder驱动程序中注销,这样它就不会再接收到进程间通信请求了。
命令协议代码BC_REQUEST_DEATH_NOTIFICATION和BC_CLEAR_DEATH_NOTIFICATION后面跟的通信数据使用一个结构体binder_ptr_cookie来描述。一方面,如果一个进程希望获得它所引用的Service组件的死亡接收通知,那么它就需要使用命令协议代码BC_REQUEST_DEATH_NOTIFICATION来向Binder驱动程序注册一个死亡接收通知;另一方面,如果一个进程想注销之前所注册的一个死亡接收通知,那么它就需要使用命令协议代码BC_CLEAR_DEATH_NOTIFICATION来向Binder驱动程序发出请求。
命令协议代码BC_DEAD_BINDER_DONE后面跟的通信数据是一个void类型的指针,指向一个死亡接收通知结构体binder_ref_death的地址。当一个进程获得一个Service组件的死亡通知时,它就会使用命令协议代码BC_DEAD_BINDER_DONE来通知Binder驱动程序,它已经处理完成该Service组件的死亡通知了。
binder_driver_return_protocol
从binder驱动程序传递给server进程和client进程的命令码:
enum binder_driver_return_protocol {
BR_ERROR = _IOR('r', 0, __s32),
/*
* int: error code
*/
BR_OK = _IO('r', 1),
/* No parameters! */
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
/*
* binder_transaction_data: the received command.
*/
BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
/*
* not currently supported
* int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
* Else the remote object has acquired a primary reference.
*/
BR_DEAD_REPLY = _IO('r', 5),
/*
* The target of the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
*/
BR_TRANSACTION_COMPLETE = _IO('r', 6),
/*
* No parameters... always refers to the last transaction requested
* (including replies). Note that this will be sent even for
* asynchronous transactions.
*/
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
/*
* void *: ptr to binder
* void *: cookie for binder
*/
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
/*
* not currently supported
* int: priority
* void *: ptr to binder
* void *: cookie for binder
*/
BR_NOOP = _IO('r', 12),
/*
* No parameters. Do nothing and examine the next command. It exists
* primarily so that we can replace it with a BR_SPAWN_LOOPER command.
*/
BR_SPAWN_LOOPER = _IO('r', 13),
/*
* No parameters. The driver has determined that a process has no
* threads waiting to service incoming transactions. When a process
* receives this command, it must spawn a new service thread and
* register it via bcENTER_LOOPER.
*/
BR_FINISHED = _IO('r', 14),
/*
* not currently supported
* stop threadpool thread
*/
BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
/*
* void *: cookie
*/
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
/*
* void *: cookie
*/
BR_FAILED_REPLY = _IO('r', 17),
/*
* The the last transaction (either a bcTRANSACTION or
* a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
*/
};
BR_ERROR : 返回协议代码BR_ERROR后面跟的通信数据是一个整数,用来描述一个错误代码。Binder驱动程序在处理应用程序进程发出的某个请求时,如果发生了异常情况,它就会使用返回协议代码BR_ERROR来通知应用程序进程。
BR_OK :返回协议代码BR_OK后面不需要指定通信数据。Binder驱动程序成功处理了应用程序进程发出的某一个请求之后,它就会使用返回协议代码BR_OK来通知应用程序进程。
BR_TRANSACTION,BR_REPLY :返回协议代码BR_TRANSACTION和BR_REPLY后面跟的通信数据使用一个结构体binder_transaction_data来描述。当一个Client进程向一个Server进程发出进程间通信请求时,Binder驱动程序就会使用返回协议代码BR_TRANSACTION通知该Server进程来处理该进程间通信请求;当Server进程处理完成该进程间通信请求之后,Binder驱动程序就会使用返回协议代码BR_REPLY将进程间通信请求结果数据返回给Client进程。
BR_DEAD_REPLY :返回协议代码BR_DEAD_REPLY后面不需要指定通信数据。Binder驱动程序在处理进程间通信请求时,如果发现目标进程或者目标线程已经死亡,它就会使用返回协议代码BR_DEAD_REPLY来通知源进程。
BR_TRANSACTION_COMPLETE :返回协议代码BR_TRANSACTION_COMPLETE后面不需要指定通信数据。当Binder驱动程序接收到应用程序进程给它发送的一个命令协议代码BC_TRANSACTION或者BC_REPLY时,它就会使用返回协议代码BR_TRANSACTION_COMPLETE来通知应用程序进程,该命令协议代码已经被接收,正在分发给目标进程或者目标线程处理。
BR_INCREFS、BR_ACQUIRE、BR_RELEASE和BR_DECREFS :返回协议代码BR_INCREFS、BR_ACQUIRE、BR_RELEASE和BR_DECREFS后面跟的通信数据使用一个结构体binder_ptr_cookie来描述,其中,命令协议代码BR_INCREFS和BR_DECREFS分别用来增加和减少一个Service组件的弱引用计数;而命令协议代码BR_ACQUIRE和BR_RELEASE分别用来增加和减少一个Service组件的强引用计数。
BR_NOOP :返回协议代码BR_NOOP后面不需要指定通信数据。Binder驱动程序使用返回协议代码BR_NOOP来通知应用程序进程执行一个空操作,它的存在是为了方便以后可以替换为返回协议代码BR_SPAWN_LOOPER。
BR_SPAWN_LOOPER:返回协议代码BR_SPAWN_LOOPER后面不需要指定通信数据。当Binder驱动程序发现一个进程没有足够的空闲Binder线程来处理进程间通信请求时,它就会使用返回协议代码BR_SPAWN_LOOPER来通知该进程增加一个新的线程到Binder线程池中。
BR_DEAD_BINDER和BR_CLEAR_DEATH_NOTIFICATION_DONE :返回协议代码BR_DEAD_BINDER和BR_CLEAR_DEATH_NOTIFICATION_DONE后面跟的通信数据是一个void类型的指针,它指向一个用来接收Service组件死亡通知的对象的地址。当Binder驱动程序监测到一个Service组件的死亡事件时,它就会使用返回协议代码BR_DEAD_BINDER来通知相应的Client进程。当Client进程通知Binder驱动程序注销它之前所注册的一个死亡接收通知时,Binder驱动程序执行完成这个注销操作之后,就会使用返回协议代码BR_CLEAR_DEATH_NOTIFICATION_DONE来通知Client进程。
BR_FAILED_REPLY :返回协议代码BR_FAILED_REPLY后面不需要指定通信数据。当Binder驱动程序处理一个进程发出的BC_TRANSACTION命令协议时,如果发生了异常情况,它就会使用返回协议代码BR_FAILED_REPLY来通知源进程。
binder_ptr_cookie
struct binder_ptr_cookie {
binder_uintptr_t ptr;
binder_uintptr_t cookie;
};
当结构体binder_ptr_cookie描述的是一个Binder实体对象时,成员变量ptr和cookie的含义等同于结构体binder_node的成员变量ptr和cookie,它们用来描述用户空间中的一个Service组件,其中,成员变量cookie指向该Service组件的地址,而成员变量ptr指向该Service组件内部的一个引用计数对象(类型为weakref_impl)的地址;
当结构体binder_ptr_cookie描述的是一个Service组件的死亡接收通知时,成员变量ptr指向的是一个Binder引用对象的句柄值,而成员变量cookie指向的是一个用来接收死亡通知的对象的地址。
binder_transaction_data
结构体binder_transaction_data用来描述进程间通信过程中所传输的数据。
struct binder_transaction_data {
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
/* target descriptor of command transaction */
__u32 handle;
/* target descriptor of return transaction */
binder_uintptr_t ptr;
} target;
binder_uintptr_t cookie; /* target object cookie */
__u32 code; /* transaction command */
/* General information about the transaction. */
__u32 flags;
pid_t sender_pid;
uid_t sender_euid;
binder_size_t data_size; /* number of bytes of data */
binder_size_t offsets_size; /* number of bytes of offsets */
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
binder_uintptr_t buffer;
/* offsets from buffer to flat_binder_object structs */
binder_uintptr_t offsets;
} ptr;
__u8 buf[8];
} data;
};
target : 成员变量target是一个联合体,用来描述一个目标Binder实体对象或者目标Binder引用对象。如果它描述的是一个目标Binder实体对象,那么它的成员变量ptr就指向与该Binder实体对象对应的一个Service组件内部的一个弱引用计数对象(weakref_impl)的地址;如果它描述的是一个目标Binder引用对象,那么它的成员变量handle就指向该Binder引用对象的句柄值。
cookie : 当Binder驱动程序使用返回命令协议BR_TRANSACTION向一个Server进程发出一个进程间通信请求时,cookie成员变量才有实际意义,它指向的是目标Service组件的地址。
code : 成员变量code是由执行进程间通信的两个进程互相约定好的一个通信代码,Binder驱动程序完全不关心它的含义。
成员变量flags是一个标志值,用来描述进程间通信行为特征,它的取值如下所示
enum transaction_flags {
TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
};
目前,只使用了TF_ONE_WAY、TF_STATUS_CODE和TF_ACCEPT_FDS这三个标志值。如果成员变量flags的TF_ONE_WAY位被设置为1,就表示这是一个异步的进程间通信过程;如果成员变量flags的TF_ACCEPT_FDS位被设置为0,就表示源进程不允许目标进程返回的结果数据中包含有文件描述符;如果成员变量flags的TF_STATUS_CODE位被设置为1,就表示成员变量data所描述的数据缓冲区的内容是一个4字节的状态码。
sender_pid和sender_euid : 成员变量sender_pid和sender_euid表示发起进程间通信请求的进程的PID和UID。这两个成员变量的值是由Binder驱动程序来填写的,因此,目标进程通过这两个成员变量就可以识别出源进程的身份,以便进行安全检查。
成员变量data_size和offsets_size分别用来描述一个通信数据缓冲区以及一个偏移数组的大小。成员变量data是一个联合体,它指向一个通信数据缓冲区。当通信数据较小时,就直接使用联合体内静态分配的数组buf来传输数据;当通信数据较大时,就需要使用一块动态分配的缓冲区来传输数据了。这块动态分配的缓冲区通过一个包含两个指针的结构体来描述,即通过联合体内的成员变量ptr来描述。结构体ptr的成员变量buffer指向一个数据缓冲区,它是真正用来保存通信数据的,它的大小由前面所描述的成员变量data_size来指定。当数据缓冲区中包含有Binder对象时,那么紧跟在这个数据缓冲区的后面就会有一个偏移数组offsets,用来描述数据缓冲区中每一个Binder对象的位置。有了这个偏移数组之后,Binder驱动程序就可以正确地维护其内部的Binder实体对象和Binder引用对象的引用计数。
数据缓冲区中的每一个Binder对象都使用一个flat_binder_object结构体来描述。
比如上面,data.ptr.buffer指向一块data_size大小的空间,包含两个binder对象,offset值分别是n1和n2。
flat_binder_object
用来描述binder_transaction_data中传输数据是用到的binder对象,可以使Binder引用对象,或者binder实体对象,也可以是一个文件描述符,它们是通过成员变量type来加以区别的。
#define B_PACK_CHARS(c1, c2, c3, c4) \
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
__u32 type;
__u32 flags;
/* 8 bytes of data. */
union {
binder_uintptr_t binder; /* local object */
__u32 handle; /* remote object */
};
/* extra data associated with local object */
binder_uintptr_t cookie;
};
BINDER_TYPE_BINDER和BINDER_TYPE_WEAK_BINDER都是用来描述一个Binder实体对象的,前者描述的是一个强类型的Binder实体对象,而后者描述的是一个弱类型的Binder实体对象。
BINDER_TYPE_HANDLE和BINDER_TYPE_WEAK_HANDLE用来描述一个Binder引用对象,前者描述的是一个强类型的Binder引用对象,而后者描述的是一个弱类型的Binder引用对象 。
BINDER_TYPE_FD用来描述一个文件描述符。
成员变量flags是一个标志值,只有当结构体flat_binder_object描述的是一个Binder实体对象时,它才有实际意义。目前只用到该成员变量的第0位到第8位。其中,第0位到第7位描述的是一个Binder实体对象在处理一个进程间通信请求时,它所运行在的线程应当具有的最小线程优先级;第8位用来描述一个Binder实体对象是否可以将一块包含有文件描述符的数据缓冲区传输给目标进程,如果它的值等于1,就表示允许,否则就不允许。
成员变量binder和handle组成了一个联合体。当结构体flat_binder_object描述的是一个Binder实体对象时,那么就使用成员变量binder来指向与该Binder实体对象对应的一个Service组件内部的一个弱引用计数对象(weakref_impl)的地址,并且使用成员变量cookie来指向该Service组件的地址;当结构体flat_binder_object描述的是一个Binder引用对象时,那么就使用成员变量handle来描述该Binder引用对象的句柄值。