Android:binder记录

binder是android跨进程通信的方式,现在记录一下

推荐:红茶一杯话Binder系列

为什么使用binder

linux有很多跨进程通信的方式,为什么用binder呢?
1.高效,只有一次数据拷贝的过程。(那个过程呢?)
2.安全,可以控制uid访问

binder的架构

binder架构主要包含client,servicemanager,service三个


image.png

binder中的数据结构

每个binder实体用binder_proc记录,


image.png

binder_proc有四颗红黑树。


image.png

通过binder代理句柄,在引用树上找到目标


image.png

12-14 更新

一.binder线程的创建

binder线性在应用启动时创建,通过ProcessState.startThreadPool创建。最后阻塞在IPCThreadState.talkWithDriver方法内的ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr),等待数据来临。
下面是一个kill -3 生成的一个静止apk的trace

"Binder:7560_1" prio=5 tid=9 Native
  | group="main" sCount=1 dsCount=0 obj=0x12c72ee0 self=0x7cb0ca6400
  | sysTid=7572 nice=0 cgrp=default sched=0/0 handle=0x7caf9f5450
  | state=S schedstat=( 35479847 21371615 67 ) utm=2 stm=1 core=1 HZ=100
  | stack=0x7caf8fb000-0x7caf8fd000 stackSize=1005KB
  | held mutexes=
  kernel: __switch_to+0xb8/0xc4
  kernel: binder_thread_read+0xdb4/0xf38
  kernel: binder_ioctl_write_read+0x18c/0x470
  kernel: binder_ioctl+0x298/0x628
  kernel: do_vfs_ioctl+0x4b8/0x590
  kernel: SyS_ioctl+0x60/0x88
  kernel: el0_svc_naked+0x24/0x28
  native: #00 pc 000000000006cb88  /system/lib64/libc.so (__ioctl+4)
  native: #01 pc 000000000001fc9c  /system/lib64/libc.so (ioctl+140)
  native: #02 pc 0000000000056628  /system/lib64/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+264)
  native: #03 pc 0000000000056768  /system/lib64/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+24)
  native: #04 pc 0000000000056ebc  /system/lib64/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+92)
  native: #05 pc 0000000000073a78  /system/lib64/libbinder.so (???)
  native: #06 pc 0000000000012604  /system/lib64/libutils.so (_ZN7android6Thread11_threadLoopEPv+272)
  native: #07 pc 00000000000a5650  /system/lib64/libandroid_runtime.so (_ZN7android14AndroidRuntime15javaThreadShellEPv+128)
  native: #08 pc 000000000006a664  /system/lib64/libc.so (_ZL15__pthread_startPv+208)
  native: #09 pc 000000000001dc28  /system/lib64/libc.so (__start_thread+16)
  (no managed stack frames)

打出的堆栈可以同归add2line定位到是源码的哪一行。add2line位于源码的prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin 目录。通过./x86_64-linux-android-addr2line -e libbinder.so 0000000000056628 可以定位到binder线程最后是阻塞在了ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)方法。

01-01更新

binder_ioctl_write_read函数分析

以一个进程发起binder通信为例子,发送数据时会进入binder_ioctl_write_read中,

static int binder_ioctl_write_read(struct file *filp,
                unsigned int cmd, unsigned long arg,
                struct binder_thread *thread)
{
    int ret = 0;
    struct binder_proc *proc = filp->private_data;
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;

    if (size != sizeof(struct binder_write_read)) {
        ret = -EINVAL;
        goto out;
    }
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {  //从用户空间copy数据到binder_write_read  bwr结构中
        ret = -EFAULT;
        goto out;
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
             "%d:%d write %lld at %016llx, read %lld at %016llx\n",
             proc->pid, thread->pid,
             (u64)bwr.write_size, (u64)bwr.write_buffer,
             (u64)bwr.read_size, (u64)bwr.read_buffer);

    if (bwr.write_size > 0) {
               //进入函数binder_thread_write
        ret = binder_thread_write(proc, thread,
                      bwr.write_buffer,
                      bwr.write_size,
                      &bwr.write_consumed);
        trace_binder_write_done(ret);
        if (ret < 0) {
            bwr.read_consumed = 0;
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    if (bwr.read_size > 0) {
        ret = binder_thread_read(proc, thread, bwr.read_buffer,
                     bwr.read_size,
                     &bwr.read_consumed,
                     filp->f_flags & O_NONBLOCK);
        trace_binder_read_done(ret);
        binder_inner_proc_lock(proc);
        if (!binder_worklist_empty_ilocked(&proc->todo))
            binder_wakeup_proc_ilocked(proc);
        binder_inner_proc_unlock(proc);
        if (ret < 0) {
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
             "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
             proc->pid, thread->pid,
             (u64)bwr.write_consumed, (u64)bwr.write_size,
             (u64)bwr.read_consumed, (u64)bwr.read_size);
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
out:
    return ret;
}

进入binder_thread_write

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;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;

    while (ptr < end && thread->return_error.cmd == BR_OK) {
        int ret;

        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) {         //处理客户端的命令,我们只关注BC_TRANSACTION命令
        .............
        case BC_TRANSACTION:
        case BC_REPLY: {
            struct binder_transaction_data tr;

            if (copy_from_user(&tr, ptr, sizeof(tr))) //从用户空间获取这次要传输的数据binder_transaction_data 
                return -EFAULT;
            ptr += sizeof(tr);    //更新偏移
            binder_transaction(proc, thread, &tr,  //进入binder_transaction函数
                       cmd == BC_REPLY, 0);
            break;
        }
        ............
        }
        *consumed = ptr - buffer;
    }
    return 0;
}

binder_transaction函数

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 *offp, *off_end, *off_start;
    binder_size_t off_min;
    u8 *sg_bufp, *sg_buf_end;
    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;
    struct binder_buffer_object *last_fixup_obj = NULL;
    binder_size_t last_fixup_min_off = 0;
    struct binder_context *context = proc->context;
    int t_debug_id = atomic_inc_return(&binder_last_id);

    e = binder_transaction_log_add(&binder_transaction_log);
    e->debug_id = t_debug_id;
    e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
    e->from_proc = proc->pid;
    e->from_thread = thread->pid;
    e->target_handle = tr->target.handle;
    e->data_size = tr->data_size;
    e->offsets_size = tr->offsets_size;
    e->context_name = proc->context->name;
        //根据binder_transaction_data中的描述获取target_node 目标节点
        if (tr->target.handle) {
            struct binder_ref *ref;

            /*
             * There must already be a strong ref
             * on this node. If so, do a strong
             * increment on the node to ensure it
             * stays alive until the transaction is
             * done.
             */
            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 {
                binder_user_error("%d:%d got transaction to invalid handle\n",
                          proc->pid, thread->pid);
                return_error = BR_FAILED_REPLY;
            }
            binder_proc_unlock(proc);
        } else {
            mutex_lock(&context->context_mgr_node_lock);
            target_node = context->binder_context_mgr_node;
            if (target_node)
                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);
        }


        binder_inner_proc_lock(proc);
        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;

    /* TODO: reuse incoming transaction for reply */
    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);

    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    if (tcomplete == NULL) {
        return_error = BR_FAILED_REPLY;
        return_error_param = -ENOMEM;
        return_error_line = __LINE__;
        goto err_alloc_tcomplete_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);

    t->debug_id = t_debug_id;

    if (reply)
        binder_debug(BINDER_DEBUG_TRANSACTION,
                 "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld-%lld\n",
                 proc->pid, thread->pid, t->debug_id,
                 target_proc->pid, target_thread->pid,
                 (u64)tr->data.ptr.buffer,
                 (u64)tr->data.ptr.offsets,
                 (u64)tr->data_size, (u64)tr->offsets_size,
                 (u64)extra_buffers_size);
    else
        binder_debug(BINDER_DEBUG_TRANSACTION,
                 "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld-%lld\n",
                 proc->pid, thread->pid, t->debug_id,
                 target_proc->pid, target_node->debug_id,
                 (u64)tr->data.ptr.buffer,
                 (u64)tr->data.ptr.offsets,
                 (u64)tr->data_size, (u64)tr->offsets_size,
                 (u64)extra_buffers_size);
    //构建本次transaction
    t->sender_euid = task_euid(proc->tsk);
    t->to_proc = target_proc;
    t->to_thread = target_thread;
    t->code = tr->code;
    t->flags = tr->flags;

    trace_binder_transaction(reply, t, target_node);

    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 (IS_ERR(t->buffer)) {
        /*
         * -ESRCH indicates VMA cleared. The target is dying.
         */
        return_error_param = PTR_ERR(t->buffer);
        return_error = return_error_param == -ESRCH ?
            BR_DEAD_REPLY : BR_FAILED_REPLY;
        return_error_line = __LINE__;
        t->buffer = NULL;
        goto err_binder_alloc_buf_failed;
    }
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    t->buffer->transaction = t;
    t->buffer->target_node = target_node;
    trace_binder_transaction_alloc_buf(t->buffer);
    off_start = (binder_size_t *)(t->buffer->data +
                      ALIGN(tr->data_size, sizeof(void *)));
    offp = off_start;
    //构建buffer data
    if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
               tr->data.ptr.buffer, tr->data_size)) {
        binder_user_error("%d:%d got transaction with invalid data ptr\n",
                proc->pid, thread->pid);
        return_error = BR_FAILED_REPLY;
        return_error_param = -EFAULT;
        return_error_line = __LINE__;
        goto err_copy_data_failed;
    }
    if (copy_from_user(offp, (const void __user *)(uintptr_t)
               tr->data.ptr.offsets, tr->offsets_size)) {
        binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
                proc->pid, thread->pid);
        return_error = BR_FAILED_REPLY;
        return_error_param = -EFAULT;
        return_error_line = __LINE__;
        goto err_copy_data_failed;
    }
    if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) {
        binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n",
                proc->pid, thread->pid, (u64)tr->offsets_size);
        return_error = BR_FAILED_REPLY;
        return_error_param = -EINVAL;
        return_error_line = __LINE__;
        goto err_bad_offset;
    }
    if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) {
        binder_user_error("%d:%d got transaction with unaligned buffers size, %lld\n",
                  proc->pid, thread->pid,
                  (u64)extra_buffers_size);
        return_error = BR_FAILED_REPLY;
        return_error_param = -EINVAL;
        return_error_line = __LINE__;
        goto err_bad_offset;
    }
    off_end = (void *)off_start + tr->offsets_size;
    sg_bufp = (u8 *)(PTR_ALIGN(off_end, sizeof(void *)));
    sg_buf_end = sg_bufp + extra_buffers_size;
    off_min = 0;
    for (; offp < off_end; offp++) {
        struct binder_object_header *hdr;
        size_t object_size = binder_validate_object(t->buffer, *offp);

        if (object_size == 0 || *offp < off_min) {
            binder_user_error("%d:%d got transaction with invalid offset (%lld, min %lld max %lld) or object.\n",
                      proc->pid, thread->pid, (u64)*offp,
                      (u64)off_min,
                      (u64)t->buffer->data_size);
            return_error = BR_FAILED_REPLY;
            return_error_param = -EINVAL;
            return_error_line = __LINE__;
            goto err_bad_offset;
        }

        hdr = (struct binder_object_header *)(t->buffer->data + *offp);
        off_min = *offp + object_size;
        switch (hdr->type) {
        case BINDER_TYPE_BINDER:
        case BINDER_TYPE_WEAK_BINDER: {
            struct flat_binder_object *fp;

            fp = to_flat_binder_object(hdr);
            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;
            }
        } break;
        case BINDER_TYPE_HANDLE:
        case BINDER_TYPE_WEAK_HANDLE: {
            struct flat_binder_object *fp;

            fp = to_flat_binder_object(hdr);
            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;
            }
        } break;

        case BINDER_TYPE_FD: {
            struct binder_fd_object *fp = to_binder_fd_object(hdr);
            int target_fd = binder_translate_fd(fp->fd, t, thread,
                                in_reply_to);

            if (target_fd < 0) {
                return_error = BR_FAILED_REPLY;
                return_error_param = target_fd;
                return_error_line = __LINE__;
                goto err_translate_failed;
            }
            fp->pad_binder = 0;
            fp->fd = target_fd;
        } break;
        case BINDER_TYPE_FDA: {
            struct binder_fd_array_object *fda =
                to_binder_fd_array_object(hdr);
            struct binder_buffer_object *parent =
                binder_validate_ptr(t->buffer, fda->parent,
                            off_start,
                            offp - off_start);
            if (!parent) {
                binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
                          proc->pid, thread->pid);
                return_error = BR_FAILED_REPLY;
                return_error_param = -EINVAL;
                return_error_line = __LINE__;
                goto err_bad_parent;
            }
            if (!binder_validate_fixup(t->buffer, off_start,
                           parent, fda->parent_offset,
                           last_fixup_obj,
                           last_fixup_min_off)) {
                binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
                          proc->pid, thread->pid);
                return_error = BR_FAILED_REPLY;
                return_error_param = -EINVAL;
                return_error_line = __LINE__;
                goto err_bad_parent;
            }
            ret = binder_translate_fd_array(fda, parent, t, thread,
                            in_reply_to);
            if (ret < 0) {
                return_error = BR_FAILED_REPLY;
                return_error_param = ret;
                return_error_line = __LINE__;
                goto err_translate_failed;
            }
            last_fixup_obj = parent;
            last_fixup_min_off =
                fda->parent_offset + sizeof(u32) * fda->num_fds;
        } break;
        case BINDER_TYPE_PTR: {
            struct binder_buffer_object *bp =
                to_binder_buffer_object(hdr);
            size_t buf_left = sg_buf_end - sg_bufp;

            if (bp->length > buf_left) {
                binder_user_error("%d:%d got transaction with too large buffer\n",
                          proc->pid, thread->pid);
                return_error = BR_FAILED_REPLY;
                return_error_param = -EINVAL;
                return_error_line = __LINE__;
                goto err_bad_offset;
            }
            if (copy_from_user(sg_bufp,
                       (const void __user *)(uintptr_t)
                       bp->buffer, bp->length)) {
                binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
                          proc->pid, thread->pid);
                return_error_param = -EFAULT;
                return_error = BR_FAILED_REPLY;
                return_error_line = __LINE__;
                goto err_copy_data_failed;
            }
            /* Fixup buffer pointer to target proc address space */
            bp->buffer = (uintptr_t)sg_bufp +
                binder_alloc_get_user_buffer_offset(
                        &target_proc->alloc);
            sg_bufp += ALIGN(bp->length, sizeof(u64));

            ret = binder_fixup_parent(t, thread, bp, off_start,
                          offp - off_start,
                          last_fixup_obj,
                          last_fixup_min_off);
            if (ret < 0) {
                return_error = BR_FAILED_REPLY;
                return_error_param = ret;
                return_error_line = __LINE__;
                goto err_translate_failed;
            }
            last_fixup_obj = bp;
            last_fixup_min_off = 0;
        } break;
        default:
            binder_user_error("%d:%d got transaction with invalid object type, %x\n",
                proc->pid, thread->pid, hdr->type);
            return_error = BR_FAILED_REPLY;
            return_error_param = -EINVAL;
            return_error_line = __LINE__;
            goto err_bad_object_type;
        }
    }
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    binder_enqueue_work(proc, tcomplete, &thread->todo); //将任务插入到目标proc
    t->work.type = BINDER_WORK_TRANSACTION;

        BUG_ON(t->buffer->async_transaction != 0);
        binder_inner_proc_lock(proc);  //唤醒目标线程
        t->need_reply = 1;
        t->from_parent = thread->transaction_stack;
        thread->transaction_stack = t;
        binder_inner_proc_unlock(proc);
        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;
        }


}

