binder Driver (binder IPC) 功能介绍与分析

概要

在我的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)

Java framework

/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 (核心类)

Native framework

/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

/kernel/drivers/staging/android/
- binder.c(核心类)
- uapi/binder.h

kernel核心类

binder.c

核心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等等命令,直至处理完毕

struct binder_proc

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;

struct binderThread

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 looper

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创建过程状态不正确时会设置.

Native Framework核心类

ProcessState.cpp

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 ProcessState::getStrongProxyForHandle(int32_t handle) 根据handle来获取sp

IPCThreadState.cpp

核心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

Java Framework核心类

待补充

序列图

从bpBinder到BBinder

BpBinder IPCThreadState binder.c binder.c2 IPCThreadState.c2 BBinder transact() ioctl binder_write_read binder_thread_write binder_transaction binder_thread_read BR_TRANSACTION waitForResponse executeCommand transact() sendReply 后面待补充 补充2 BpBinder IPCThreadState binder.c binder.c2 IPCThreadState.c2 BBinder

binder thread生命周期

退出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队列去。
binder Driver (binder IPC) 功能介绍与分析_第1张图片

binder service生命周期

BC_ACQUIRE、BC_RELEASE、BC_INCREFS、BC_DECREFS
BR_ACQUIRE、BR_RELEASE、BR_INCREFS、BR_DECREFS

BpBinder到BBinder的查找过程

binder Driver (binder IPC) 功能介绍与分析_第2张图片

Binder线程池

主线程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/

你可能感兴趣的:(Android,Android,Binder,Binder,Driver,Binder,IPC,Binder)