查看原文
其他

Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击

IngresGe IngresGe 2021-11-05

阅读本文大约需要花费30分钟。

《Android取经之路》系列文章:

《系统启动篇》

Android取经之路——启动篇

Android系统架构

Android是怎么启动的

Android系统启动之init进程(一)

Android系统启动之init进程(二)

Android 10.0系统启动之init进程(三)

Android 10.0系统启动之init进程(四)

Android 10.0系统启动之Zygote进程(一)

Android 10.0系统启动之Zygote进程(二)

Android 10.0系统启动之Zygote进程(三)

Android 10.0系统启动之Zygote进程(四)

Android 10.0系统启动之SystemServer进程(一)

Android 10.0系统启动之SystemServer进程(二)

Android 10.0系统服务之AMS启动流程

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驱动分析


1.概述

前面介绍了Binder驱动的机制、ServiceManager加载的流程、Native层服务注册、获取的流程,但是这些都是浮在表面的接口,真正的数据时如何传输的?协议码如何转向,让我们这一节深入来分析一下    


    

2.Binder的线程与进程

对于底层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线程来处理的。



3 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队列有新的请求到来时便会唤醒,如果是由所需进程唤醒的,那么进程会让其中一个线程处理响应的请求,其他线程再次进入休眠状态。



4 Binder协议的演变

下面展示了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。



5.通信流程-binder如何定向打击

在 《Native-C\C++实例分析》 一节中,我们知道了Native层的服务注册和获取流程,我们以服务注册为示例来继续分析


5.1 talkWithDriver()

当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()



5.2 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;}
5.3 binder_transaction
流程:

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;
...}
整理了一张binder_transaction的示意图:

Client的数据传来后,进行事务处理后,唤醒Server端,Server端进行数据读取。假设我们这里的Server端为ServiceManager,在ServiceManager中有一个循环,不停的向Binder驱动发送读写的信息,读到内容后调用binder_parse()进行解析。

binder_loop()中请求时,write_size=0,到binder驱动中会进入binder_thread_read



5.3 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()把该结构传到用户态。


5.4 目标端事务处理
5.4.1.当ServiceManager为Server端时

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后,释放内存空间



5.4.2 当ProcessState中的服务为Server端时

1)当Binder驱动把 BR_TRANSACTION 放入用户空间后,waitForResponse()读到CMD=BR_TRANSACTION,会调用executeCommand()进行处理,最终调用到BBinder的transact(),最终会调到onTransact()

2)在调用完transact()动作后,executeCommand()会判断tr.flags有没有携带TF_ONE_WAY标记,如果没有携带,说明这次传输是需要回复的,于是调用sendReply()进行回复




6.总结:
6.1 服务注册

服务注册过程(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层是如何工作的。


: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存