推荐:https://www.2cto.com/kf/201208/148770.html

Ibinder是什么?

java层的一个base接口,Binder和BinderProxy都实现了他。

Binder与parcelable的关系?

IInterface是什么?

定义binder都得实现它,只有一个方法。

/**
 * Base class for Binder interfaces.  When defining a new interface,
 * you must derive it from IInterface.
 */
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

具体用法参考:https://www.jianshu.com/p/3a7ac774c493

驱动是如何找到服务端的Binder的?

通过cookie值,cookie值就是地址。

因此,当binder_transaction_data传递到binder驱动层后,驱动层可以准确地分析出数据中到底有多少binder对象,并分别进行处理,从而产生出合适的红黑树节点。此时,如果产生的红黑树节点是binder_node的话,binder_node的cookie域会被赋值成flat_binder_object所携带的cookie值,也就是用户态的BBinder地址值啦。这个新生成的binder_node节点被插入红黑树后,会一直严阵以待,以后当它成为另外某次传输动作的目标节点时,它的cookie域就派上用场了,此时cookie值会被反映到用户态,于是用户态就拿到了BBinder对象。
参考:https://www.cnblogs.com/lzlltmf/p/5906665.html

binder传输的数据结构是怎样的?

binder_transaction_data

BpBinder的handle等于0是怎么赋值的?

