Android Binder机制(六) addService详解02之 请求的处理

前面一文介绍了addService的请求发送部分,Binder驱动在处理addService请求时,将一个待处理事务添加到ServiceManager中,然后将ServiceManager唤醒。在Android Binder机制(三) ServiceManager守护进程的末尾,我们说过ServiceManager启动之后,由于没有事务可处理,就进入了等待状态。这里,从ServiceManager被唤醒后开始讲解。

目录
1. Android消息机制的架构

注意:本文是基于Android 4.4.2版本进行介绍的!

1. Binder驱动中binder_thread_read()的源码

下面,就接着Android Binder机制(三) ServiceManager守护进程中的休眠部分进行讲解,看看Service Manager被唤醒后,会干些什么。

static int binder_thread_read(struct binder_proc *proc,
                struct binder_thread *thread,
                void  __user *buffer, int size,
                signed long *consumed, int non_block)
{
    ...
    if (wait_for_proc_work) {
      ...
      if (non_block) {
          ...
      } else
          // 阻塞式的读取,则阻塞等待事务的发生。
          ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    } else {
      ...
    }
    ...

    while (1) {
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;

        // 如果当前线程的"待完成工作"不为空,则取出待完成工作。
        if (!list_empty(&thread->todo))
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        else if (!list_empty(&proc->todo) && wait_for_proc_work)
            ...
        else {
            ...
        }

        ...

        switch (w->type) {
            case BINDER_WORK_TRANSACTION: {
                t = container_of(w, struct binder_transaction, work);
            } break;
            ...
        }

        if (!t)
            continue;

        // t->buffer->target_node是目标节点。
        // 这里,addService请求的目标是ServiceManager,因此target_node是ServiceManager对应的节点;
        // 它的值在事务交互时(binder_transaction中),被赋值为ServiceManager对应的Binder实体。  
        if (t->buffer->target_node) {
            // 事务目标对应的Binder实体(即,ServiceManager对应的Binder实体)
            struct binder_node *target_node = t->buffer->target_node;
            // Binder实体在用户空间的地址(ServiceManager的ptr为NULL)
            tr.target.ptr = target_node->ptr;
            // Binder实体在用户空间的其它数据(ServiceManager的cookie为NULL)
            tr.cookie =  target_node->cookie;
            t->saved_priority = task_nice(current);
            if (t->priority < target_node->min_priority &&
                !(t->flags & TF_ONE_WAY))
                binder_set_nice(t->priority);
            else if (!(t->flags & TF_ONE_WAY) ||
                 t->saved_priority > target_node->min_priority)
                binder_set_nice(target_node->min_priority);
            cmd = BR_TRANSACTION;
        } else {
            tr.target.ptr = NULL;
            tr.cookie = NULL;
            cmd = BR_REPLY;
        }
        // 交易码
        tr.code = t->code;
        tr.flags = t->flags;
        tr.sender_euid = t->sender_euid;

        if (t->from) {
            struct task_struct *sender = t->from->proc->tsk;
            tr.sender_pid = task_tgid_nr_ns(sender,
                            current->nsproxy->pid_ns);
        } else {
            tr.sender_pid = 0;
        }

        // 数据大小
        tr.data_size = t->buffer->data_size;
        // 数据中对象的偏移数组的大小(即对象的个数)
        tr.offsets_size = t->buffer->offsets_size;
        // 数据
        tr.data.ptr.buffer = (void *)t->buffer->data +
                    proc->user_buffer_offset;
        // 数据中对象的偏移数组
        tr.data.ptr.offsets = tr.data.ptr.buffer +
                    ALIGN(t->buffer->data_size,
                        sizeof(void *));

        // 将cmd指令写入到ptr,即传递到用户空间
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        // 将tr数据拷贝到用户空间
        ptr += sizeof(uint32_t);
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        ptr += sizeof(tr);

        ...
        // 删除已处理的事务
        list_del(&t->work.entry);
        t->buffer->allow_user_free = 1;
        // 设置回复信息
        if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
            // 该事务会发送给Service Manager守护进程进行处理。
            // Service Manager处理之后,还需要给Binder驱动回复处理结果。
            // 这里设置Binder驱动回复信息。
            t->to_parent = thread->transaction_stack;
            // to_thread表示Service Manager反馈后,将反馈结果交给当前thread进行处理
            t->to_thread = thread;
            // transaction_stack交易栈保存当前事务。用于之处反馈是针对哪个事务的。
            thread->transaction_stack = t;
        } else {
            ...
        }
        break;
    }

