Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
摘要:本节主要来讲解Android10.0 Binder的数据是如何完成定向打击
阅读本文大约需要花费30分钟。
文章首发微信公众号:IngresGe
专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!
欢迎关注我的公众号!
[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析
[Android取经之路] 系列文章:
《系统启动篇》
- Android系统架构
- Android是怎么启动的
- Android 10.0系统启动之init进程
- Android10.0系统启动之Zygote进程
- Android 10.0 系统启动之SystemServer进程
- Android 10.0 系统服务之ActivityMnagerService
- Android10.0系统启动之Launcher(桌面)启动流程
- Android10.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驱动分析
- Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
- Android10.0 Binder通信原理(七)-Framework binder示例
- Android10.0 Binder通信原理(八)-Framework层分析
- Android10.0 Binder通信原理(九)-AIDL Binder示例
- Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
- Android10.0 Binder通信原理(十一)-Binder总结
《HwBinder通信原理》
- HwBinder入门篇-Android10.0 HwBinder通信原理(一)
- HIDL详解-Android10.0 HwBinder通信原理(二)
- HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
- HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
- HwServiceManager篇-Android10.0 HwBinder通信原理(五)
- Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
- Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
- JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
- JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
- HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
- HwBinder原理总结-Android10.0 HwBinder通信原理(十一)
《编译原理》
- 编译系统入门篇-Android10.0编译系统(一)
- 编译环境初始化-Android10.0编译系统(二)
- make编译过程-Android10.0编译系统(三)
- Image打包流程-Android10.0编译系统(四)
- Kati详解-Android10.0编译系统(五)
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;elseerr = -errno;
#elseerr = INVALID_OPERATION;
#endifif (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的contextvoid __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_TRANSACTIONif (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 ,存入trif (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
流程:
- 我们向ServiceManager注册服务时时,Native中 new BpBinder(0,xxx),这里的handle=0,在binder驱动中找到了目标binder_node--target_node, 指向ServiceManager; 如果此时的handle 不为0,会根据handle 找到对应的binder_ref节点,最终找到binder_node;
- 根据target_node找到目标binder_proc--target_proc;
- 创建binder_transaction节点,并将其插入目标进程的todo列表;
- 尝试唤醒目标进程。
处理Binder实体与Handle转化的时候,有下面几点注意的:
- 第一次注册Binder实体的时候,是向别的进程注册的,ServiceManager,或者SystemServer中的AMS服务
- Client请求服务的时候,一定是由Binder驱动为Client分配binder_ref,如果本进程的线程请求,fp->type = BINDER_TYPE_BINDER,否则就是fp->type = BINDER_TYPE_HANDLE。
- 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,表明想访问ServiceManagerif (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_proctarget_node = binder_get_node_refs_for_txn(target_node, &target_proc,&return_error);elsereturn_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的当前线程elset->from = NULL;t->sender_euid = task_euid(proc->tsk); // 源线程用户idt->to_proc = target_proc; // 负责处理该事务的进程--ServiceManagert->to_thread = target_thread; // 负责处理该事务的线程// 将binder_transaction_data的code、flags域记入binder_transaction节点t->code = tr->code; // ADD_SERVICE_TRANSACTIONt->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_reffor (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的handlestruct 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(),尝试解析并执行那些刚收来的工作。
流程:
- 利用wait_event_xxxx()让自己挂起,等待下一次被唤醒;
- 唤醒后找到合适的待处理的工作节点,即binder_transaction节点;
- 把binder_transaction中的信息整理到一个binder_transaction_data中;
- 整理一个cmd整数值,具体数值或者为BR_TRANSACTION,或者为BR_REPLY;
- 将cmd数值和binder_transaction_data拷贝到用户态;
- 如有必要,将得到的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为falseret = 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_TRANSACTIONif (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端时
- 当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
- Binder驱动读取ServiceManager传来的数据,进入binder_transaction(),cmd=BC_REPLY,唤醒Client进程,把BR_TRANSACTION_COMPLETE分别发给ServiceManager 和Client进程
- IPCThreadState 收到BR_TRANSACTION_COMPLETE后,把数据写入mIn,mOut移除内容,继续调用talkWithDriver(),向Binder驱动发起BINDER_WRITE_READ请求,此时mOut无值,mIn有内容
- Binder驱动进入binder_thread_read(),根据ServiceManager发来的reply数据,发送BR_REPLY给client
- IPCThreadState waitForResponse()收到BR_REPLY后,释放内存空间
5.4.2 当ProcessState中的服务为Server端时
- 当Binder驱动把 BR_TRANSACTION 放入用户空间后,waitForResponse()读到CMD=BR_TRANSACTION,会调用executeCommand()进行处理,最终调用到BBinder的transact(),最终会调到onTransact()
- 在调用完transact()动作后,executeCommand()会判断tr.flags有没有携带TF_ONE_WAY标记,如果没有携带,说明这次传输是需要回复的,于是调用sendReply()进行回复
6.总结:
6.1 服务注册
服务注册过程(addService)核心功能:在服务所在进程创建binder_node,在servicemanager进程创建binder_ref。其中binder_ref的desc在同一个进程内是唯一的:
- 每个进程binder_proc所记录的binder_ref的handle值是从1开始递增的;
- 所有进程binder_proc所记录的handle=0的binder_ref都指向service manager;
- 同一个服务的binder_node在不同进程的binder_ref的handle值可以不同;
在《Native-C\C++实例分析》一节,我们说到了 MediaPlayerService 向ServiceManager 进行服务注册的流程,其中 MediaPlayerService是Client,ServiceManager是Server进程,通信流程图如下所示:
过程分析:
- MediaPlayerService进程调用ioctl()向Binder驱动发送IPC数据,该过程可以理解成一个事务binder_transaction(记为T1),执行当前操作的线程binder_thread(记为thread1),则T1>from_parent=NULL,T1>from=thread1,thread1>transaction_stack=T1。
- Binder驱动收到该Binder请求,生成BR_TRANSACTION命令,选择目标处理该请求的线程,即ServiceManager的binder线程(记为thread2),则 T1>to_parent = NULL,T1>to_thread = thread2。并将整个binder_transaction数据(记为T2)插入到目标线程的todo队列;
- ServiceManager不断地从todo链表检查是否有节点,如果有的话就会摘取下来并解析、执行,ServiceManager的线程thread2收到T2后,调用服务注册函数将服务”media.player”注册到服务目录中。当服务注册完成后,生成IPC应答数据(BC_REPLY),T2>form_parent = T1,T2>from = thread2, thread2>transaction_stack = T2。
- 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()时,会区分请求服务所属进程情况:
- 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;最终readStrongBinder(),返回的是BpBinder对象
- 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。最终readStrongBinder(),返回的是BBinder对象的真实子类
至此,Binder的定向打击,IPC数据流转就介绍完成了,下一节我们一起来看看Binder在Framework层是如何工作的。
我的微信公众号:IngresGe
Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击相关推荐
- Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
摘要:本节主要来讲解Android10.0 Native层HIDL服务的注册原理 阅读本文大约需要花费23分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Androi ...
- Android10.0 Binder通信原理(十一)-Binder总结
摘要:本节主要来讲解Android10.0 Binder的通信原理总结 阅读本文大约需要花费17分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设 ...
- Android10.0 Binder通信原理(五)-Binder驱动分析
摘要:本节主要来讲解Android10.0 Binder的驱动层分析 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计 ...
- Android10.0 Binder通信原理(二)-Binder入门篇
摘要:本节主要来讲解Android10.0 Binder的设计原理,如何设计一个Binder通信 阅读本文大约需要花费15分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分 ...
- Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
摘要:本节主要来讲解Android10.0 Binder.HwBinder.VndBinder的关联与各自作用 阅读本文大约需要花费10分钟. 文章首发微信公众号:IngresGe 专注于Androi ...
- HwBinder原理总结-Android10.0 HwBinder通信原理(十一)
摘要:本节主要来进行Android10.0 HwBinder的原理总结 阅读本文大约需要花费14分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设 ...
- HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
摘要:本节主要来讲解Android10.0 HwBinder驱动的流程 阅读本文大约需要花费24分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设 ...
- JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
摘要:本节主要来讲解Android10.0 JAVA层HIDL服务的获取原理 阅读本文大约需要花费19分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的 ...
- JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
摘要:本节主要来讲解Android10.0 JAVA层HIDL服务的注册原理 阅读本文大约需要花费22分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的 ...
最新文章
- 2021春季学期-创新设计与实践-Lesson5
- MSM 实现 tomcat session 共享
- Java剪切板操作大全
- 【案例】数据量猛增,BI分析效率太低怎么破?
- 剑指Offer - 面试题61. 扑克牌中的顺子
- java并发集合面试题,那些经常被问的JAVA面试题(1)—— 集合部分
- javascript V8引擎垃圾收集机制
- mysql的条件求和函数_mysql 带条件取count记录数,SUM()函数按条件求和
- 简化版XP按装IIS5.1实录
- 遥感数字图像处理——第三章——空间域处理方法
- 最经典的人生定律、法则、效应总结
- cypress初识--看完就可以写一个简单web自动化脚本了!
- 2021-03-23美团面试
- loj121-动态图连通性
- Credential Harvester Attack Method获得用户信息
- テクニカルアーティストの基本的な役割と、もう1つ重要な役割
- Datadog 能成为最大的云监控厂商吗
- 麻雀优化算法 优化XGBoost的参数 python代码
- 离散数学笔记_第一章:逻辑和证明(2 )
- result returns more than one elements; nested exception is javax.persistence.NonUniqueResultExceptio
热门文章
- gen_caltab自治标定板
- raver php,为PhpStorm添加Laravel 代码智能提示功能
- java 并发_Java并发原理无废话指南
- adb cannot connect to daemon_手机触屏失效的抢救办法,以及如何利用adb实现PC与手机交互...
- Activiti工作流从入门到入土:整合spring
- JavaScript获取浏览器的显示区域大小信息
- JS基础-Array对象手册
- 发布servlet版 Ajax 验证码验证组件
- 工信部:推动窄带物联网、5G泛在信息基础设施
- ngx_lua中的协程调度(三)