在我的Android体系架构解读一文中,在kernel层有很多个驱动,Android Logger,Shared Memory Driver,Binder Driver是非常通用非常重要的几个。 其中Binder Driver是Android Framework IPC机制的核心,来学习一下
整个Binder架构所涉及的总共有以下5个目录:
/framework/base/core/java/ (Java)
/framework/base/core/jni/ (JNI)
/framework/native/libs/binder (Native)
/framework/native/cmds/servicemanager/ (Native)
/kernel/drivers/staging/android (Driver)
/framework/base/core/java/android/os/
- IInterface.java
- IBinder.java
- Parcel.java
- IServiceManager.java
- ServiceManager.java
- ServiceManagerNative.java
- Binder.java
/framework/base/core/jni/
- android_os_Parcel.cpp
- AndroidRuntime.cpp
- android_util_Binder.cpp (核心类)
/framework/native/libs/binder
- IServiceManager.cpp
- BpBinder.cpp
- Binder.cpp
- IPCThreadState.cpp (核心类)
- ProcessState.cpp (核心类)
/framework/native/include/binder/
- IServiceManager.h
- IInterface.h
/framework/native/cmds/servicemanager/
- service_manager.c
- binder.c
/kernel/drivers/staging/android/
- binder.c(核心类)
- uapi/binder.h
核心method | comments |
---|---|
static int __init binder_init(void) | init |
static int binder_open(struct inode *nodp, struct file *filp) | 打开binder驱动 |
static int binder_mmap(struct file *filp, struct vm_area_struct *vma) | mmap,共享物理内存到内核虚拟地址空间和用户虚拟内存空间,binder数据传输能减少一次数据拷贝得益于此 |
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 内核空间里面的ioctl,有几种cmd:BINDER_WRITE_READ,BINDER_SET_MAX_THREADS,BINDER_SET_CONTEXT_MGR等,最重要的一种是binder_write_read |
static struct binder_thread *binder_get_thread(struct binder_proc *proc) | binder_ioctl的过程中会尽量从proc的threads树中查找和current线程匹配的binder_thread节点,如果找不到,就会创建一个新的节点并插入树中 |
static int binder_ioctl_write_read(struct file *filp,unsigned int cmd, unsigned long arg, struct binder_thread *thread) | 通过binder的写或者读的方法在内核空间最终会运行到这个方法里 |
static int binder_thread_write(struct binder_proc *proc,struct binder_thread *thread,binder_uintptr_t binder_buffer, size_t size,binder_size_t *consumed) | 该过程就是把binder_buffer里面的指令执行完毕的过程,该过程里面涉及到的指令也比较多,主要有BC_TRANSACTION、BC_REPLAY等等,从用户空间拷贝到内核空间,读出一个指令,然后根据指令完成相应的操作,比如对于BC_TRANSACTION指令就是从用户空间拷贝一段binder_transaction_data数据到内核空间copy_from_user(&tr, ptr, sizeof(tr) |
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed, int non_block) | 该过程需要通过binder_inner_proc_lock(proc)持有同步锁;当处于binder_thread_read过程,read_buffer无数据则释放同步锁,并处于binder_wait_for_work过程,等signal_pending(current)有数据到来则唤醒并尝试持有同步锁。循环从&thread->todo或者&proc->todo里面拿出一个binder_work,根据binder_work的内容从内核空间向用户空间发送BR_TRANSACTION、BR_TRANSACTION_COMPLETE、BR_DEAD_BINDER、BR_SPAWN_LOOPER等等命令,直至处理完毕 |
binder_proc是描述Binder进程上下文信息的结构体。Binder驱动的文件节点是"/dev/binder",当程序构造ProcessState并打开binder驱动(该文件节点)之时,会调用到驱动层的binder_open()函数,而binder_proc就是在binder_open()函数中创建的。新创建的binder_proc会作为一个节点,插入一个总链表(binder_procs)中。4个变量threads、nodes、refs_by_desc、refs_by_node非常重要。传输过程就是依赖于它们来实现的
类型 | 成员变量 | 解释 |
---|---|---|
struct hlist_node | proc_node; | // 根据proc_node,可以获取该进程在"全局哈希表binder_procs(统计了所有的binder proc进程)"中的位置 |
struct rb_root | threads; | // binder_proc进程内用于处理用户请求的线程组成的红黑树(关联binder_thread->rb_node) |
struct rb_root | nodes; | // binder_proc进程内的binder实体组成的红黑树(关联binder_node->rb_node) |
struct rb_root | refs_by_desc; | // binder_proc进程内的binder引用组成的红黑树,该引用以句柄来排序(关联binder_ref->rb_node_desc) |
struct rb_root | refs_by_node; | // binder_proc进程内的binder引用组成的红黑树,该引用以它对应的binder实体的地址来排序(关联binder_ref->rb_node) |
int | pid; | // 进程id |
struct vm_area_struct * | vma; | // 进程的内核虚拟内存 |
struct mm_struct * | vma_vm_mm; | |
struct task_struct * | tsk; | // 进程控制结构体(每一个进程都由task_struct 数据结构来定义)。 |
struct files_struct * | files; | // 保存了进程打开的所有文件表数据 |
struct hlist_node | deferred_work_node; | |
int | deferred_work; | |
void * | buffer; | // 该进程映射的物理内存在内核空间中的起始位置 |
ptrdiff_t | user_buffer_offset; | // 内核虚拟地址与进程虚拟地址之间的差值 |
struct list_head | buffers; | // 和binder_buffer->entry关联到同一链表,从而对Binder内存进行管理 |
struct rb_root | free_buffers; | // 空闲内存,和binder_buffer->rb_node关联。 |
struct rb_root | allocated_buffers; | // 已分配内存,和binder_buffer->rb_node关联。 |
size_t | free_async_space; | |
struct page ** | pages; | // 映射内存的page页数组,page是描述物理内存的结构体 |
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; | // 最大线程数。定义threads中可包含的最大进程数。 |
int | requested_threads; | |
int | requested_threads_started; | |
int | ready_threads; | |
long | default_priority; | // 默认优先级。 |
struct dentry * | debugfs_entry; |
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线程的统计信息 |
enum {
BINDER_LOOPER_STATE_REGISTERED = 0x01, // 创建注册线程BC_REGISTER_LOOPER
BINDER_LOOPER_STATE_ENTERED = 0x02, // 创建主线程BC_ENTER_LOOPER
BINDER_LOOPER_STATE_EXITED = 0x04, // 已退出
BINDER_LOOPER_STATE_INVALID = 0x08, // 非法
BINDER_LOOPER_STATE_WAITING = 0x10, // 等待中
BINDER_LOOPER_STATE_NEED_RETURN = 0x20, // 需要返回
};
BINDER_LOOPER_STATE_REGISTERED:binder_thread_write()过程中收到 BC_REGISTER_LOOPER,则线程状态为这个;
BINDER_LOOPER_STATE_ENTERED:binder_thread_write()过程中收到 BC_ENTER_LOOPER,则线程状态为这个;
BINDER_LOOPER_STATE_EXITED:binder_thread_write()过程中收到 BC_EXIT_LOOPER, 则线程状态为这个;
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创建过程状态不正确时会设置.
DEFAULT_MAX_BINDER_THREADS 默认最大binder线程数目15
核心method | comments |
---|---|
static int open_driver(const char *driver) | opendriver |
virtual bool threadLoop() | 加入当前线程到线程池 |
String8 ProcessState::makeBinderThreadName() | 拼出一个binder线程名 |
void ProcessState::spawnPooledThread(bool isMain) | 创建一个binder线程到线程池 |
sp |
根据handle来获取sp |
核心method | comments |
---|---|
void IPCThreadState::joinThreadPool(bool isMain) | 加入线程池,根据当前所处线程往kernel发指令BC_ENTER_LOOPER或者BC_REGISTER_LOOPER |
status_t IPCThreadState::talkWithDriver(bool doReceive) | 透传指令到driver |
status_t IPCThreadState::transact(int32_t handle,uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) | 直接在当前线程发送数据,如果有返回值的话,就在当前线程上面waitforResponse |
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) | 等结果,循环调用talkWithDriver,直到拿到结果,BR_TRANSACTION_COMPLETE,BR_REPLY等等,其它执行到executeCommand |
status_t IPCThreadState::executeCommand(int32_t cmd) | 执行commands。除了BR_TRANSACTION还有BR_DEAD_BINDER、BR_SPAWN_LOOPER等等,如果是BR_TRANSACTION,就调用进入到BBinder |
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags) | 发送回复 |
void IPCThreadState::incStrongHandle(int32_t handle) | 驱动中增加handler强引用BC_ACQUIRE |
void IPCThreadState::decStrongHandle(int32_t handle) | BC_RELEASE |
void IPCThreadState::incWeakHandle(int32_t handle) | BC_INCREFS |
void IPCThreadState::decWeakHandle(int32_t handle) | BC_DECREFS |
待补充
退出waitForResponse场景说明:
1)当Client收到BR_DEAD_REPLY或BR_FAILED_REPLY(往往是对端进程被杀或者transaction执行失败),则无论是同步还是异步的binder call都会结束waitForResponse()方法。
2)正常通信的情况下,当收到BR_TRANSACTION_COMPLETE则结束同步binder call; 当收到BR_REPLY则结束异步binder call。
Binder IPC机制的大体思路是这样的,它将每次“传输并执行特定语义的”工作理解为一个小事务,既然所传输的数据是binder_transaction_data类型的,那么这种事务的类名可以相应地定为binder_transaction。系统中当然会有很多事务啦,那么发向同一个进程或线程的若干事务就必须串行化起来,因此binder驱动为进程节点(binder_proc)和线程节点(binder_thread)都设计了个todo队列。todo队列的职责就是“串行化地组织待处理的事务”。这样看来,传输动作的基本目标就很明确了,就是想办法把发起端的一个binder_transaction节点,插入到目标端进程或其合适子线程的todo队列去。
BC_ACQUIRE、BC_RELEASE、BC_INCREFS、BC_DECREFS
BR_ACQUIRE、BR_RELEASE、BR_INCREFS、BR_DECREFS
主线程1个
普通线程做大M个,M默认15/31(不同版本),ProcessState.cpp中初始化设置DEFAULT_MAX_BINDER_THREADS,另外后期也可设置该值
普通线程也可以主动通过joinThreadPool加入到线程池中
一次数据传递从bpBinder到BBinder总拷贝1次:从起始用户空间拷贝到内核空间一次,从内核空间到目标用户空间共享
https://my.oschina.net/youranhongcha/blog/152233
http://gityuan.com/2015/10/31/binder-prepare/