done:

    // 更新bwr.read_consumed的值
    *consumed = ptr - buffer;

    ...
    return 0;
}

说明:ServiceManager进程在调用wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread))进入等待之后,被MediaPlayerService进程唤醒。唤醒之后,binder_has_thread_work()为true,因为ServiceManager的待处理事务队列中有个待处理事务(即,MediaPlayerService添加服务的请求)。
(01) 进入while循环后,首先取出待处理事务。
(02) 事务的类型是BINDER_WORK_TRANSACTION,得到对应的binder_transaction*类型指针t之后,跳出switch语句。很显然,此时t不为NULL,因此继续往下执行。下面的工作的目的,是将t中的数据转移到tr中(tr是事务交互数据包结构体binder_transaction_data对应的指针),然后将指令和tr数据都拷贝到用户空间,让ServiceManager读取后进行处理。
下面列举比较重要的几个部分进行说明。

    // 数据大小
    tr.data_size = t->buffer->data_size;
    // 数据中对象的偏移数组的大小(即对象的个数)
    tr.offsets_size = t->buffer->offsets_size;
    // 数据
    tr.data.ptr.buffer = (void *)t->buffer->data +
                proc->user_buffer_offset;
    // 数据中对象的偏移数组
    tr.data.ptr.offsets = tr.data.ptr.buffer +
                ALIGN(t->buffer->data_size,
                        sizeof(void *));

这里着重强调一下地址的赋值方式,因为它涉及到Binder机制的数据拷贝原理!
t->buffer是在binder_transaction()中,通过binder_alloc_buf()分配的内核空间地址。现在要将数据返回给Service Manager守护进程,需要将内核空间的数据拷贝到用户空间。如果你还记得的话,前面在Android Binder机制(三) ServiceManager守护进程的mmap()中,我们将内核虚拟地址和进程虚拟地址映射到同一个物理存储区;现在,已知内核虚拟地址(即t->buffer->data)。那么,只需要将t->buffer->data加上proc->user_buffer_offset(内核虚拟地址和进程虚拟地址的偏移)即可得到在用户空间的地址。

在tr赋值完毕之后,就将完整数据拷贝到用户空间。此时,该事务已经在Binder驱动中被处理,于是将事务从Service Manager的待处理事务队列中删除。Binder驱动随后会将该事务发送给Service Manager守护进程,Service Manager守护进程在处理完事务之后,需要反馈结果给Binder驱动。因此,接下来会设置t->to_thread和t->transaction_stack等成员。最后,修改*consumed的值,即bwr.read_consumed的值,表示待读取内容的大小。
执行完binder_thread_read()之后,回到binder_ioctl()中,执行copy_to_user()将数据拷贝到用户空间。接下来,就回到了Service Manager的守护进程当中,即回到binder_loop()中。

2. binder_loop()

void binder_loop(struct binder_state *bs, binder_handler func)
{
    struct binder_write_read bwr;
    unsigned readbuf[32];
    ...

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;

        bwr.read_buffer = (unsigned) readbuf;

        // 向Kernel中发送消息(先写后读)。
        // 先将消息传递给Kernel,然后再从Kernel读取消息反馈
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        ...

        // 解析读取的消息反馈
        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        ...
    }
}

说明:binder_loop()会将ioctl()反馈的数据发送给binder_parse()进行解析。

3. binder_parse()

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uint32_t *ptr, uint32_t size, binder_handler func)
{
    int r = 1;
    uint32_t *end = ptr + (size / 4);

    while (ptr < end) {
        uint32_t cmd = *ptr++;

        switch(cmd) {
        case BR_NOOP:
            break;
        ...
        case BR_TRANSACTION: {
            struct binder_txn *txn = (void *) ptr;
            ...
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;   // 用于保存"Binder驱动反馈的信息"
                struct binder_io reply; // 用来保存"回复给Binder驱动的信息"
                int res;

                // 初始化reply
                bio_init(&reply, rdata, sizeof(rdata), 4);
                // 根据txt(Binder驱动反馈的信息)初始化msg
                bio_init_from_txn(&msg, txn);
                // 消息处理
                res = func(bs, txn, &msg, &reply);
                // 反馈消息给Binder驱动。
                binder_send_reply(bs, &reply, txn->data, res);
            }
            ptr += sizeof(*txn) / sizeof(uint32_t);
            break;
        }
        ...
        }
    }

    return r;
}

说明:此处里的cmd就是bwr.read_buffer指针。而在Binder驱动的binder_thread_read()中,反馈的第一个指令是BR_NOOP;因此这里的cmd=BR_NOOP,不执行任何动作,继续取出下一个指令cmd=BR_TRANSACTION。在BR_TRANSACTION中,会先取出消息,在对消息处理之后,再将反馈信息发送给Binder驱动。下面是BR_TRANSACTION的详细内容。
(01) 首先,将ptr转换成struct binder_txn结构体指针。struct binder_txn是与binder_transaction_datad对应的结构体,在Android Binder机制(二) Binder中的数据结构中有它的详细介绍。
(02) 此处的func是函数指针svcmgr_handler,不为空;因此,先调用bio_init()初始化reply,再调用bio_init_from_txn()来初始化msg。
(03) 初始化完毕之后,就调用svcmgr_handler()对消息进行处理。
(04) 消息处理完毕,就通过binder_send_reply()将处理结果反馈给Binder驱动。

4. bio_init()

void bio_init(struct binder_io *bio, void *data,
              uint32_t maxdata, uint32_t maxoffs)
{               
    uint32_t n = maxoffs * sizeof(uint32_t);

    if (n > maxdata) {
        bio->flags = BIO_F_OVERFLOW;
        bio->data_avail = 0;
        bio->offs_avail = 0;            
        return;
    }       

    bio->data = bio->data0 = (char *) data + n;
    bio->offs = bio->offs0 = data;
    bio->data_avail = maxdata - n;
    bio->offs_avail = maxoffs;
    bio->flags = 0;
}

说明:bio_init()就是对struct binder_io的各个成员赋值。

5. bio_init_from_txn()

void bio_init_from_txn(struct binder_io *bio, struct binder_txn *txn)
{           
    bio->data = bio->data0 = txn->data;    // 数据起始地址
    bio->offs = bio->offs0 = txn->offs;    // 数据中对象的偏移数组的起始地址
    bio->data_avail = txn->data_size;      // 数据大小
    bio->offs_avail = txn->offs_size / 4;  // 对象个数
    bio->flags = BIO_F_SHARED;
}

说明:bio_init_from_txn()就是根据已有的数据txn初始化struct binder_io的各个成员。

6. svcmgr_handler()

int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;  
    uint32_t strict_policy;
    int allow_isolated;

    if (txn->target != svcmgr_handle)
        return -1;

    ...
    // 数据有效性检测(数据头)
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        ...
    }

    switch(txn->code) {
        case SVC_MGR_GET_SERVICE:
        case SVC_MGR_CHECK_SERVICE:
            ...

        case SVC_MGR_ADD_SERVICE:
            s = bio_get_string16(msg, &len);
            ptr = bio_get_ref(msg);
            allow_isolated = bio_get_uint32(msg) ? 1 : 0;
            if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
                return -1;
            break;
        case SVC_MGR_LIST_SERVICES:
            ...
    }

    bio_put_uint32(reply, 0);
    return 0;
}

说明:
(01) txt->target对应tr.target.ptr,而tr.target.ptr是Binder驱动的在binder_thread_read()中赋值的,它指向Service Manager的Binder实体在用户空间的句柄,是NULL。而svcmgr_handle=BINDER_SERVICE_MANAGER=((void*) 0)。显然,txt->target=svcmgr_handler。
(02) 接下来,先通过bio_get_uint32(msg)和bio_get_string16(msg, &len)进行有效性检测。通过bio_get_uint32()从msg中取出32位的整型数,就是MediaPlayerService请求数据中的STRICT_MODE_PENALTY_GATHER。然后,通过bio_get_string16(msg, &len)获取数据中字符串,也就是"android.os.IServiceManager"。接着,将该字符串和svcmgr_id进行比较(依次比较长度和内容);很显然,这里是相当的。
(03) 在通过有效性检测之后,就根据相应的事务编码进行处理。这里txt->code的值是SVC_MGR_ADD_SERVICE。先通过bio_get_string16()获取MediaPlayerService的名称,也就是s="media.player",然后就通过bio_get_ref()获取MediaPlayerService对象的引用。

7. svcmgr_handler()

void *bio_get_ref(struct binder_io *bio)
{   
    struct binder_object *obj;

    obj = _bio_get_obj(bio);
    if (!obj)
        return 0;

    if (obj->type == BINDER_TYPE_HANDLE)
        return obj->pointer;

    return 0;
}       

说明:binder_object是与flat_binder_object对应的结构体,关于它的详细介绍可以参考Android Binder机制(二) Binder中的数据结构
(01) _bio_get_obj(bio)的代码就不展开了,它是根据bio创建binder_object对象。实际上,obj就是MediaPlayerService打包成的flat_binder_object对象。
(02) obj->type的值是BINDER_TYPE_HANDLE。原来MediaPlayerService对应的type是BINDER_TYPE_BINDER,但在Binder驱动的binder_transaction()中,将type修改成了BINDER_TYPE_HANDLE。因此,返回obj->pointer,而obj->pointer实际上是flat_binder_object中的handle,而该handle在Binder驱动中被赋值为"MediaPlayerService对应的Binder引用的描述,即binder_ref->desc"。根据该引用描述,可以在Binder驱动中找到MediaPlayerService对应的Binder实体以及MediaPlayerService对应的进程上下文信息,进而可以给MediaPlayerService发送消息。

8. svcmgr_handler()

接下来,回到svcmgr_handler()中,继续执行do_add_service()。

int do_add_service(struct binder_state *bs,
                   uint16_t *s, unsigned len,
                   void *ptr, unsigned uid, int allow_isolated)
{
    struct svcinfo *si;
    ...

    if (!svc_can_register(uid, s)) {
        ...
    }

    si = find_svc(s, len);
    if (si) {
        ...
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) { 
            ...
        }
        si->ptr = ptr;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\0';
        si->death.func = svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->next = svclist;
        svclist = si;
    }

    binder_acquire(bs, ptr);
    binder_link_to_death(bs, ptr, &si->death);
    return 0;
}

说明:do_add_service()是将该MediaPlayerService (01) 先看看参数。bs是struct binder_state类型,它在保存了打开"/dev/binder"文件的相关信息。s是IBinder对象的名称,即"media.player"。len是s的长度。ptr是MediaPlayerService在Binder驱动中的引用描述。uid是MediaPlayerService的uid。allow_isolated是flase。
(02) svc_can_register()是检测能否将uid线程的信息注册到Service Manager中。这里,返回true。
(03) find_svc(s, len)是在Service Manager的服务队列svclist中,查找是否有名称为s的服务。由于之前没有将MediaPlayerService注册到Service Manager中,这里返回的si=null;接下来,就将MediaPlayerService的信息保存到si中,然后再将si注册到svclist中。
这样,MediaPlayerService就注册到Service Manager中了。

9. svcmgr_handler()

接下来,回到svcmgr_handler()中,调用bio_put_uint32(reply, 0)。这里就不对bio_put_uint32()的代码进行展开了,bio_put_uint32(reply, val)的作用是将val写入到reply中。但是,当val=0时,不会写入任何数据;也就是说bio_put_uint32(reply, 0)不会写入任何数据到reply中!

int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    ...

    switch(txn->code) {

        case SVC_MGR_ADD_SERVICE:
            s = bio_get_string16(msg, &len);
            ptr = bio_get_ref(msg);
            allow_isolated = bio_get_uint32(msg) ? 1 : 0;
            if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
                return -1;
            break;
            ...
    }

    bio_put_uint32(reply, 0);
    return 0;
}

