Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
阅读本文大约需要花费30分钟。
《Android取经之路》系列文章:
《系统启动篇》
Android 10.0系统启动之SystemServer进程(一)
Android 10.0系统启动之SystemServer进程(二)
Android 10.0系统启动之Launcher(桌面)启动流程
Android 10.0应用进程创建过程以及Zygote的fork流程
Android 10.0 PackageManagerService(一)工作原理及启动流程
Android 10.0 PackageManagerService(二)权限扫描
Android 10.0 PackageManagerService(三)APK扫描
Android 10.0 PackageManagerService(四)APK安装流程
《日志系统》
Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现
《Binder系列》
Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
Android10.0 Binder通信原理(二)-Binder入门篇
Android10.0 Binder通信原理(三)-ServiceManager篇
Android10.0 Binder通信原理(四)-Native-C\C++实例分析
Android10.0 Binder通信原理(五)-Binder驱动分析
前面介绍了Binder驱动的机制、ServiceManager加载的流程、Native层服务注册、获取的流程,但是这些都是浮在表面的接口,真正的数据时如何传输的?协议码如何转向,让我们这一节深入来分析一下
对于底层Binder驱动,通过binder_procs链表记录所有创建的binder_proc结构体,binder驱动层的每一个binder_proc结构体都与用户空间的一个用于binder通信的进程一一对应,且每个进程有且只有一个ProcessState对象,这是通过单例模式来保证的。在每个进程中可以有很多个线程,每个线程对应一个IPCThreadState对象,IPCThreadState对象也是单例模式,即一个线程对应一个IPCThreadState对象,在Binder驱动层也有与之相对应的结构,那就是Binder_thread结构体。在binder_proc结构体中通过成员变量rb_root threads,来记录当前进程内所有的binder_thread。
如下图所示:
Binder线程池:每个Server进程在启动时会创建一个binder线程池,并向其中注册一个Binder线程;之后Server进程也可以向binder线程池注册新的线程,或者Binder驱动在探测到没有空闲binder线程时会主动向Server进程注册新的的binder线程。对于所有Client端进程的binder请求都是交由Server端进程的binder线程来处理的。
Binder-IPC机制,就是指在进程间传输数据(binder_transaction_data),一次数据的传输,称为事务(binder_transaction)。
对于多个不同进程向同一个进程发送事务时,这个同一个进程或线程的事务需要串行执行,在Binder驱动中为binder_proc和binder_thread都有todo队列。
也就是说对于进程间的通信,就是发送端把binder_transaction节点,插入到目标进程或其子线程的todo队列中,等目标进程或线程不断循环地从todo队列中取出数据并进行相应的操作。
在Binder驱动层,每个接收端进程都有一个todo队列,用于保存发送端进程发送过来的binder请求,这类请求可以由接收端进程的任意一个空闲的binder线程处理。
接收端进程存在一个或多个binder线程,在每个binder线程里都有一个todo队列,也是用于保存发送端进程发送过来的binder请求,这类请求只能由当前binder线程来处理。
binder线程在空闲时进入可中断的休眠状态,当自己的todo队列或所属进程的todo队列有新的请求到来时便会唤醒,如果是由所需进程唤醒的,那么进程会让其中一个线程处理响应的请求,其他线程再次进入休眠状态。
下面展示了Binder协议码的演变过程,在Android9.0之前,当client向Binder驱动发送BC_TRANSACTION,Binder驱动唤醒Server进程时,会向client进程发送BR_TRANSACTION_COMPLETE,现在这一步被移到了 唤醒Client之后再做,减少了数据延迟。
Android9.0之前的协议码流程:
Android9.0及之后的协议码流程:
上面第5步的 BR_TRANSACTION_COMPLETE 被延迟到 第 10步 ,Android做了deferred_thread_work,延迟 TRANSACTION_COMPLETE,因此不会立即返回到用户空间;这允许目标进程立即开始处理此事务,从而减少延迟。然后,当目标回复(或出现错误)时,我们将返回TRANSACTION_COMPLETE。
在 《Native-C\C++实例分析》 一节中,我们知道了Native层的服务注册和获取流程,我们以服务注册为示例来继续分析
当BpBinder 调用transact()准备进行事务处理,其中发送的语义是BC_TRANSACTION.
IPCThreadState waitForResponse()中启动了while循环来和binder驱动进行通信,进行事务处理。通过talkWithDriver进行通信.
talkWithDriver()用来不停的和Binder驱动进行通信,ioctl()函数在传递BINDER_WRITE_READ语义时,既会使用“输入buffer”,也会使用“输出buffer”,所以IPCThreadState专门搞了两个Parcel类型的成员变量:mIn和mOut。mOut中的内容发出去,发送后的回复写进mIn。
BINDER_WRITE_READ的命令发给Binder驱动后,ServiceManager有个循环不停的解析Binder驱动的BINDER_WRITE_READ信息,调用binder_parse()进行解析,我们前面addService()时,传入的code为ADD_SERVICE_TRANSACTION,在ServiceManager中解析后,对应的值为SVC_MGR_ADD_SERVICE,最终把服务的name和handle(对象) 存入到svclist中,ServiceManager再通过binder_send_reply()把返回的数据发送出来,在talkWithDriver()中填入mIn中,waitForResponse()进行最终的语义处理,发送出去。
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
...
//如果仍在读取输入缓冲区中剩余的数据,并且调用方已请求读取下一个数据,则不希望写入任何内容。
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); //把mOut的数据存入 write_buffer中,
// This is what we'll read.
if (doReceive && needRead) {
//接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
//没有收到数据时,把read置空,binder只进行write处理
bwr.read_size = 0;
bwr.read_buffer = 0;
}
...
//当读缓冲和写缓冲都为空,则直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
...
#if defined(__ANDROID__)
//通过ioctl不停的读写操作,跟Binder Driver进行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
...
} while (err == -EINTR);//当被中断,则继续执行
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
...
return NO_ERROR;
}
return err;
}
第一次mOut里面存的是BC_TRANSACTION及binder_transaction_data的值,mIn没有值,talkWithDriver()中此时,bwr.write_size >0 ; bwr.read_size = 0,调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) 和binder驱动进行交互。在Binder驱动一节,我们了解到,当write_size>0, read_size=0时,会进入binder_thread_write()
流程转换:binder_ioctl()->binder_ioctl_write_read()->binder_thread_write()
主要是从用户空间拷贝binder_transaction_data的数据,并传给binder_transaction()函数进行实际的传输。
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)
{
uint32_t cmd;
struct binder_context *context = proc->context; //原来Service进程的proc的context
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed; //buffer的
void __user *end = buffer + size;
while (ptr < end && thread->return_error.cmd == BR_OK) {
int ret;
//拷贝用户空间的cmd命令,addService和getService时,为 BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);
atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);
atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);
}
switch (cmd) {
...
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷贝用户空间的 binder_transaction_data ,存入tr
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
//binder事务处理
binder_transaction(proc, thread, &tr,
cmd == BC_REPLY, 0);
break;
}
...
default:
pr_err("%d:%d unknown command %d\n",
proc->pid, thread->pid, cmd);
return -EINVAL;
}
*consumed = ptr - buffer;
}
return 0;
}
1.我们向ServiceManager注册服务时时,Native中 new BpBinder(0,xxx),这里的handle=0,在binder驱动中找到了目标binder_node--target_node, 指向ServiceManager;
如果此时的handle 不为0,会根据handle 找到对应的binder_ref节点,最终找到binder_node;
2.根据target_node找到目标binder_proc--target_proc;
3.创建binder_transaction节点,并将其插入目标进程的todo列表;
4.尝试唤醒目标进程。
处理Binder实体与Handle转化的时候,有下面几点注意的:
1.第一次注册Binder实体的时候,是向别的进程注册的,ServiceManager,或者SystemServer中的AMS服务
2.Client请求服务的时候,一定是由Binder驱动为Client分配binder_ref,如果本进程的线程请求,fp->type = BINDER_TYPE_BINDER,否则就是fp->type = BINDER_TYPE_HANDLE。
3.Android中的Parcel里面的对象一定是flat_binder_object
本地是从用户空间进入binder_transaction(),因此这里的proc、thread为前面IPCThreadState 所在进程的内容。
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
int ret;
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t buffer_offset = 0;
binder_size_t off_start_offset, off_end_offset;
binder_size_t off_min;
binder_size_t sg_buf_offset, sg_buf_end_offset;
struct binder_proc *target_proc = NULL;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
uint32_t return_error = 0;
uint32_t return_error_param = 0;
uint32_t return_error_line = 0;
binder_size_t last_fixup_obj_off = 0;
binder_size_t last_fixup_min_off = 0;
struct binder_context *context = proc->context;
int t_debug_id = atomic_inc_return(&binder_last_id);
char *secctx = NULL;
u32 secctx_sz = 0;
...
//addService第一次进来时,reply为空
if (reply) {
...
} else {
//addService和getService时,传入的handle=0,表明想访问ServiceManager
if (tr->target.handle) {
//先从tr->target.handle句柄值,找到对应的binder_ref节点,及binder_node节点
struct binder_ref *ref;
binder_proc_lock(proc);
ref = binder_get_ref_olocked(proc, tr->target.handle,
true);
if (ref) {
target_node = binder_get_node_refs_for_txn(
ref->node, &target_proc,
&return_error);
} else {
return_error = BR_FAILED_REPLY;
}
binder_proc_unlock(proc);
} else {
mutex_lock(&context->context_mgr_node_lock); //互斥锁
// handle=0则找到servicemanager实体
target_node = context->binder_context_mgr_node;
if (target_node)
//获取ServiceManager进程的target_proc
target_node = binder_get_node_refs_for_txn(
target_node, &target_proc,
&return_error);
else
return_error = BR_DEAD_REPLY;
mutex_unlock(&context->context_mgr_node_lock); //释放锁
if (target_node && target_proc == proc) {
binder_user_error("%d:%d got transaction to context manager from process owning it\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
return_error_param = -EINVAL;
return_error_line = __LINE__;
goto err_invalid_target_handle;
}
}
...
//检查Client进程是否有权限向Server进程发送请求
if (security_binder_transaction(proc->tsk,
target_proc->tsk) < 0) {
return_error = BR_FAILED_REPLY;
return_error_param = -EPERM;
return_error_line = __LINE__;
goto err_invalid_target_handle;
}
binder_inner_proc_lock(proc);
//如果flag不是oneway,并且现场的transaction_stack存在内容
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
struct binder_transaction *tmp;
tmp = thread->transaction_stack;
if (tmp->to_thread != thread) {
spin_lock(&tmp->lock);
binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n",
proc->pid, thread->pid, tmp->debug_id,
tmp->to_proc ? tmp->to_proc->pid : 0,
tmp->to_thread ?
tmp->to_thread->pid : 0);
spin_unlock(&tmp->lock);
binder_inner_proc_unlock(proc);
return_error = BR_FAILED_REPLY;
return_error_param = -EPROTO;
return_error_line = __LINE__;
goto err_bad_call_stack;
}
while (tmp) {
struct binder_thread *from;
spin_lock(&tmp->lock);
from = tmp->from;
if (from && from->proc == target_proc) {
atomic_inc(&from->tmp_ref);
target_thread = from;
spin_unlock(&tmp->lock);
break;
}
spin_unlock(&tmp->lock);
tmp = tmp->from_parent;
}
}
binder_inner_proc_unlock(proc);
}
if (target_thread)
e->to_thread = target_thread->pid;
e->to_proc = target_proc->pid;
// 创建binder_transaction节点
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL) {
return_error = BR_FAILED_REPLY;
return_error_param = -ENOMEM;
return_error_line = __LINE__;
goto err_alloc_t_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION);
spin_lock_init(&t->lock);
//创建一个binder_work节点
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
...
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
t->debug_id = t_debug_id;
...
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread; // 返回proc的当前线程
else
t->from = NULL;
t->sender_euid = task_euid(proc->tsk); // 源线程用户id
t->to_proc = target_proc; // 负责处理该事务的进程--ServiceManager
t->to_thread = target_thread; // 负责处理该事务的线程
// 将binder_transaction_data的code、flags域记入binder_transaction节点
t->code = tr->code; // ADD_SERVICE_TRANSACTION
t->flags = tr->flags; // TF_ACCEPT_FDS
// 源线程优先级设置
if (!(t->flags & TF_ONE_WAY) &&
binder_supported_policy(current->policy)) {
/* Inherit supported policies for synchronous transactions */
t->priority.sched_policy = current->policy;
t->priority.prio = current->normal_prio;
} else {
/* Otherwise, fall back to the default priority */
t->priority = target_proc->default_priority;
}
if (target_node && target_node->txn_security_ctx) {
u32 secid;
size_t added_size;
security_task_getsecid(proc->tsk, &secid);
ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
if (ret) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_get_secctx_failed;
}
added_size = ALIGN(secctx_sz, sizeof(u64));
extra_buffers_size += added_size;
if (extra_buffers_size < added_size) {
/* integer overflow of extra_buffers_size */
return_error = BR_FAILED_REPLY;
return_error_param = EINVAL;
return_error_line = __LINE__;
goto err_bad_extra_size;
}
}
//分配一块buffer用于保存mOut中的data和mObjects 中的offset数据
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
...
if (secctx) {
size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
ALIGN(tr->offsets_size, sizeof(void *)) +
ALIGN(extra_buffers_size, sizeof(void *)) -
ALIGN(secctx_sz, sizeof(u64));
t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, buf_offset,
secctx, secctx_sz);
security_release_secctx(secctx, secctx_sz);
secctx = NULL;
}
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t; // 缓冲区正交给哪个事务使用
t->buffer->target_node = target_node; // 缓冲区正交给哪个Binder实体对象使用
trace_binder_transaction_alloc_buf(t->buffer);
//拷贝用户空间的binder_transaction_data中ptr.buffer到内核,存入t->buffer
//从mOut中将data拷贝到buffer中
if (binder_alloc_copy_user_to_buffer(
&target_proc->alloc,
t->buffer, 0,
(const void __user *)
(uintptr_t)tr->data.ptr.buffer,
tr->data_size)) {
...
}
//拷贝用户空间的binder_transaction_data中ptr.offsets到内核,存入t->buffer
//从mObjects 中将offset数据拷贝到buffer中data之后
if (binder_alloc_copy_user_to_buffer(
&target_proc->alloc,
t->buffer,
ALIGN(tr->data_size, sizeof(void *)),
(const void __user *)
(uintptr_t)tr->data.ptr.offsets,
tr->offsets_size)) {
...
}
...
off_start_offset = ALIGN(tr->data_size, sizeof(void *));
buffer_offset = off_start_offset;
off_end_offset = off_start_offset + tr->offsets_size;
sg_buf_offset = ALIGN(off_end_offset, sizeof(void *));
sg_buf_end_offset = sg_buf_offset + extra_buffers_size -
ALIGN(secctx_sz, sizeof(u64));
off_min = 0;
//从data中解析出所有的binder实体并为其创建binder_node和binder_ref
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
buffer_offset += sizeof(binder_size_t)) {
struct binder_object_header *hdr;
size_t object_size;
struct binder_object object;
binder_size_t object_offset;
//得到object_offset的大小
binder_alloc_copy_from_buffer(&target_proc->alloc,
&object_offset,
t->buffer,
buffer_offset,
sizeof(object_offset));
//从t->buffer中解析object,object_size=sizeof(flat_binder_object)
object_size = binder_get_object(target_proc, t->buffer,
object_offset, &object);
if (object_size == 0 || object_offset < off_min) {
...
return_error = BR_FAILED_REPLY;
return_error_param = -EINVAL;
return_error_line = __LINE__;
goto err_bad_offset;
}
hdr = &object.hdr;
off_min = object_offset + object_size;
//根据addService时,writeStrongBinder()写的是实体Binder--BINDER_TYPE_BINDER,还是代理Binder--BINDER_TYPE_HANDLE类型来决定
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
// 如果是binder实体
struct flat_binder_object *fp;
fp = to_flat_binder_object(hdr);
//在目标进程的binder_proc中创建对应的binder_ref红黑树节点
//BINDER_TYPE_BINDER 转成BINDER_TYPE_HANDLE
//为binder实体创建binder_node并添加到红黑树proc->nodes.rb_node中
ret = binder_translate_binder(fp, t, thread);
if (ret < 0) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, object_offset,
fp, sizeof(*fp));
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
// 如果是 Binder引用,拿到Binder的handle
struct flat_binder_object *fp;
fp = to_flat_binder_object(hdr);
//在远端进程的binder_proc中找到一个binder_ref红黑树节点
//解析出引用的flat_binder_object,并在请求proc下创建服务的引用
ret = binder_translate_handle(fp, t, thread);
if (ret < 0) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, object_offset,
fp, sizeof(*fp));
} break;
...
}
}
//transaction事务处理完成
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
t->work.type = BINDER_WORK_TRANSACTION; //设置事务类型
if (reply) {
...
} else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
binder_inner_proc_lock(proc);
//延迟 TRANSACTION_COMPLETE,因此我们不会立即返回到用户空间;
//这允许目标进程立即开始处理此事务,从而减少延迟。
//然后,当目标回复(或出现错误)时,我们将返回TRANSACTION_COMPLETE。
//把binder_transaction节点插入target_list(即目标todo队列)
binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete);
t->need_reply = 1; //是双向的所以需要回复
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t; //将传递数据保存在请求线程的中,以后后续缓存释放等
binder_inner_proc_unlock(proc);
//将数据放到目标进程的todo list中去,唤醒目标进程处理请求,这里唤醒ServiceManager进行处理
if (!binder_proc_transaction(t, target_proc, target_thread)) {
binder_inner_proc_lock(proc);
binder_pop_transaction_ilocked(thread, t);
binder_inner_proc_unlock(proc);
goto err_dead_proc_or_thread;
}
} else {
...
}
if (target_thread)
binder_thread_dec_tmpref(target_thread);
binder_proc_dec_tmpref(target_proc);
if (target_node)
binder_dec_node_tmpref(target_node);
smp_wmb();
WRITE_ONCE(e->debug_id_done, t_debug_id);
return;
...
}
Client的数据传来后,进行事务处理后,唤醒Server端,Server端进行数据读取。假设我们这里的Server端为ServiceManager,在ServiceManager中有一个循环,不停的向Binder驱动发送读写的信息,读到内容后调用binder_parse()进行解析。
binder_loop()中请求时,write_size=0,到binder驱动中会进入binder_thread_read
由于本次是通过Servicemanager进入了binder_thread_read(),因此,这里的proc,thread都是ServiceManager的内容。
当目标进程ServiceManager被唤醒时,会接着执行自己的binder_thread_read(),尝试解析并执行那些刚收来的工作。
流程:
1.利用wait_event_xxxx()让自己挂起,等待下一次被唤醒;
2.唤醒后找到合适的待处理的工作节点,即binder_transaction节点;
3.把binder_transaction中的信息整理到一个binder_transaction_data中;
4.整理一个cmd整数值,具体数值或者为BR_TRANSACTION,或者为BR_REPLY;
5.将cmd数值和binder_transaction_data拷贝到用户态;
6.如有必要,将得到的binder_transaction节点插入目标端线程的transaction_stack堆栈中。
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)
{
...
retry:
//优先考虑thread节点的todo链表中有没有工作需要完成
wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
...
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_restore_priority(current, proc->default_priority);
}
if (non_block) {
if (!binder_has_work(thread, wait_for_proc_work))
ret = -EAGAIN;
} else {
//休眠在这里, wait_for_proc_work为false
ret = binder_wait_for_work(thread, wait_for_proc_work);
}
while (1) {
...
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
binder_inner_proc_unlock(proc);
t = container_of(w, struct binder_transaction, work);
} break;
}
...
//数据在内核中封装成结构体binder_transaction传输,
//据返回到应用层之后要封装成结构体 binder_transaction_data,所以这里就是将数据从新封装成binder_transaction_data返回给用户空间
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;
struct binder_priority node_prio;
trd->target.ptr = target_node->ptr;
// 用目标binder_node中记录的cookie值给binder_transaction_data的cookie域赋值
// 这个值就是目标binder实体的地址
trd->cookie = target_node->cookie;
node_prio.sched_policy = target_node->sched_policy;
node_prio.prio = target_node->min_priority;
binder_transaction_priority(current, t, node_prio,
target_node->inherit_rt);
cmd = BR_TRANSACTION;
} else {
trd->target.ptr = 0;
trd->cookie = 0;
cmd = BR_REPLY;
}
trd->code = t->code;
trd->flags = t->flags;
trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);
t_from = binder_get_txn_from(t);
if (t_from) {
struct task_struct *sender = t_from->proc->tsk;
trd->sender_pid =
task_tgid_nr_ns(sender,
task_active_pid_ns(current));
} else {
trd->sender_pid = 0;
}
trd->data_size = t->buffer->data_size;
trd->offsets_size = t->buffer->offsets_size;
trd->data.ptr.buffer = (uintptr_t)t->buffer->user_data; //获取buffer在用户空间中的地址
trd->data.ptr.offsets = trd->data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
tr.secctx = t->security_ctx;
if (t->security_ctx) {
cmd = BR_TRANSACTION_SEC_CTX;
trsize = sizeof(tr);
}
//将cmd命令写入用户态,此时应该是BR_TRANSACTION
if (put_user(cmd, (uint32_t __user *)ptr)) {
if (t_from)
binder_thread_dec_tmpref(t_from);
binder_cleanup_transaction(t, "put_user failed",
BR_FAILED_REPLY);
return -EFAULT;
}
ptr += sizeof(uint32_t);
//将重新封装后的数据拷贝到用户空间
if (copy_to_user(ptr, &tr, trsize)) {
if (t_from)
binder_thread_dec_tmpref(t_from);
binder_cleanup_transaction(t, "copy_to_user failed",
BR_FAILED_REPLY);
return -EFAULT;
}
ptr += trsize;
}
if (t_from)
binder_thread_dec_tmpref(t_from);
t->buffer->allow_user_free = 1;
if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) {
//binder_transaction节点插入了目标线程的transaction_stack堆栈,而且是以to_thread域来连接堆栈中的其他节点
binder_inner_proc_lock(thread->proc);
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
binder_inner_proc_unlock(thread->proc);
} else {
// TF_ONE_WAY情况,此时会删除binder_transaction节点
binder_free_transaction(t);
}
break;
}
如果没有工作需要做,binder_thread_read()函数就进入睡眠或返回,否则binder_thread_read()函数会从todo队列摘下了一个节点,并把节点里的数据整理成一个binder_transaction_data结构,然后通过copy_to_user()把该结构传到用户态。
1)当Binder驱动把 BR_TRANSACTION 放入用户空间后,其实此时ServiceManager为Server端,那么进入ServiceManager,binder_parse()解析BR_TRANSACTION 调用svcmgr_handler处理,code=SVC_MGR_ADD_SERVICE, 然后调用binder_send_reply() cmd_reply=BC_REPLY,cmd_free=BC_FREE_BUFFER, 发给Binder驱动,其中write_size > 0
2)Binder驱动读取ServiceManager传来的数据,进入binder_transaction(),cmd=BC_REPLY,唤醒Client进程,把BR_TRANSACTION_COMPLETE分别发给ServiceManager 和Client进程
3)IPCThreadState 收到BR_TRANSACTION_COMPLETE后,把数据写入mIn,mOut移除内容,继续调用talkWithDriver(),向Binder驱动发起BINDER_WRITE_READ请求,此时mOut无值,mIn有内容
4)Binder驱动进入binder_thread_read(),根据ServiceManager发来的reply数据,发送BR_REPLY给client
5)IPCThreadState waitForResponse()收到BR_REPLY后,释放内存空间
1)当Binder驱动把 BR_TRANSACTION 放入用户空间后,waitForResponse()读到CMD=BR_TRANSACTION,会调用executeCommand()进行处理,最终调用到BBinder的transact(),最终会调到onTransact()
2)在调用完transact()动作后,executeCommand()会判断tr.flags有没有携带TF_ONE_WAY标记,如果没有携带,说明这次传输是需要回复的,于是调用sendReply()进行回复
服务注册过程(addService)核心功能:在服务所在进程创建binder_node,在servicemanager进程创建binder_ref。其中binder_ref的desc在同一个进程内是唯一的:
1)每个进程binder_proc所记录的binder_ref的handle值是从1开始递增的;
2)所有进程binder_proc所记录的handle=0的binder_ref都指向service manager;
3)同一个服务的binder_node在不同进程的binder_ref的handle值可以不同;
在《Native-C\C++实例分析》一节,我们说到了 MediaPlayerService 向ServiceManager 进行服务注册的流程,其中 MediaPlayerService是Client,ServiceManager是Server进程,通信流程图如下所示:
过程分析:
1)MediaPlayerService进程调用ioctl()向Binder驱动发送IPC数据,该过程可以理解成一个事务binder_transaction(记为T1),执行当前操作的线程binder_thread(记为thread1),则T1>from_parent=NULL,T1>from=thread1,thread1>transaction_stack=T1。
2)Binder驱动收到该Binder请求,生成BR_TRANSACTION命令,选择目标处理该请求的线程,即ServiceManager的binder线程(记为thread2),则 T1>to_parent = NULL,T1>to_thread = thread2。并将整个binder_transaction数据(记为T2)插入到目标线程的todo队列;
3)ServiceManager不断地从todo链表检查是否有节点,如果有的话就会摘取下来并解析、执行,ServiceManager的线程thread2收到T2后,调用服务注册函数将服务”media.player”注册到服务目录中。当服务注册完成后,生成IPC应答数据(BC_REPLY),T2>form_parent = T1,T2>from = thread2, thread2>transaction_stack = T2。
4)Binder驱动收到该Binder应答请求,生成BR_REPLY命令,T2>to_parent = T1,T2>to_thread = thread1, thread1>transaction_stack = T2。在MediaPlayerService收到该命令后,知道服务注册完成便可以正常使用。
整个过程中,BC_TRANSACTION和BR_TRANSACTION过程是一个完整的事务过程;BC_REPLY和BR_REPLY是一个完整的事务过程。到此,其他进行便可以获取该服务,使用服务提供的方法。
6.2获取服务
获取服务(getService)过程,就是向servicemanager进程查询指定服务,当执行binder_transaction()时,会区分请求服务所属进程情况:
1)当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;最终readStrongBinder(),返回的是BpBinder对象
2)当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。最终readStrongBinder(),返回的是BBinder对象的真实子类
至此,Binder的定向打击,IPC数据流转就介绍完成了,下一节我们一起来看看Binder在Framework层是如何工作的。