defaultServiceManager -> ProcessState::getContextObject -> ProcessState::getStrongProxyForHandle

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    {
        AutoMutex _l(gDefaultServiceManagerLock);
        while (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }

    return gDefaultServiceManager;
}

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);  //这里传入了0!!!
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                // Special case for context manager...
                // The context manager is the only object for which we create
                // a BpBinder proxy without already holding a reference.
                // Perform a dummy transaction to ensure the context manager
                // is registered before we create the first local reference
                // to it (which will occur when creating the BpBinder).
                // If a local reference is created for the BpBinder when the
                // context manager is not present, the driver will fail to
                // provide a reference to the context manager, but the
                // driver API does not return status.
                //
                // Note that this is not race-free if the context manager
                // dies while this code runs.
                //
                // TODO: add a driver API to wait for context manager, or
                // stop special casing handle 0 for context manager and add
                // a driver API to get a handle to the context manager with
                // proper reference counting.

                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }

            b = new BpBinder(handle);  //生成一个代理对象
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

一次binder的通信协议流程如何?

在Binder IPC通信过程中,进程间通信都要先通过向Binder驱动发送BC_XXX命令,然后Binder 驱动稍做处理后通过对应的BR_XXX将命令转给给目标进程。

如果有返回值,进程也是先将返回结果以BC_REPLY的形式先发给Binder驱动,然后通过驱动以BR_REPLY命令转发。

image.png

PS:从Driver发出的命令以BR开始,而发往Driver的命令以BC开头。
参考:https://blog.csdn.net/fuyajun01/article/details/23028413

BC_TRANSACTION这个命令是在哪里写入的?

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;

    IF_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }

    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
       //这里写入
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }

    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }

    if ((flags & TF_ONE_WAY) == 0) {
        #if 0
        if (code == 4) { // relayout
            ALOGI(">>>>>> CALLING transaction 4");
        } else {
            ALOGI(">>>>>> CALLING transaction %d", code);
        }
        #endif
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        #if 0
        if (code == 4) { // relayout
            ALOGI("<<<<<< RETURNING transaction 4");
        } else {
            ALOGI("<<<<<< RETURNING transaction %d", code);
        }
        #endif

        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }

    return err;
}