接着,回到binder_parse()中,调用binder_send_reply()写入到即将发送Binder的缓冲区中。

10. svcmgr_handler()

void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       void *buffer_to_free,
                       int status)
{   
    struct {
        uint32_t cmd_free;
        void *buffer;
        uint32_t cmd_reply;
        struct binder_txn txn;
    } __attribute__((packed)) data;

    data.cmd_free = BC_FREE_BUFFER;
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY;
    data.txn.target = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        ...
    } else {
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data = reply->data0;
        data.txn.offs = reply->offs0;
    }
    binder_write(bs, &data, sizeof(data));
}   

说明:
(01) 先看看参数。bs是struct binder_state,它保存了打开"/dev/binder"文件的相关信息。reply没有任何数据。buffer_to_free是对应binder_transaction_data中保存请求数据的buffer缓冲区,它是在Binder驱动的binder_transaction()中分配的。status_t=0。
(02) 该函数中的私有结构体struct是用来描述返回给Binder驱动的数据。我们知道,Binder机制的交互数据的格式是"指令+数据"。这里,返回的指令有两个BC_FREE_BUFFER和BC_REPLY,BC_FREE_BUFFER是告诉Binder驱动,请求处理完毕,让Binder驱动释放数据缓冲;而BC_REPLY是告诉Binder驱动,这是回复,回复的内容是data.txt.data,实际上,这里的回复内容是空!
(03) 最后,调用binder_write()将数据打包。

11. binder_write()的源码

int binder_write(struct binder_state *bs, void *data, unsigned len)
{
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;                // 数据长度
    bwr.write_consumed = 0;             
    bwr.write_buffer = (unsigned) data;  // 数据是BINDER_WRITE_READ
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                strerror(errno));
    }
    return res;
}

说明:binder_write()单单只是向Binder驱动发送一个消息,而不会去读取消息反馈。

12. Binder驱动中binder_ioctl()的BINDER_WRITE_READ相关部分的源码

下面我们看看Binder驱动部分的对应代码。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  ...

  switch (cmd) {
  case BINDER_WRITE_READ: {
      struct binder_write_read bwr;
      ...

      // 将binder_write_read从"用户空间" 拷贝到 "内核空间"
      if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
          ...
      }

      // 如果write_size>0,则进行写操作
      if (bwr.write_size > 0) {
          ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
          ...
      }

      // 如果read_size>0,则进行读操作
      if (bwr.read_size > 0) {
          ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags   & O_NONBLOCK);
          ...
      }
      ...

      if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
          ret = -EFAULT;
          goto err;
      }
      break;
  }
  ...
  }
  ret = 0;

  ...
  return ret;
}

说明:bwr.write_size>0,而bwr.read_size=0;因此,只会执行写动作,而不会进行读取动作。下面看看binder_thread_write()到底写了些什么。

13. Binder驱动中binder_thread_write()的源码

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
            void __user *buffer, int size, signed long *consumed)
{
    uint32_t cmd; 
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;

    // 读取binder_write_read.write_buffer中的内容。
    // 每次读取32bit(即4个字节)
    while (ptr < end && thread->return_error == BR_OK) {
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);

        ...
        switch (cmd) {

        case BC_FREE_BUFFER: {
            void __user *data_ptr;
            struct binder_buffer *buffer;

            // 获取要释放的内存地址
            if (get_user(data_ptr, (void * __user *)ptr))
                return -EFAULT;
            ptr += sizeof(void *);

            // 根据用户空间地址,得到进程空间地址;
            // 再根据进程空间地址,在proc->allocated_buffers红黑树中进行查找该地址对应的binder_buffer对象。
            buffer = binder_buffer_lookup(proc, data_ptr);
            ...
            // 释放内存
            trace_binder_transaction_buffer_release(buffer);
            binder_transaction_buffer_release(proc, buffer, NULL);
            binder_free_buf(proc, buffer);
            break;
        }
        case BC_TRANSACTION:
        case BC_REPLY: {
            struct binder_transaction_data tr;

            if (copy_from_user(&tr, ptr, sizeof(tr)))
                return -EFAULT;
            ptr += sizeof(tr);
            binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
            break;
        }
        ...
        }
        // 更新bwr.write_consumed的值
        *consumed = ptr - buffer;
    }
    return 0;
}

