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

[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编译系统(五)
Blueprint简介-Android10.0编译系统(六)
Blueprint代码详细分析-Android10.0编译系统(七)
Android.bp 语法浅析-Android10.0编译系统(八)
Ninja简介-Android10.0编译系统(九)
Ninja提升编译速度的方法-Android10.0编译系统(十)
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;
        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
流程:

我们向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,表明想访问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(),尝试解析并执行那些刚收来的工作。

 

流程:

利用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为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端时
当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进程,通信流程图如下所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值