copy_from_user 的参数是什么意思?

功能:用于将用户空间的数据传送到内核空间。
unsigned long copy_from_user(void * to, const void __user * from, unsigned long n)
第一个参数to是内核空间的数据目标地址指针,
第二个参数from是用户空间的数据源地址指针,
第三个参数n是数据的长度。
如果数据拷贝成功,则返回零;否则,返回没有拷贝成功的数据字节数。
此函数将from指针指向的用户空间地址开始的连续n个字节的数据产送到to指针指向的内核空间地址
参考:https://baike.baidu.com/item/copy_from_user/18705810

用户空间是哪个实体跟binder驱动通信?

IPCThreadState
这个对象在服务进程的Main函数初始化
/frameworks/av/media/mediaserver/main_mediaserver.cpp

 int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    InitializeIcuOrDie();
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool(); //这里初始化了
}

入口是:
IPCThreadState::talkWithDriver函数中,构造binder_write_read bwr,然后调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
进而会进入的内核空间:
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
//cmd是BINDER_WRITE_READ,arg是用户空间的binder_write_read的地址。
.....
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
.....
}
进入binder_ioctl_write_read,可以看到内核中处理的数据类型的基础就是binder_write_read结构

static int binder_ioctl_write_read(struct file *filp,
                unsigned int cmd, unsigned long arg,
                struct binder_thread *thread)
{

    struct binder_proc *proc = filp->private_data;
    void __user *ubuf = (void __user *)arg;   //用户空间数据的地址
    struct binder_write_read bwr;         //内核空间的binder_write_read
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {    //拷贝到内核空间的bwr
        ret = -EFAULT;
        goto out;
    }
    //打印一下信息
    binder_debug(BINDER_DEBUG_READ_WRITE,
             "%d:%d write %lld at %016llx, read %lld at %016llx\n",
             proc->pid, thread->pid,
             (u64)bwr.write_size, (u64)bwr.write_buffer,
             (u64)bwr.read_size, (u64)bwr.read_buffer);

    if (bwr.write_size > 0) {
        ret = binder_thread_write(proc, thread,
                      bwr.write_buffer,
                      bwr.write_size,
                      &bwr.write_consumed);
        trace_binder_write_done(ret);
        if (ret < 0) {
            bwr.read_consumed = 0;
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    if (bwr.read_size > 0) {
        ret = binder_thread_read(proc, thread, bwr.read_buffer,
                     bwr.read_size,
                     &bwr.read_consumed,
                     filp->f_flags & O_NONBLOCK);
        trace_binder_read_done(ret);
        if (!list_empty(&proc->todo))
            wake_up_interruptible(&proc->wait);
        if (ret < 0) {
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
             "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
             proc->pid, thread->pid,
             (u64)bwr.write_consumed, (u64)bwr.write_size,
             (u64)bwr.read_consumed, (u64)bwr.read_size);
    //返回给用户空间的binder_write_read结构
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
out:
    return ret;
}

被打扁的binder对象是怎么传输到binder驱动的?

BC_REGISTER_LOOPER干了什么事情?

将一个线程加入binder线程池会发送这个命令。
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
在驱动中只是设置一个值
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;

返回用户空间是什么呢?
是BR_NOOP
参考https://blog.csdn.net/bob_fly1984/article/details/79836789
https://blog.csdn.net/yangwen123/article/details/9254827

应用间的binder通信又是怎么建立的呢?

通过binderservice方式,会通知AMS拉起服务,注册binder实体,然后返回binder代理给客户端。

binder 共享内存 拷贝次数

共享内存0次,binder一次,binder只在客户端到内核拷贝一次,服务端跟内核是通过共享内存实现的。

进程内核空间是什么?

就是跑着内核代码的地址。

门面模式是什么?

就是把很多的动作,例如开灯,开音乐等放在一个函数里面,这个函数就是相当与是门面函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容