说明:在Service Manager中,反馈给Binder驱动的指令有两个,分别是BC_FREE_BUFFER和BC_REPLY。
(01) binder_write_read()先读出BC_FREE_BUFFER指令,然后释放内存。代码中给出了相应的注释,这里就不再详细说明了。
(02) 接着,读出BC_REPLY指令,将数据拷贝到内核空间之后,便执行binder_transaction()对数据进行处理。

14. Binder驱动中binder_transaction()的源码

static void binder_transaction(struct binder_proc *proc,
                   struct binder_thread *thread,
                   struct binder_transaction_data *tr, int reply)
{
    struct binder_transaction *t;
    struct binder_work *tcomplete;
    size_t *offp, *off_end;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    struct binder_transaction_log_entry *e;
    uint32_t return_error;

    ...

    if (reply) {
        // 事务栈
        in_reply_to = thread->transaction_stack;
        ...
        // 设置优先级
        binder_set_nice(in_reply_to->saved_priority);
        ...
        thread->transaction_stack = in_reply_to->to_parent;
        // 发起请求的线程,即MediaPlayerService所在线程。
        // from的值,是MediaPlayerService发起请求时在binder_transaction()中赋值的。
        target_thread = in_reply_to->from;
        ...
        // MediaPlayerService对应的进程
        target_proc = target_thread->proc;
    } else {
        ...
    }
    if (target_thread) {
        e->to_thread = target_thread->pid;
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
    } else {
        ...
    }
    e->to_proc = target_proc->pid;

    // 分配一个待处理的事务t,t是binder事务(binder_transaction对象)
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    if (t == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_t_failed;
    }

    // 分配一个待完成的工作tcomplete,tcomplete是binder_work对象。
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    if (tcomplete == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_tcomplete_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);

    t->debug_id = ++binder_last_id;
    e->debug_id = t->debug_id;

    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;
    // 下面的一些赋值是初始化事务t
    t->sender_euid = proc->tsk->cred->euid;
    // 事务将交给target_proc进程进行处理
    t->to_proc = target_proc;
    // 事务将交给target_thread线程进行处理
    t->to_thread = target_thread;
    // 事务编码
    t->code = tr->code;
    // 事务标志
    t->flags = tr->flags;
    // 事务优先级
    t->priority = task_nice(current);

    // 分配空间
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
        tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    if (t->buffer == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_binder_alloc_buf_failed;
    }
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    // 保存事务
    t->buffer->transaction = t;
    // target_node为NULL
    t->buffer->target_node = target_node;
    trace_binder_transaction_alloc_buf(t->buffer);
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);

    offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

    // 将"用户传入的数据"保存到事务中
    if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
        ...
    }
    // 将"用户传入的数据偏移地址"保存到事务中
    if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
        ...
    }

    ...
    off_end = (void *)offp + tr->offsets_size;
    for (; offp < off_end; offp++) {
        ...
    }
    if (reply) {
        binder_pop_transaction(target_thread, in_reply_to);
    } else if (!(t->flags & TF_ONE_WAY)) {
        ...
    } else {
        ...
    }
    // 设置事务的类型为BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // 将事务添加到target_list队列中,即target_list的待处理事务中
    list_add_tail(&t->work.entry, target_list);
    // 设置待完成工作的类型为BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // 将待完成工作添加到thread->todo队列中,即当前线程的待完成工作中。
    list_add_tail(&tcomplete->entry, &thread->todo);
    // 唤醒目标进程
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;
    ...
}

