您的位置:首页 > 其它

binder 发送 BINDER_WRITE_READ 过程

2016-07-26 20:53 555 查看
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

    ...

    switch (cmd) {

    case BINDER_WRITE_READ: {

        struct binder_write_read bwr;

        if (size != sizeof(struct binder_write_read)) {

            ret = -EINVAL;

            goto err;

        }

        if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {

            ret = -EFAULT;

            goto err;

        }

        ...

        if (bwr.write_size > 0) {

            ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);

        ...

        }

        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 (!list_empty(&proc->todo))

                wake_up_interruptible(&proc->wait);

        ...

        }

        ...

        if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

            ret = -EFAULT;

            goto err;

        }

        break;

    }

    ...

    return ret;

}

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;

    while (ptr < end && thread->return_error == BR_OK) {

        if (get_user(cmd, (uint32_t __user *)ptr)) //从用户空间获得命令的类型

        switch (cmd) {

        ...

        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);// 处理 BC_TRANSACTION,BC_REPLY

            break;

        }

        ...

        *consumed = ptr - buffer;

    }

    return 0;

}

static void binder_transaction(struct binder_proc *proc,

                   struct binder_thread *thread,

                   struct binder_transaction_data *tr, int reply)

{

    ...

    if (target_thread) {

        e->to_thread = target_thread->pid;

        target_list = &target_thread->todo;

        target_wait = &target_thread->wait;

    } else {

        target_list = &target_proc->todo;

        target_wait = &target_proc->wait;

    }

    ...

    if (reply) {

        binder_pop_transaction(target_thread, in_reply_to);

    } else if (!(t->flags & TF_ONE_WAY)) {

        t->need_reply = 1;

        t->from_parent = thread->transaction_stack; // 传输的真实数据 binder_transaction

        thread->transaction_stack = t;

    ...

    t->work.type = BINDER_WORK_TRANSACTION;

    list_add_tail(&t->work.entry, target_list); //添加到目标线程的todo工作队列

    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;

    list_add_tail(&tcomplete->entry, &thread->todo);//添加到命令发起者的todo工作队列

    if (target_wait)

        wake_up_interruptible(target_wait); //唤醒目标 server 正在 binder_thread_read 等待的目标线程

    return;

}

static int binder_thread_read(struct binder_proc *proc,

                  struct binder_thread *thread,

                  void  __user *buffer, int size,

                  signed long *consumed, int non_block)

{

    void __user *ptr = buffer + *consumed;

    void __user *end = buffer + size;

    ...

            ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));//睡眠等待 todo 中的数据

    ...

    while (1) {

        uint32_t cmd;

        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)

            w = list_first_entry(&proc->todo, struct binder_work, entry);

        ...

        switch (w->type) {

        case BINDER_WORK_TRANSACTION: {

            t = container_of(w, struct binder_transaction, work);

        } break;

        case BINDER_WORK_TRANSACTION_COMPLETE: {

            cmd = BR_TRANSACTION_COMPLETE;

            if (put_user(cmd, (uint32_t __user *)ptr))

                return -EFAULT;

            ptr += sizeof(uint32_t);

        ...

        } break;

        ...

        // 填充 binder_transaction_data 数据

        if (t->buffer->target_node) {

        ...

            tr.target.ptr = target_node->ptr;

            tr.cookie =  target_node->cookie;

        ...

            cmd = BR_TRANSACTION;//cmd BR_TRANSACTION

        } else {

            tr.target.ptr = NULL;

            tr.cookie = NULL;

            cmd = BR_REPLY;//cmd BR_REPLY

        }

        ...

        //从todo队列中读取的数据拷贝到用户空间

        if (put_user(cmd, (uint32_t __user *)ptr))

            return -EFAULT;

        ptr += sizeof(uint32_t);

        if (copy_to_user(ptr, &tr, sizeof(tr)))

            return -EFAULT;

        ptr += sizeof(tr);

    ...

    *consumed = ptr - buffer;

    ...

    return 0;

}

binder 通信数据请求过程

1.BC_TRANSACTION        //客户端第一次通过 binder驱动 向目标服务端的 todo队列 和本地调用者线程的 todo队列,添加工作项数据,再唤醒服务端的read()

                //在唤醒服务端后,继续执行本地的read(),处理上面添加到本地todo的任务项数据(BR_TRANSACTION_COMPLETE)

2.BR_TRANSACTION        //服务端 ioctl 里的 read()函数被唤醒后,会向自己的用户空间发送 BR_TRANSACTION 操作,

                //此时服务端的用户空间就实现了RPC调用,得到返回结果后再向binder驱动发送(BC_REPLY),把数据传递到内核空间

3.BR_TRANSACTION_COMPLETE    //客户端处理本地todo,此时会将数据传递到用户空间,意思是我们会跳出binder_ioctl函数返回到用户空间,

                //很快由于while(1)我们会第二次进入到内核空间,在read()函数中等待服务端的处理结果

4.BC_REPLY            //BR_TRANSACTION 命令后,经过一段时间服务端的数据已经处理完成,服务端的用户空间向内核空间发送 BC_REPLY,

                //将处理好的数据传回给binder驱动,将工作项数据添加到目标客户的todo,再唤醒等待的客户端

5.BR_REPLY            //客户端被唤醒后,是在客户端内核空间 read() 函数中处理 BR_REPLY 命令,然后将数据客户端的用户空间,

                //这样客户端就拿到了服务端的处理数据,IPC就完成了

6.BR_TRANSACTION_COMPLETE    //同上面一样,这时候只是 服务端处理本地todo工作项,同样也返回到用户空间,

                //又会第二次进入到 ioctl 的 read()函数中,等待新的 client 的请求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: