一、概述
Binder驱动是Android专用的,但底层的驱动架构与Linux驱动一样。binder驱动在以misc设备进行注册,作为虚拟字符设备,没有直接操作硬件,只是对设备内存的处理,主要是驱动设备的初始化(binder_init),打开(binder_open),映射(binder_mmap),数据操作(binder_ioctl)。
- 通过init(),创建/dev/binder设备节点
- 通过open(),获取Binder Driver的文件描述符
- 通过mmap(),在内核分配一块内存,用于存放数据
- 通过ioctl(),将IPC数据作为参数传递给Binder Driver
用户态的程序调用Kernel层驱动是需要陷入内核态,进行系统调用(syscall),比如打开Binder驱动方法的调用链是:open()->__open()->binder_open()。open()为用户空间的方法, _open()是系统调用中相应的处理方法,通过查找,对应调用到内核binder驱动的binder_open方法。
Client进程通过RPC(Remote Procedure Call Protocol)与Server通信,可以简单的分为三层,驱动层、IPC层、业务层。demo()是client和server共同协商好的统一方法,RPC数据、code、handle、协议这四项组成了IPC的层的数据,通过IPC层进行数据传输,而真正在Client和Server两端建立通信的基础设施是Binder Driver。
例如:当AMS的client向ServiceManger注册服务的过程中,IPC层的数据组成为:handle=0,RPC数据为AMS,code为ADD_SERVICE_TRANSACTION,binder协议为BC_TRANSACTION。
二、Binder核心方法
2.1 binder_init
[->android/binder.c]
1 | static int __init binder_init(void) |
主要工作是注册misc设备。
debugfs_create_file是指在debugfs文件系统中创建一个目录,返回值是指向dentry的指针。当kernel禁用debugfs的话,返回值是%ENODEV,默认是禁用的。如果需要打开,在目录kernel/arch/arm64/configs下找到defconfig文件下添加一行CONFIG_DEBUG_FS=y,即可开启debugfs。
2.1.1 init_binder_device
[->android/binder.c]
1 | static int __init init_binder_device(const char *name) |
2.2 binder_open
[->android/binder.c]
1 | static int binder_open(struct inode *nodp, struct file *filp) |
创建binder_proc对象,并把当前进程等信息保存到binder_proc对象,该对象管理IPC所需要的各种信息并拥有其他结构体的根结构体;再把binder_proc对象保存到文件指针filp中,并且把binder_proc加入到全局链表binder_procs。
Binder驱动中 HLIST_HEAD创建全局的哈希链表binder_procs,用于保存所有的binder_proc队列,每次新创建的binder_proc都会加入到binder_procs链表中。
2.3 binder_mmap
[->android/binder.c]
1 | static int binder_mmap(struct file *filp, struct vm_area_struct *vma) |
mmap的主要功能:首先在内核虚拟地址空间,申请一块与用户虚拟空间相同大小的内存,然后再申请一个page大小的物理内存,再将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟空间,从而实现了用户空间的buffer和内核空间的buffer同步操作的功能。
2.3.1 binder_alloc_mmap_handler
[->android/binder.c]
1 | int binder_alloc_mmap_handler(struct binder_alloc *alloc, |
binder_mmap通过加锁,保证一次只有一个进程分配内存,保证多进程间的并发访问。user_buffer_offset是虚拟进程地址与虚拟内核地址的差值,该值为负值。
2.4 binder_ioctl
[->android/binder.c]
1 | static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
2.4.1 binder_get_thread
[->android/binder.c]
1 | static struct binder_thread *binder_get_thread(struct binder_proc *proc) |
2.4.2 binder_ioctl_write_read
[->android/binder.c]
1 | static int binder_ioctl_write_read(struct file *filp, |
binder_ioctl_write_read主要流程如下:
1.把用户空间ubuf拷贝到内核空间bwr;
2.当bwr写缓存有数据,则执行binder_thread_write;当写失败时则将bwr数据写回到用户空间并退出;
3.当bwr读缓存有数据,则执行binder_thread_read;当读失败时则将bwr数据写回到用户空间并退出;
4.把内核数据bwr拷贝到用户空间ubuf。
binder_thread_write、binder_thread_read作为两个核心方法,在第三节中详细介绍。
2.5 小结
binder_init:初始化字符设备,注册misc设备;
binder_open:打开驱动设备,初始化binder_proc;
binder_mmap:申请内核空间,将用户空间和内核空间映射到同一块物理内存;
binder_ioctl:执行相应的ioctl操作,主要进行读写操作。
下面看下binder通信的具体协议。
三、Binder通信协议
3.1 通信模型
一次完整的Binder通信过程如下(非oneway):
Binder协议包含在IPC数据中,分为两类:
1.BINDER_COMMAND_PROTOCOL:binder请求码,以BC_开头,简称BC码,用于从IPC层传递到Binder Driver层;
2.BINDER_RETURN_PROTOCOL:binder响应码,以BR_开头,简称BR码,用于从Binder Driver层传递到IPC层。
Binder IPC通信至少是两个进程的交互
client进程执行binder_thread_write,根据BC_xx命令,生成相应的binder_work;
server进程执行binder_thread_read,根据binder_work_type类型,生成BR_xx,发送到用户空间处理。
3.2 binder_thread_write
请求过程是通过binder_thread_write方法,该方法用于处理Binder协议中的请求码,当binder_buffer存在数据,binder线程的写操作循环执行。
1 | static int binder_thread_write(struct binder_proc *proc, |
对于BC_TRANSACTION、BC_REPLY的请求码,回执行binder_transaction方法,这是最为频繁的操作,对于其他命令则不同。
3.2.1 binder_transaction
1 | static void binder_transaction(struct binder_proc *proc, |
3.2.2 BC_PROTOCOL
Binder的请求码是在binder_driver_command_protocol中定义的,用于应用程序向binder驱动设备发送请求消息,应用程序包含Client和Server端,以BC_开头,总共19条。
请求码 | 参数类型 | 作用 |
---|---|---|
BC_TRANSACTION | binder_transaction_data | Client向Binder驱动发送的请求数据 |
BC_REPLY | binder_transaction_data | Server向Binder驱动发送的回复数据 |
BC_ACQUIRE_RESULT | __s32 | 暂时不支持 |
BC_FREE_BUFFER | binder_uintptr_t | 释放内存 |
BC_INCREFS | __u32 | binder_ref弱引用加1操作 |
BC_ACQUIRE | __u32 | binder_ref弱引用减1操作 |
BC_RELEASE | __u32 | binder_ref强引用加1操作 |
BC_DECREFS | __u32 | binder_ref强引用减1操作 |
BC_INCREFS_DONE | binder_ptr_cookie | binder_node强引用减1操作 |
BC_ACQUIRE_DONE | binder_ptr_cookie | binder_node弱引用减1操作 |
BC_ATTEMPT_ACQUIRE | binder_pri_desc | 暂时不支持 |
BC_REGISTER_LOOPER | 无参数 | 创建新的Looper线程 |
BC_ENTER_LOOPER | 无参数 | 应用线程进入Looper |
BC_EXIT_LOOPER | 无参数 | 应用线程退出Looper |
BC_REQUEST_DEATH_NOTIFICATION | binder_handle_cookie | 注册死亡通知 |
BC_CLEAR_DEATH_NOTIFICATION | binder_handle_cookie | 取消注册的死亡通知 |
BC_DEAD_BINDER_DONE | binder_uintptr_t | 已经完成的死亡通知 |
BC_TRANSACTION_SG | binder_transaction_data_sg | Client向Binder驱动发送的Command |
BC_REPLY_SG | binder_transaction_data_sg | Server向Binder驱动发送的Command |
BC_FREE_BUFFER
通过mmap映射内存,其中ServiceManager映射的空间大小为128K,其他Binder应用进程映射的内存大小为1M-8k;
Binder驱动基于这种映射的内存采用最佳匹配来动态分配和释放,通过bind_buffer结构体中的free字段来表示相应的buffer是空闲还是已分配状态。对于已分配的buffers加入到binder_proc中的allocated_buffers红黑树,对于空闲的buffer加入到free_buffers红黑树;
当应用程序需要内存时,根据所需内存大小从free_buffers中找到最合适的内存,并放入allocated_buffers树中,当应用程序处理完成后必须尽快使用BC_FREE_BUFFER命令来释放该buffer,从而添加回到free_buffers树。
BC_INCREFS、BC_ACQUIRE、BC_RELEASE、BC_DECREFS等请求码的作用是对binder的强/弱引用的计数操作,用于实现强/弱指针的功能;
BC_REGISTER_LOOPER:Binder用于驱动层决策而创建新的binder线程,joniThreadPool过程,创建非binder主线程;
BC_ENTER_LOOPER:binder主线程(由应用层发起)的创建会向驱动发送该消息;joniThreadPool过程,创建binder主线程;
BC_EXIT_LOOPER:退出binder线程,对于binder主线程是不能退出;jointThreadPool的过程出现timeout且是非binder主线程,则会退出该binder线程。
3.3 binder_thread_read
响应处理的过程是通过binder_thread_read方法,该方法根据不同的binder_work->type已经不同的状态,生成相应的响应码。
1 | static int binder_thread_read(struct binder_proc *proc, |
当transaction堆栈为空且线程todo链表为空,且non_block=false时,则意味着没有任何事物需要处理,会进入等待客户端请求的状态。当有事务需要处理时便会进入循环处理过程,并生成相应的响应码。在Binder驱动层,只有在进入binder_thread_read方法时,同时满足以下条件才会生成BR_SPAWN_LOOPER命令,当用户态进程收到该命令则会创建新的线程。
1.binder_proc的requested_threads线程数等于0;
2.binder_proc的waiting_threads的列表为空;
3.binder_proc的requested_threads_started个数小于15即最大线程个数;
4.binder_thead的looper状态为BINDER_LOOPER_STATE_REGISTERED或BINDER_LOOPER_STATE_ENTERED。
响应码的处理(文章注册Servicemanager中),在用户空间的 IPCThreadState类中的 IPCThreadState::waitForResponse和 IPCThreadState::executeCommand两个方法共同处理Binder协议中的响应码。
3.3.1 BR_PROTOCOL
Binder响应码,在binder_driver_return_protocol中定义,是binder设备向应用程序回复的消息,应用程序包括client和server端,以BR_开头,总共18条。
响应码 | 参数类型 | 作用 |
---|---|---|
BR_ERROR | __s32 | 操作发送错误 |
BR_OK | 无参数 | 操作完成 |
BR_TRANSACTION | binder_transaction_data | Binder驱动向Server发送的请求数据 |
BR_REPLY | binder_transaction_data | Binder驱动向Client发送的回复数据 |
BR_ACQUIRE_RESULT | __s32 | 暂时不支持 |
BR_DEAD_REPLY | 无参数 | 回复失败,线程或节点为空 |
BR_TRANSACTION_COMPLETE | 无参数 | 对请求发送的成功反馈 |
BR_INCREFS | binder_ptr_cookie | binder_ref弱引用加1操作 |
BR_ACQUIRE | binder_ptr_cookie | binder_ref弱引用减1操作 |
BR_RELEASE | binder_ptr_cookie | binder_ref强引用加1操作 |
BR_DECREFS | binder_ptr_cookie | binder_ref强引用减1操作 |
BR_ATTEMPT_ACQUIRE | binder_pri_ptr_cookie | 暂时不支持 |
BR_NOOP | 无参数 | 不做任何事情 |
BR_SPAWN_LOOPER | 无参数 | 创建新的Looper线程 |
BR_FINISHED | 无参数 | 暂时不支持 |
BR_DEAD_BINDER | binder_uintptr_t | Binder驱动向client发送死亡通知 |
BR_CLEAR_DEATH_NOTIFICATION_DONE | binder_uintptr_t | 清除死亡通知 |
BR_FAILED_REPLY | 无参数 | 回复失败,transaction出错导致 |
BR_SPAWN_LOOPER:binder驱动已经检测到进程中没有线程等待即将到来的事务,那么当一个进程接受到这条命令时,该进程必须创建一个新的服务线程并注册该线程,在接下来的响应过程会看到何时生成该响应码。
BR_TRANSACTION_COMPLETE:当Client端向Binder驱动发送BC_TRANSACTION命令后,Client会收到BR_TRANSACTION_COMPLETE命令,告知Client端请求命令发送成功;对于Server向Binder驱动发送BC_REPLY命令后,server端会收到BR_TRANSACTION_COMPLETE命令,告知Server端请求回应命令发送成功。
BR_DEAD_REPLY:当应用层向Binder驱动发送Binder调用时,若Binder应用层的另一个端已经死亡,则驱动回应BR_DEAD_REPLY命令。
BR_FAILED_REPLY:当应用层向Binder驱动发送Binder调用时,若transaction出错,比如调用的函数号不存在,则驱动回应BR_FAILED_REPLY。
3.4 协议使用场景
3.4.1 BC协议
BC协议 | 调用方法 |
---|---|
BC_TRANSACTION | IPC.transact() |
BC_REPLY | IPC.sendReply() |
BC_FREE_BUFFER | IPC.freeBuffer() |
BC_REQUEST_DEATH_NOTIFICATION | IPC.requestDeathNotification() |
BC_CLEAR_DEATH_NOTIFICATION | IPC.clearDeathNotification() |
BC_DEAD_BINDER_DONE | IPC.execute() |
binder_thread_write()根据不同的BC协议而执行不同的流程。 其中BC_TRANSACTION和BC_REPLY协议,会进入binder_transaction()过程。
3.4.2 BR协议
BR协议 | 触发时机 |
---|---|
BR_TRANSACTION | 收到BINDER_WORK_TRANSACTION |
BR_REPLY | 收到BINDER_WORK_TRANSACTION |
BR_TRANSACTION_COMPLETE | 收到BINDER_WORK_TRANSACTION_COMPLETE |
BR_DEAD_BINDER | 收到BINDER_WORK_DEAD_BINDER或BINDER_WORK_DEAD_BINDER_AND_CLEAR |
BR_CLEAR_DEATH_NOTIFICATION_DONE | 收到BINDER_WORK_CLEAR_DEATH_NOTIFICATION |
BR_DEAD_REPLY,BR_FAILED_REPLY,BR_ERROR这些都是失败或错误相关的应答协议。
3.4.3 协议转换图
以BC_TRANSACTION为例,说明协议转换过程。
- 发起端进程:binder_transaction()过程将BC_TRANSACTION转换为BW_TRANSACTION;
- 接收端进程:binder_thread_read()过程,将BW_TRANSACTION转换为BR_TRANSACTION;
- 接收端进程:IPC.execute()过程,处理BR_TRANSACTION命令。
注:BINDER_WORK_xxx –> BW_xxx
四、Binder内存机制
binder_mmap是Binder进程间通信的高效的核心机制所在,其模型如下:
虚拟进程地址空间(vm_area_struct)和虚拟内核地址空间(vm_struct)都映射到同一块物理内存空间。当client端与server端发送数据时,client作为数据发送端,先从自己的进程空间把IPC通信数据copy_from_user拷贝到内核空间,而server端作为数据接收端,与内核共享数据,不再需要拷贝数据,而是通过内存地址空间的偏移量获取内存地址,整个过程只发生一次内存拷贝。一般的做法,需要Client端进程空间拷贝到内核空间,再由内核空间拷贝到server进程空间,会发生两次拷贝。
对于进程和内核虚拟地址映射到同一个物理内存的操作(通过地址偏移量来实现)是发生在数据接收端,而数据发送端还是需要将用户态的数据复制到内核态。为什么不直接让发送端和接收端直接映射到同一块物理空间,那样连一次复制的操作都不需要,0次复制那就和Linux标准内核的共享内存IPC没有区别了,对于共享内存虽然效率高,但是对于多进程同步的问题比较复杂,而管道/消息队列等IPC需要复制两次,效率较低。总之Android选择Binder是基于速度和安全性的考虑。
附录
下面列举Binder驱动相关的一些重要结构体
结构体列表
序号 | 结构体 | 名称 | 解释 |
---|---|---|---|
1 | binder_proc | binder进程 | 每个进程调用open()打开binder驱动都会创建该结构体,用于管理IPC所需的各种信息 |
2 | binder_thread | binder线程 | 对应于上层的binder线程 |
3 | binder_node | binder实体 | 对应于BBinder对象,记录BBinder的进程、指针、引用计数等 |
4 | binder_ref | binder引用 | 对应于BpBinder对象,记录BpBinder的引用计数、死亡通知、BBinder指针等 |
5 | binder_ref_death | binder死亡引用 | 记录binder死亡的引用信息 |
6 | binder_write_read | binder读写 | 记录buffer中读和写的数据信息 |
7 | binder_transaction_data | binder事务数据 | 记录传输数据内容,比如发送方pid/uid,RPC数据 |
8 | flat_binder_object | binder扁平对象 | Binder对象在两个进程间传递的扁平结构 |
9 | binder_buffer | binder内存 | 调用mmap()创建用于Binder传输数据的缓存区 |
10 | binder_transaction | binder事务 | 记录传输事务的发送方和接收方线程、进程等 |
11 | binder_work | binder工作 | 记录binder工作类型 |
12 | binder_state | binder状态 |
6~9 用于数据传输相关,其中binder_write_read,binder_transaction_data进程空间和内核空间是通用的。
BWR核心数据表
binder_write_read是整个Binder IPC过程,最为核心的数据结构之一。
1.binder_proc
binder_proc结构体:用于管理IPC所需的各种信息,拥有其他结构体的结构体。
类型 | 成员变量 | 解释 |
---|---|---|
struct hlist_node | proc_node | 进程节点 |
struct rb_root | threads | binder_thread红黑树的根节点 |
struct rb_root | nodes | binder_node红黑树的根节点 |
struct rb_root | refs_by_desc | binder_ref红黑树的根节点(以handle为key) |
struct rb_root | refs_by_node | binder_ref红黑树的根节点(以ptr为key) |
int | pid | 相应进程id |
struct vm_area_struct * | vma | 指向进程虚拟地址空间的指针 |
struct mm_struct * | vma_vm_mm | 相应进程的内存结构体 |
struct task_struct * | tsk | 相应进程的task结构体 |
struct files_struct * | files | 相应进程的文件结构体 |
struct hlist_node | deferred_work_node | |
int | deferred_work | |
void * | buffer | 内核空间的起始地址 |
ptrdiff_t | user_buffer_offset | 内核空间与用户空间的地址偏移量 |
struct list_head | buffers | 所有的buffer |
struct rb_root | free_buffers | 空闲的buffer |
struct rb_root | allocated_buffers | 已分配的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 | 等待队列 |
struct binder_stats | stats | binder统计信息 |
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 |
- free_buffers:记录所有空闲的buffer,记录以buffer_size为key的binder_buffer的红黑树结构
- allocated_buffers:记录所有已分配的buffer,记录以buffer_size为key的binder_buffer的红黑树结构
- buffers: 所有buffer(包含空闲的和已分配的buffer)的按地址由从低到高都连入到buffers链表中
- ready_threads: 准备就绪的线程个数,往往是指进入binder_thread_read(),处于休眠等待状态的线程个数;ready_threads线程个数越多,代表系统越空闲。
- requested_threads_started:是指系统已经启动的线程个数,在方法binder_thread_write()中,执行一次
BC_REGISTER_LOOPER
,则requested_threads_started++,requested_threads–;上限为max_threads
.BC_REGISTER_LOOPER
次数与requested_threads_started
个数应该相等; - requested_threads:请求的线程个数,在方法binder_thread_read()中,当同时满足requested_threads_started小于最大线程数,没有ready_threads线程,且requested_threads=0,则执行requested_threads++。可见requested_threads取值要么为0,要么为1.
2.binder_thread
binder_thread结构体代表当前binder操作所在的线程
类型 | 成员变量 | 解释 |
---|---|---|
struct binder_proc * | proc | 线程所属的进程 |
struct rb_node | rb_node | |
int | pid | 线程pid |
int | looper | looper的状态 |
struct binder_transaction * | transaction_stack | 线程正在处理的事务 |
struct list_head | todo | 将要处理的链表 |
uint32_t | return_error | write失败后,返回的错误码 |
uint32_t | return_error2 | write失败后,返回的错误码2 |
wait_queue_head_t | wait | 等待队列的队头 |
struct binder_stats | stats | binder线程的统计信息 |
looper的状态如下:
1 | enum { |
binder_thread_write()过程:
- 收到 BC_REGISTER_LOOPER,则线程状态为BINDER_LOOPER_STATE_REGISTERED;
- 收到 BC_ENTER_LOOPER,则线程状态为 BINDER_LOOPER_STATE_ENTERED;
- 收到 BC_EXIT_LOOPER, 则线程状态为BINDER_LOOPER_STATE_EXITED;
其他3个状态的时机:
- BINDER_LOOPER_STATE_WAITING:
- 当停留在binder_thread_read()的wait_event_xxx过程, 则设置该状态;
- BINDER_LOOPER_STATE_NEED_RETURN:
- binder_get_thread()过程, 根据binder_proc查询不到当前线程所对应的binder_thread,会新建binder_thread对象;
- binder_deferred_flush()过程;
- BINDER_LOOPER_STATE_INVALID:
- 当binder_thread创建过程状态不正确时会设置.
3.binder_node
binder_node代表一个binder实体
类型 | 成员变量 | 解释 |
---|---|---|
int | debug_id | 节点创建时分配,具有全局唯一性,用于调试使用 |
struct binder_work | work | |
struct rb_node | rb_node | binder节点正常使用,union |
struct hlist_node | dead_node | binder节点已销毁,union |
struct binder_proc * | proc | binder所在的进程 |
struct hlist_head | refs | 所有指向该节点的binder引用队列 |
int | internal_strong_refs | |
int | local_weak_refs | |
int | local_strong_refs | |
binder_uintptr_t | ptr | 指向用户空间binder_node的指针 |
binder_uintptr_t | cookie | 附件数据 |
unsigned | has_strong_ref | 占位1bit |
unsigned | pending_strong_ref | 占位1bit |
unsigned | has_weak_ref | 占位1bit |
unsigned | pending_weak_ref | 占位1bit |
unsigned | has_async_transaction | 占位1bit |
unsigned | accept_fds | 占位1bit |
unsigned | min_priority | 占位8bit,最小优先级 |
struct list_head | async_todo | 异步todo队列 |
binder_node有一个联合类型:
1 | union { |
当Binder对象已销毁,但还存在该Binder节点引用,则采用dead_node,并加入到全局列表binder_dead_nodes
;否则使用rb_node节点。
另外:
- binder_node.ptr对应于flat_binder_object.binder;
- binder_node.cookie对应于flat_binder_object.cookie。
4.binder_ref
类型 | 成员变量 | 解释 |
---|---|---|
int | debug_id | 用于调试使用 |
struct rb_node | rb_node_desc | 以desc为索引的红黑树 |
struct rb_node | rb_node_node | 以node为索引的红黑树 |
struct hlist_node | node_entry | |
struct binder_proc * | proc | binder进程 |
struct binder_node * | node | binder节点 |
uint32_t | desc | handle |
int | strong | 强引用次数 |
int | weak | 弱引用次数 |
struct binder_ref_death * | death | 当应用注册死亡通知时,此域不为空 |
binder引用的查询方式如下:
- node + proc => ref (transaction)
- desc + proc => ref (transaction, inc/dec ref)
- node => refs + procs (proc exit)
5. binder_ref_death
1 | struct binder_ref_death { |
cookie只是死亡通知的BpBinder代理对象的指针
6.binder_write_read
用户空间程序和Binder驱动程序交互基本都是通过BINDER_WRITE_READ命令,来进行数据的读写操作。
类型 | 成员变量 | 解释 |
---|---|---|
binder_size_t | write_size | write_buffer的总字节数 |
binder_size_t | write_consumed | write_buffer已消费的字节数 |
binder_uintptr_t | write_buffer | 写缓冲数据的指针 |
binder_size_t | read_size | read_buffer的总字节数 |
binder_size_t | read_consumed | read_buffer已消费的字节数 |
binder_uintptr_t | read_buffer | 读缓存数据的指针 |
- write_buffer变量:用于发送IPC(或IPC reply)数据,即传递经由Binder Driver的数据时使用。
- read_buffer 变量:用于接收来自Binder Driver的数据,即Binder Driver在接收IPC(或IPC reply)数据后,保存到read_buffer,再传递到用户空间;
write_buffer和read_buffer都是包含Binder协议命令和binder_transaction_data结构体。
- copy_from_user()将用户空间IPC数据拷贝到内核态binder_write_read结构体;
- copy_to_user()将用内核态binder_write_read结构体数据拷贝到用户空间;
7.binder_transaction_data
当BINDER_WRITE_READ命令的目标是本地Binder node时,target使用ptr,否则使用handle。只有当这是Binder node时,cookie才有意义,表示附加数据,由进程自己解释。
1 | struct binder_transaction_data { |
target
: 对于BpBinder则使用handle,对于BBinder则使用ptr,故使用union数据类型来表示;code
: 比如注册服务过程code为ADD_SERVICE_TRANSACTION,又比如获取服务code为CHECK_SERVICE_TRANSACTIONdata
:代表整个数据区,其中data.ptr指向的是传递给Binder驱动的数据区的起始地址,data.offsets指的是数据区中IPC数据地址的偏移量。cookie
: 记录着BBinder指针。- data_size:代表本次传输的parcel数据的大小;
- offsets_size: 代表传递的IPC对象的大小;根据这个可以推测出传递了多少个binder对象。
- 对于64位IPC,一个IPC对象大小等于8;
- 对于32位IPC,一个IPC对象大小等于4;
8.flat_binder_object
flat_binder_object结构体代表Binder对象在两个进程间传递的扁平结构。
类型 | 成员变量 | 解释 |
---|---|---|
__u32 | type | 类型 |
__u32 | flags | 记录优先级、文件描述符许可 |
binder_uintptr_t | binder | (union)当传递的是binder_node时使用,指向binder_node在应用程序的地址 |
__u32 | handle | (union)当传递的是binder_ref时使用,存放Binder在进程中的引用号 |
binder_uintptr_t | cookie | 只对binder_node有效,存放binder_node的额外数据 |
此处的类型type的可能取值来自于enum
,成员如下:
成员变量 | 解释 |
---|---|
BINDER_TYPE_BINDER | binder_node的强引用 |
BINDER_TYPE_WEAK_BINDER | binder_node的弱引用 |
BINDER_TYPE_HANDLE | binder_ref强引用 |
BINDER_TYPE_WEAK_HANDLE | binder_ref弱引用 |
BINDER_TYPE_FD | binder文件描述符 |
说明:
- 当type等于BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER类型时, 代表Server进程向ServiceManager进程注册服务,则创建binder_node对象;
- 当type等于BINDER_TYPE_HANDLE或BINDER_TYPE_WEAK_HEANDLE类型时, 代表Client进程向Server进程请求代理,则创建binder_ref对象;
- 当type等于BINDER_TYPE_FD类型时, 代表进程向另一个进程发送文件描述符,只打开文件,则无需创建任何对象。
9.binder_buffer
每一次Binder传输数据时,都会先从Binder内存缓存区中分配一个binder_buffer来存储传输数据。
类型 | 成员变量 | 解释 |
---|---|---|
struct list_head | entry | buffer实体的地址 |
struct rb_node | rb_node | buffer实体的地址 |
unsigned | free | 标记是否是空闲buffer,占位1bit |
unsigned | allow_user_free | 是否允许用户释放,占位1bit |
unsigned | async_transaction | 占位1bit |
unsigned | debug_id | 占位29bit |
struct binder_transaction * | transaction | 该缓存区的需要处理的事务 |
struct binder_node * | target_node | 该缓存区所需处理的Binder实体 |
size_t | data_size | 数据大小 |
size_t | offsets_size | 数据偏移量 |
uint8_t | data[0] | 数据地址 |
每一个binder_buffer分为空闲和已分配的,通过free标记来区分。空闲和已分配的binder_buffer通过各自的成员变量rb_node分别连入binder_proc的free_buffers(红黑树)和allocated_buffers(红黑树)。
10.binder_transaction
类型 | 成员变量 | 解释 |
---|---|---|
int | debug_id | 用于调试 |
struct binder_work | work | binder工作类型 |
struct binder_thread * | from | 发送端线程 |
struct binder_transaction * | from_parent | 上一个事务 |
struct binder_proc * | to_proc | 接收端进程 |
struct binder_thread * | to_thread | 接收端线程 |
struct binder_transaction * | to_parent | 下一个事务 |
unsigned | need_reply | 是否需要回复 |
struct binder_buffer * | buffer | 数据buffer |
unsigned int | code | 通信方法,比如startService |
unsigned int | flags | 标志,比如是否oneway |
long | priority | 优先级 |
long | saved_priority | 保存的优先级 |
kuid_t | sender_euid | 发送端uid |
执行binder_transaction()过程创建的结构体
- debug_id:是一个全局静态变量,每当创建一个
binder_transaction
或binder_node
或binder_ref
对象,则++debug_id - from与to_thread是一对,分别是发送端线程和接收端线程;
- from_parent与to_parent是一对,分别是上一个和下一个binder_transaction,组成一个链表。
- 执行binder_transaction()方法过程,当非oneway的BC_TRANSACTION时,则设置当前事务t->from_parent等于当前线程的transaction_stack;
- 执行binder_thread_read()方法过程,当非oneway的BR_TRANSACTION时,则设置当前事务t->to_parent等于当前线程的transaction_stack;
11.binder_work
1 | struct binder_work { |
binder_work.type设置时机:
- binder_transaction()
- binder_thread_write()
- binder_new_node()
12.binder_state
类型 | 成员变量 | 解释 |
---|---|---|
int | fd | 文件描述符 |
void * | mapped | 映射到进程空间的起始地址 |
size_t | mapsize | 内存空间的映射大小 |