说明:
(01) reply=1。这里只关注reply部分。target_thread被赋值为MediaPlayerService所在的线程,而target_proc则是MediaPlayerService对应的进程。
(02) 接着,会新建一个待处理事务t和待完成的工作tcomplete,并对它们进行初始化。这部分前面已经介绍过了;这里就不再重复说明了。从Service Manager反馈的信息中,仅仅包含了数据0,而没有flat_binder_object对象;因此,off_end=offp,不会执行for循环。
(03) 此时,MediaPlayerService已经成功的添加到了Server Manager守护进程中,接下来便调用binder_pop_transaction(target_thread, in_reply_to)将事务从"target_thread的事务栈"中删除,即从MediaPlayerService线程的事务栈中删除该事务。
(04) 之后,便是设置事务的类型为BINDER_WORK_TRANSACTION,然后将其添加到target_list队列中。即,将事务添加到MediaPlayerService的待处理事务队列中。
(05) 设置待完成工作的类型为BINDER_WORK_TRANSACTION_COMPLETE,然后将其添加到thread->todo中。即,将其添加到当前线程(Service Manager守护进程的线程)的待处理事务队列中。
(06) 最后,调用wake_up_interruptible()唤醒MediaPlayerService进程。

此时,Binder驱动就将addService的反馈内容以待处理事务t的方式添加到MediaPlayerService的待处理事务队列当中,并将MediaPlayerService进程唤醒了。而对于待完成工作tcomplete,肯定是告诉ServiceManager进程,它的反馈已经被Binder驱动收到。

下面,还是先说完ServiceManager的流程,然后再来看MediaPlayerService被唤醒后做了什么。

ServiceManager执行完binder_transaction()后,回到binder_thread_write()中;此时,数据已经处理完毕,便返回到binder_ioctl()中。binder_ioctl()将数据拷贝到用户空间后,Binder驱动的工作就结束了。
于是,又回到ServiceManager守护进程中,binder_write()执行完ioctl()后,返回到binder_send_reply()中,binder_send_reply()则进一步返回到binder_parse()。binder_parse()已经解析完请求数据,于是进一步返回到binder_loop()中。而binder_loop()会再次开始循环,调用ioctl(,BINDER_WRITE_READ,)到Binder驱动执行读操作。
当ServiceManager再次进入到Binder驱动,并通过binder_ioctl()调用到binder_thread_read()时。由于此时的ServiceManager线程中有一个类型为BINDER_WORK_TRANSACTION_COMPLETE的待处理事务;于是,便取出该事务进行执行。执行完毕之后,将该事务从Service Manager的待处理事务队列中删除,并反馈cmd=BR_TRANSACTION_COMPLETE信息给ServiceManager守护进程。ServiceManager守护进程收到Binder驱动的反馈后,解析出BR_TRANSACTION_COMPLETE,该指令什么也不做;它的目的是让ServiceManager知道,此次addService的反馈已经顺利完成!
于是,ServiceManager继续它的循环;当它再次调用ioctl(),进而进入到Binder驱动中读取请求时;由于此时的待处理事务队列为空,因此,ServiceManager会再次进入中断等待状态,等待Client的请求。


至此,MediaPlayerService进程的addService的请求处理部分就讲解完了。在继续了解请求的反馈之前,先回顾一下本部分的内容。

MediaPlayerService将addService请求发送到Binder驱动,Binder驱动将addService转换成一个待处理事务并添加到ServiceManager的事务队列中,并将ServiceManager唤醒。ServiceManager被唤醒后,取出该处理;接着,Binder驱动将BR_TRANSACTION发送到ServiceManager守护进程中。ServiceManager通过BR_TRANSACTION解析出addService请求;在从请求数据中解析出MediaPlayerService的相关信息后,并将这些信息存储在一个链表中。接着,ServiceManager守护进程反馈BC_FREE_BUFFER和BC_REPLY给Binder驱动。Binder驱动收到BC_FREE_BUFFER后,释放保存事务数据的内存;在收到BC_REPLY之后,得知ServiceManager已经处理完addService请求。于是,将一个待处理事务添加到MediaPlayerService的事务队列中;然后将MediaPlayerService唤醒。目的是告诉MediaPlayerService,它已经处理完了addService请求。 最后,Binder驱动还需要反馈一个BR_TRANSACTION_COMPLETE给ServiceManager进程,目的是告诉ServiceManager,Binder驱动已经收到了它的回复。

by skywang
Previous     Next