美文网首页
Android Binder通信原理--06:Binder数据如

Android Binder通信原理--06:Binder数据如

作者: DarcyZhou | 来源:发表于2023-10-18 08:33 被阅读0次

本文转载自:Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击

本文基于Android 10.0源码分析

1.摘要

  本节主要来讲解Android10.0 Binder的数据是如何完成定向打击。

2.概述

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

3.Binder的线程与进程

  对于底层Binder驱动,通过binder_procs链表记录所有创建的binder_proc结构体,binder驱动层的每一个binder_proc结构体都与用户空间的一个用于binder通信的进程一一对应,且每个进程有且只有一个ProcessState对象,这是通过单例模式来保证的。在每个进程中可以有很多个线程,每个线程对应一个IPCThreadState对象,IPCThreadState对象也是单例模式,即一个线程对应一个IPCThreadState对象,在Binder驱动层也有与之相对应的结构,那就是binder_thread结构体。在binder_proc结构体中通过成员变量rb_root threads,来记录当前进程内所有的binder_thread。

  如下图所示:

Binder6-1.png

Binder线程池:

  每个Server进程在启动时会创建一个binder线程池,并向其中注册一个Binder线程;之后Server进程也可以向binder线程池注册新的线程,或者Binder驱动在探测到没有空闲binder线程时会主动向Server进程注册新的的binder线程。对于所有Client端进程的binder请求都是交由Server端进程的binder线程来处理的。

4.Binder传输过程

  Binder-IPC机制,就是指在进程间传输数据(binder_transaction_data),一次数据的传输,称为事务(binder_transaction)。
  对于多个不同进程向同一个进程发送事务时,这个同一个进程或线程的事务需要串行执行,在Binder驱动中为binder_proc和binder_thread都有todo队列。
  也就是说对于进程间的通信,就是发送端把binder_transaction节点,插入到目标进程或其子线程的todo队列中,等目标进程或线程不断循环地从todo队列中取出数据并进行相应的操作。

Binder6-2.png

  在Binder驱动层,每个接收端进程都有一个todo队列,用于保存发送端进程发送过来的binder请求,这类请求可以由接收端进程的任意一个空闲的binder线程处理。
  接收端进程存在一个或多个binder线程,在每个binder线程里都有一个todo队列,也是用于保存发送端进程发送过来的binder请求,这类请求只能由当前binder线程来处理。
  binder线程在空闲时进入可中断的休眠状态,当自己的todo队列或所属进程的todo队列有新的请求到来时便会唤醒,如果是由所需进程唤醒的,那么进程会让其中一个线程处理响应的请求,其他线程再次进入休眠状态。

5.Binder协议的演变

  下面展示了Binder协议码的演变过程,在Android9.0之前,当client向Binder驱动发送BC_TRANSACTION,Binder驱动唤醒Server进程时,会向client进程发送BR_TRANSACTION_COMPLETE,现在这一步被移到了唤醒Client之后再做,减少了数据延迟。

(1)Android9.0之前的协议码流程

Binder6-3.png

(2)Android9.0及之后的协议码流程

  上面第5步的 BR_TRANSACTION_COMPLETE 被延迟到第 10步 ,Android做了deferred_thread_work,延迟 TRANSACTION_COMPLETE,因此不会立即返回到用户空间;这允许目标进程立即开始处理此事务,从而减少延迟。然后,当目标回复(或出现错误)时,我们将返回TRANSACTION_COMPLETE。

Binder6-4.png

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

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

Binder6-5.png

6.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()进行最终的语义处理,发送出去。

// frameworks/native/libs/binder/IPCThreadState.cpp
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()

6.2 binder_thread_write

  主要是从用户空间拷贝binder_transaction_data的数据,并传给binder_transaction()函数进行实际的传输。

// drivers/android/binder.c
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;
}

6.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所在进程的内容。

// drivers/android/binder.c
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的示意图:

Binder6-6.png

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

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

6.4 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堆栈中。

// drivers/android/binder.c
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()把该结构传到用户态。

6.5 目标端事务处理

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

6.5.2 当ProcessState中的服务为Server端时

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

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

7.总结

7.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进程,通信流程图如下所示:

Binder6-7.png

过程分析:

  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是一个完整的事务过程。到此,其他进行便可以获取该服务,使用服务提供的方法。

7.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层是如何工作的。

相关文章

网友评论

      本文标题:Android Binder通信原理--06:Binder数据如

      本文链接:https://www.haomeiwen.com/subject/nslvbdtx.html