我理解的Binder通信机制(二)——数据发送与数据获取

1,470 阅读20分钟

上一篇《我理解的Binder通信机制(一)——Binder通信通道的建立》【2】(标注一下,本文后面的篇幅中会经常提到上一篇的内容,这里标注为【2】)中介绍了Binder通道的建立过程。通道建立以后,就可以在其中进行数据传输了,所以,这一篇接着说基于这个通道的数据发送与数据获取过程,这里说的数据发送是指server进程(作为client)向servermanager进程(作为server)注册系统服务;数据获取是指client进程(作为client)向servermanager进程(作为server)获取系统服务,属于系统级的数据通信。

0 前言

刚开始研究Binder机制的时候,主要看一些关于framework的书籍。其中,讲解到Binder机制时,都是以具体的系统服务的注册及获取过程来说明。心中一直存在一个疑问:为什么要以系统服务来讲解Binder机制,服务和Binder之间有什么关系吗?直到看到addService方法中变量service的类型IBinder,才反应过来,其实,系统服务本身就是Binder类型,当然可以以系统注册、获取过程来作为切入点研究Binder通信机制。OK,闲话扯完,进入主题。

一、数据发送之注册服务
1 进入内核前的处理

还是以具体的系统服务来研究这一过程的细节。先来看一下addService方法。

/**
 * @param name 服务名称
 * @param service 具体的服务
 */
 @UnsupportedAppUsage
 public static void addService(String name, IBinder service, boolean allowIsolated,
            int dumpPriority) {
    try {
         getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
    } catch (RemoteException e) {
         Log.e(TAG, "error in addService", e);
    }
 }

getIServiceManager方法还是一个IPC的过程。整个Binder机制是由上到下,由Java到Native,层层调用,本文略去Java层的调用细节,直接定位Native层BpServiceManager的addService方法

class IServiceManager.cpp::BpServiceManager
------------------
virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated) {
    //Parcel是数据通信包
    Parcel data, reply; 
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());   
    data.writeString16(name);      
    data.writeStrongBinder(service); 
    data.writeInt32(allowIsolated ? 1 : 0); 
    //remote()指向的是BpBinder对象
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}
1.1 Parcel#writeStrongBinder
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}
1.1.1 flatten_binder
status_t flatten_binder(const sp<ProcessState>& proc,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        //本地Binder不为空
        IBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0;
            obj.handle = handle;
            obj.cookie = 0;
        } else { //进入该分支
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        ...
    }
    return finish_flatten_binder(binder, obj, out);
}

flatten_binder函数的作用主要是将IBinder类型的对象转化为flat_binder_object类型的对象。所以,binder是以flat_binder_object的形式在进程间传递。从函数名称上可以推断出来,该函数将binder flat了一下。这是个什么效果呢?可以想象一下,在球场的大叔大妈捡到易拉罐的第一个动作是什么?没错,啪,给一脚,踩扁,就是flat了一下。易拉罐还是易拉罐,只是外形发生了变化,放到binder这里也是一样的道理。

1.2 BpBinder::transact

在transact之前,先看一下remote()函数,

class BpRefBase : public virtual RefBase
{
protected:
    explicit                BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase();
    ...
    inline  IBinder*        remote()                { return mRemote; }
    inline  IBinder*        remote() const          { return mRemote; }

private:
    IBinder* const          mRemote;
    ...
};

【2】最后的4.4.2小节可知,BpRefBase中mRemote变量存储的是BpBinder对象。

remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

这样就相当于

new BpBinder->transact(ADD_SERVICE_TRANSACTION, data, &reply);

来看一下该方法

status_t BpBinder::transact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
                mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}
1.2.1 IPCThreadState::self
IPCThreadState* IPCThreadState::self()
{
    if (gHaveTLS.load(std::memory_order_acquire)) {
        restart:
        const pthread_key_t k = gTLS;
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;

        //初始IPCThreadState
        return new IPCThreadState;
    }

    // Racey, heuristic test for simultaneous shutdown.
    if (gShutdown.load(std::memory_order_relaxed)) { 
        return nullptr;
    }

    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS.load(std::memory_order_relaxed)) {
        //创建线程的TLS
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
        if (key_create_value != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return nullptr;
        }
        gHaveTLS.store(true, std::memory_order_release);
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

IPCThreadState构造方法中的逻辑有些不懂,直接引用gityuan.com/2015/11/14/…的一段话。

TLS是指Thread local storage(线程本地储存空间),每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。通过pthread_getspecific / pthread_setspecific函数可以获取、设置这些空间中的内容。从线程本地存储空间中获得保存在其中的IPCThreadState对象。

1.2.2 IPCThreadState::transact
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err;
    flags |= TF_ACCEPT_FDS;
    //此时,code为ADD_SERVICE_TRANSACTION
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }

    ...
    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        ...

    } else {
        err = waitForResponse(nullptr, nullptr);
    }
    return err;
}

该方法中主要做了两部分工作:writeTransactionData、waitForResponse。从方法名也可以知道,writeTransactionData在写入数据,继续往下看,

1.3 writeTransactionData
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
                                              int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    binder_transaction_data tr;

    //填充binder_transaction_data
    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    //检查数据
    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        //填充binder_transaction_data
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();

        //在binder_transaction_data数据包中存储binder(实体或引用)。
        //可能存多个binder,所以,offsets_size表示binder数组的大小
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        //binder在binder_transaction_data数据包中的偏移量
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    //cmd为BC_TRANSACTION,写入parcel mOut中
    mOut.writeInt32(cmd);
    //数据包写入parcel mOut中
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

writeTransactionData方法也很好理解,简单的说,就是在填充传输的数据包binder_transaction_data。其中,可以包含数据、binder,相当于在flat_binder_object外面又包了一层。参数offsets_size和data.ptr.offsets标识出了binder(实体或引用)在数据包中的大小、位置,这样在进程间传输中,目标进程可以根据这两个变量,从中提取出binder,完成binder的进程间传递。最后,把Binder命令BC_TRANSACTION和binder_transaction_data结构体写入到parcel类型的变量mOut中。这里注意一下,数据包写入mOut后会在被用到时取出来。

1.4 waitForResponse
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
    //无限循环
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;

        //读取命令
        cmd = (uint32_t)mIn.readInt32();

        switch (cmd) {
            case BR_TRANSACTION_COMPLETE:
                ...
            case BR_DEAD_REPLY:
                ...
            case BR_FAILED_REPLY:
                ...
            case BR_ACQUIRE_RESULT:
                ...
            case BR_REPLY:
                ...
            default:
                err = executeCommand(cmd);
                if (err != NO_ERROR) goto finish;
                break;
        }
    }

    finish:
        ...
    return err;
}

waitForResponse方法刚开始就进入一个while的无限循环,其中,第一个if判断talkWithDriver,

1.5 talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive) {

    ...
    binder_write_read bwr;
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    /* 要么读,要么写 */
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;

    //调用栈 IPCThreadState::transact -> writeTransactionData
    //还记得在writeTransactionData函数中binder_transaction_data写入了mOut吗?
    //将mOut.data封装进binder_write_read
    bwr.write_buffer = (uintptr_t) mOut.data();

    //需要读数据
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t) mIn.data();
    } else {
        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 {
        //调用ioctl函数同binder驱动进行数据交互
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;

        if (mProcess->mDriverFD < 0) {
            err = -EBADF;
        }
    } while (err == -EINTR);
    return err;
}

还记得在1.3小节writeTransactionData方法中binder_transaction_data写入了mOut中吗?talkWithDriver方法中将mOut.data封装进binder_write_read中,然后调用ioctl函数同binder驱动进行数据交互。

截至目前,我们看一下binder在从应用层到binder驱动传输过程中发生了哪些变化:IBinder -> flat_binder_object -> binder_transaction_data -> parcel.mData -> binder_write_read

2 调用ioctl函数进入Binder驱动

Binder驱动和应用程序之间定义了一套接口协议,主要功能由ioctl()接口实现,不提供read(),write()接口,因为ioctl()灵活方便,且能够一次调用实现先写后读以满足同步交互,而不必分别调用write()和read()。

ioctl函数调用进入内核,调用binder_ioctl,

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

    switch (cmd) {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread);
            if (ret)
                goto err;
            break
            ...
    }
    ret = 0;
    ...
    return ret;
}

binder_ioctl走分支BINDER_WRITE_READ,调用binder_ioctl_write_read

2.2 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;
    //当前情形下,binder_proc表示smgr进程
    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 (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }

    //bwr.write_size大于0表示向内核缓冲区写入数据
    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;
        }
    }
    //bwr.read_size大于0表示从内核缓冲区读取数据
    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;
        }
    }

    // 从内核缓冲区拷贝数据到用户空间
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    out:
    return ret;
}

先来看一下copy_from_user和copy_to_user函数

2.2.1 copy_from_user & copy_to_user
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)

该函数是从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0。函数参数如下,

  • void *to 内核地址
  • const void __user *from 用户空间地址
  • unsigned long n 数据大小
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)

该函数是从内核空间拷贝数据到用户空间,失败返回没有拷贝成功的数据字节数,成功返回0。函数参数如下,

  • void __user *to 用户空间地址
  • const void *from 内核地址
  • long n 数据大小

binder_ioctl_wrtie_read函数会从用户空间拷贝数据到内核,数据存放在bwr,然后根据bwr中的write_size、read_size来判断向内核缓冲区写入数据,还是从内核缓冲区中读取数据。当前情形下,向内核写入数据,所以调用binder_thread_write。

2.3 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;
    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 == BR_OK) {
        //拷贝用户空间的cmd命令,此时为BC_TRANSACTION
        if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
        ptr += sizeof(uint32_t);
        switch (cmd) {
        case BC_TRANSACTION:
        case BC_REPLY: {
            struct binder_transaction_data tr;
            //拷贝用户空间的binder_transaction_data
            if (copy_from_user(&tr, ptr, sizeof(tr)))   return -EFAULT;
            ptr += sizeof(tr);
            binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
            break;
        }
        ...
    }
    *consumed = ptr - buffer;
  }
  return 0;
}
2.4 binder_transaction
/**
 *
 * @param proc    binder所在的进程
 * @param thread  binder所在线程
 * @param tr      binder_transaction_data 数据包
 * @param reply   是否需要reply
 */
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;
    binder_size_t *offp, *off_end;
    binder_size_t off_min;
    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) {
        ...
    } else {
        //tr->target.handle非0
        if (tr->target.handle) {
            ...
        }
            //当前在注册服务,target.handle为0。
            //进入else分支
        else {
            //目标binder为servicemanager实体
            target_node = binder_context_mgr_node;
            ...
        }
        //目标为servicemanager进程
        target_proc = target_node->proc;
        ...
    }

    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;
    }
    e->to_proc = target_proc->pid;

    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...
    //binder_work类型
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...

    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;

    t->sender_euid = task_euid(proc->tsk);
    t->to_proc = target_proc;
    t->to_thread = target_thread;
    t->code = tr->code; //code为ADD_SERVICE_TRANSACTION
    t->flags = tr->flags;
    t->priority = task_nice(current);

    trace_binder_transaction(reply, t, target_node);

    //从servicemanager进程中分配buffer
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
                                 tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    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);
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);

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

    //拷贝用户空间的binder_transaction_data中ptr.buffer到内核
    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;
        //goto err_copy_data_failed;
    }

    //拷贝用户空间的binder_transaction_data中ptr.offsets到内核
    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;
        //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;
        goto err_bad_offset;
    }


    off_end = (void *) offp + tr->offsets_size;
    off_min = 0;
    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;

        if (*offp > t->buffer->data_size - sizeof(*fp) ||
            *offp < off_min ||
            t->buffer->data_size < sizeof(*fp) ||
            !IS_ALIGNED(*offp, sizeof(u32))) {
            binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
                              proc->pid, thread->pid, (u64) * offp,
                              (u64) off_min,
                              (u64)(t->buffer->data_size -
                                    sizeof(*fp)));
            return_error = BR_FAILED_REPLY;
            goto err_bad_offset;
        }

        /* 解析数据binder_transaction_data中可能携带的binder,
         * flat_binder_object是binder在进程间传输形式 */
        fp = (struct flat_binder_object *) (t->buffer->data + *offp);

        off_min = *offp + sizeof(struct flat_binder_object);


        /*
         *判断数据中的binder的类型
         */
        switch (fp->type) {

            //binder_node是binder实体在binder驱动中的存在形式
            case BINDER_TYPE_BINDER:
            case BINDER_TYPE_WEAK_BINDER: {
                struct binder_ref *ref;

                //binder驱动中维护的binder_node红黑树中是否包含该binder实体
                struct binder_node *node = binder_get_node(proc, fp->binder);
                if (node == NULL) {
                    //不在红黑树中,则创建一个
                    node = binder_new_node(proc, fp->binder, fp->cookie);
                    if (node == NULL) {
                        return_error = BR_FAILED_REPLY;
                        goto err_binder_new_node_failed;
                    }
                    node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                    node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
                }
                if (fp->cookie != node->cookie) {
                    binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
                                      proc->pid, thread->pid,
                                      (u64) fp->binder, node->debug_id,
                                      (u64) fp->cookie, (u64) node->cookie);
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }
                if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }

                //查找该binder实体对应的binder引用
                ref = binder_get_ref_for_node(target_proc, node);
                if (ref == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }
                if (fp->type == BINDER_TYPE_BINDER)
                    fp->type = BINDER_TYPE_HANDLE;
                else
                    fp->type = BINDER_TYPE_WEAK_HANDLE;
                fp->handle = ref->desc;
                //binder引用次数+1
                binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                               &thread->todo);

                trace_binder_transaction_node_to_ref(t, node, ref);

            }
                break;

                //类型为binder引用
            case BINDER_TYPE_HANDLE:
            case BINDER_TYPE_WEAK_HANDLE: {

                //维护binder引用对应的红黑树中查找该binder引用
                struct binder_ref *ref = binder_get_ref(proc, fp->handle);

                if (ref == NULL) {
                    binder_user_error("%d:%d got transaction with invalid handle, %d\n",
                                      proc->pid,
                                      thread->pid, fp->handle);
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_failed;
                }

                if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_failed;
                }

                //判断binder引用的对应实体所在的进程是否是目标进程,
                //如果为binder所属的进程,则将flat_binder_object的类型设置为binder实体节点
                if (ref->node->proc == target_proc) {
                    if (fp->type == BINDER_TYPE_HANDLE)
                        fp->type = BINDER_TYPE_BINDER;
                    else
                        fp->type = BINDER_TYPE_WEAK_BINDER;
                    fp->binder = ref->node->ptr;
                    fp->cookie = ref->node->cookie;
                    //计数+1
                    binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
                    trace_binder_transaction_ref_to_node(t, ref);
                    binder_debug(BINDER_DEBUG_TRANSACTION,
                                 "        ref %d desc %d -> node %d u%016llx\n",
                                 ref->debug_id, ref->desc, ref->node->debug_id,
                                 (u64) ref->node->ptr);
                }
                //进程号不匹配,则还是使用binder引用
                else {
                    struct binder_ref *new_ref;

                    new_ref = binder_get_ref_for_node(target_proc, ref->node);
                    if (new_ref == NULL) {
                        return_error = BR_FAILED_REPLY;
                        goto err_binder_get_ref_for_node_failed;
                    }
                    fp->handle = new_ref->desc;
                    //binder引用计数+1
                    binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                    trace_binder_transaction_ref_to_ref(t, ref, new_ref);
                }
            }
                break;

            case BINDER_TYPE_FD: {
                ...

            default:
                binder_user_error("%d:%d got transaction with invalid object type, %x\n",
                                  proc->pid, thread->pid, fp->type);
                return_error = BR_FAILED_REPLY;
                goto err_bad_object_type;
        }
    }
    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;
        thread->transaction_stack = t;
    } else {
        if (target_node->has_async_transaction) {
            target_list = &target_node->async_todo;
            target_wait = NULL;
        } else
            target_node->has_async_transaction = 1;
    }

    t->work.type = BINDER_WORK_TRANSACTION;
    list_add_tail(&t->work.entry, target_list);
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    list_add_tail(&tcomplete->entry, &thread->todo);
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;

}

binder_transaction函数内容比较多,首要工作就是要确定目标进程的信息,诸如target_node、target_proc等。然后,在目标进程中分配缓冲区,用来接收传递的数据。注意到有copy_from_user函数的调用,将用户空间中与binder有关的offsets, offsets_size拷贝到内核中,为要添加的flat_binder_object做准备。根据flat_binder_object的类型来确定传递的binder是实体节点还是引用。最后,向servicemanager的binder_proc->todo添加BINDER_WORK_TRANSACTION事务。

2.4.1 binder_get_node
 static struct binder_node *binder_get_node(struct binder_proc *proc,
											binder_uintptr_t ptr)
 {
	 struct rb_node *n = proc->nodes.rb_node;
	 struct binder_node *node;

	 //红黑树中查找ptr为索引的binder节点,找到返回;没找到返回NULL;
	 while (n) {
		 node = rb_entry(n, struct binder_node, rb_node);

		 if (ptr < node->ptr)
			 n = n->rb_left;
		 else if (ptr > node->ptr)
			 n = n->rb_right;
		 else
			 return node;
	 }
	 return NULL;
 }

binder_get_node会从server进程中维护的binder_node类型的红黑树中查找以ptr为索引的binder节点,ptr为binder在用户空间的指针。如果没找到就创建一个新节点添加到树中。此时,会调用binder_new_node函数,

2.4.2 binder_new_node
static struct binder_node *binder_new_node(struct binder_proc *proc,
											binder_uintptr_t ptr,
											binder_uintptr_t cookie)
 {
	 struct rb_node **p = &proc->nodes.rb_node;
	 struct rb_node *parent = NULL;
	 struct binder_node *node;

	 //先在红黑树位置查找,找不到则创建
	 while (*p) {
		 parent = *p;
		 node = rb_entry(parent, struct binder_node, rb_node);

		 if (ptr < node->ptr)
			 p = &(*p)->rb_left;
		 else if (ptr > node->ptr)
			 p = &(*p)->rb_right;
		 else
			 return NULL;
	 }

	 //分配空间
	 node = kzalloc(sizeof(*node), GFP_KERNEL);
	 if (node == NULL)
		 return NULL;
	 binder_stats_created(BINDER_STAT_NODE);

	 //将新建的node链接到红黑树
	 rb_link_node(&node->rb_node, parent, p);
	 rb_insert_color(&node->rb_node, &proc->nodes);
	 //node信息设置
	 node->debug_id = ++binder_last_id;
	 node->proc = proc;
	 node->ptr = ptr;
	 node->cookie = cookie;
	 node->work.type = BINDER_WORK_NODE;
	 INIT_LIST_HEAD(&node->work.entry);
	 INIT_LIST_HEAD(&node->async_todo);
	 return node;
 }
2.4.3 binder_get_ref_for_node
 //获取binder实体节点对应的binder引用
 static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
												   struct binder_node *node)
 {
	 struct rb_node *n;
	 struct rb_node **p = &proc->refs_by_node.rb_node;
	 struct rb_node *parent = NULL;
	 struct binder_ref *ref, *new_ref;

	 //在红黑树rb_node_node中查找binder_node对应的binder_ref
	 while (*p) {
		 parent = *p;
		 ref = rb_entry(parent, struct binder_ref, rb_node_node);

		 if (node < ref->node)
			 p = &(*p)->rb_left;
		 else if (node > ref->node)
			 p = &(*p)->rb_right;
		 else
			 return ref;
	 }

	 //为新创建的binder_ref分配空间
	 new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
	 if (new_ref == NULL)
		 return NULL;

	 //新建binder_ref
	 binder_stats_created(BINDER_STAT_REF);
	 new_ref->debug_id = ++binder_last_id;
	 new_ref->proc = proc;
	 new_ref->node = node;
	 //链接到rb_node_node红黑树中
	 rb_link_node(&new_ref->rb_node_node, parent, p);
	 rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);

	 //新建的binder引用如果对应servicemanager,其desc变量为0,否则为1。
	 new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1;
	 for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
		 ref = rb_entry(n, struct binder_ref, rb_node_desc);
		 if (ref->desc > new_ref->desc)
			 break;
		 new_ref->desc = ref->desc + 1;
	 }

	 p = &proc->refs_by_desc.rb_node;

	 //rb_node_desc同样是一个红黑树,
	 //以binder_ref的desc域为索引维护的一个binder_ref红黑树
	 while (*p) {
		 parent = *p;
		 ref = rb_entry(parent, struct binder_ref, rb_node_desc);

		 if (new_ref->desc < ref->desc)
			 p = &(*p)->rb_left;
		 else if (new_ref->desc > ref->desc)
			 p = &(*p)->rb_right;
		 else
			 BUG();
	 }

	 //链接到rb_node_desc红黑树中
	 rb_link_node(&new_ref->rb_node_desc, parent, p);
	 rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);

	 if (node) {
		 hlist_add_head(&new_ref->node_entry, &node->refs);

	 }
	 return new_ref;
 }

binder_get_ref_for_node函数主要工作就是获取binder实体节点对应的binder引用。研究其逻辑可以知道,进程中维护着两个红黑树 rb_node_node、rb_node_desc。两个都是维护着binder引用的红黑树,不同的是,rb_node_node是以binder节点在驱动中的地址为索引;rb_node_desc是以引用号(即结构的desc域)为索引。

binder_transaction正确执行后,我们接着看binder_thread_write的逻辑,之后跳出switch,binder_thread_write函数返回0,表示操作成功。binder_ioctl_write_read接到返回值后,就会将操作后的数据从内核拷贝回用户空间,并返回0。

    binder_ioctl_write_read函数
    // 从内核缓冲区拷贝数据到用户空间
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }

上层函数talkWithDriver中,

 do {
        //调用ioctl函数同binder驱动进行数据交互
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;

        if (mProcess->mDriverFD < 0) {
            err = -EBADF;
        }
    } while (err == -EINTR);

ioctl函数返回值 == 0,err被赋值为NO_ERROR,接着返回err给上层调用函数。这样一次单向的数据传输完成,至于需不需要reply,看上层调用。

3 servicemanager处理IPC请求

在【2】中3.3小节中提到,servicemanager作为一个server进程,为了应对来自client进程的请求,servicemanager在binder_loop会进入一个无限循环等待处理client进程的IPC请求。但是进入无限循环中没有继续研究细节,现在来看一下。

在for循环中,调用ioctl函数与binder驱动交互,结果就是从binder驱动中读取IPC请求数据。当ioctl返回后,便通过binder_parse方法解析返回数据。binder驱动可以返回多种BR指令给servicemanager,其中BR_TRANSACTION指令用于注册和获取服务。

3.1 binder_parse
int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func) {
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
        //读取BR命令
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);

        switch (cmd) {
            ...

            case BR_TRANSACTION: {
                struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
                if ((end - ptr) < sizeof(*txn)) {
                    ALOGE("parse: txn too small!\n");
                    return -1;
                }
                binder_dump_txn(txn);
                if (func) {
                    unsigned rdata[256 / 4];
                    //binder驱动发送给当前进程的IPC数据
                    struct binder_io msg;
                    //要写入Binder驱动的IPC数据
                    struct binder_io reply;
                    int res;
                    //初始化IPC数据
                    bio_init(&reply, rdata, sizeof(rdata), 4);
                    bio_init_from_txn(&msg, txn);
                    //调用func处理BC_TRANSACTION指令,处理结果保存在reply中
                    res = func(bs, txn, &msg, &reply);

                    //oneway
                    if (txn->flags & TF_ONE_WAY) {
                        binder_free_buffer(bs, txn->data.ptr.buffer);
                    }
                        //需要reply,将处理结果返回给binder驱动程序
                    else {
                        binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                    }
                }
                ptr += sizeof(*txn);
                break;
            }
                ...

            default:
                ALOGE("parse: OOPS %d\n", cmd);
                return -1;
        }
    }
    return r;
}

func实参由binder_loop传入,

  binder_loop(bs, svcmgr_handler);

binder驱动发送给servicemanager的BR_TRANSACTION指令便由该函数处理,看一下

3.2 svcmgr_handler
 int svcmgr_handler(struct binder_state *bs,
   struct binder_transaction_data *txn,
   struct binder_io *msg,
   struct binder_io *reply)
{
	struct svcinfo *si;
	uint16_t *s;
	size_t len;
	uint32_t handle;
	uint32_t strict_policy;
	int allow_isolated;
	uint32_t dumpsys_priority;

	strict_policy = bio_get_uint32(msg);
	s = bio_get_string16(msg, &len);
	...

	switch(txn->code) {
		//获取service
		case SVC_MGR_GET_SERVICE:
		case SVC_MGR_CHECK_SERVICE:
			s = bio_get_string16(msg, &len);
			if (s == NULL) {
				return -1;
			}
			handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
			if (!handle)
				break;
			bio_put_ref(reply, handle);
			return 0;

		//注册服务
		case SVC_MGR_ADD_SERVICE:
		
			//服务名称
			s = bio_get_string16(msg, &len);
			if (s == NULL) {
				return -1;
			}
			handle = bio_get_ref(msg);
			allow_isolated = bio_get_uint32(msg) ? 1 : 0;
			dumpsys_priority = bio_get_uint32(msg);
			if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid))
				return -1;
			break;

		case SVC_MGR_LIST_SERVICES: {
			uint32_t n = bio_get_uint32(msg);
			uint32_t req_dumpsys_priority = bio_get_uint32(msg);

			if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
				ALOGE("list_service() uid=%d - PERMISSION DENIED\n",txn->sender_euid);
				return -1;
			}
			si = svclist;
			// walk through the list of services n times skipping services that do not support the requested priority
			while (si) {
				if (si->dumpsys_priority & req_dumpsys_priority) {
					if (n == 0) break;
					n--;
				}
				si = si->next;
			}
			if (si) {
				bio_put_string16(reply, si->name);
				return 0;
			}
			return -1;
		}
		default:
			ALOGE("unknown code %d\n", txn->code);
			return -1;
	}

	bio_put_uint32(reply, 0);
	return 0;
}

在SVC_MGR_GET_SERVICE、SVC_MGR_ADD_SERVICE分支下分别调用do_find_service、do_add_service函数,这是在获取服务、注册服务过程中会调用的函数。这一部分研究服务注册,那就先看do_add_service

3.3 do_add_service
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
	 struct svcinfo *si;

	 if (!handle || (len == 0) || (len > 127))
		 return -1;

	 //是否有权限被注册为service
	 if (!svc_can_register(s, len, spid, uid)) {
		 ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
			   str8(s, len), handle, uid);
		 return -1;
	 }

	 //在servicelist中查找s是否已被注册
	 si = find_svc(s, len);
	 if (si) {
		 if (si->handle) {
			 ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
				   str8(s, len), handle, uid);
			 svcinfo_death(bs, si);
		 }
		 si->handle = handle;
	 }
	 //服务注册
	 else {
		 si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
		 if (!si) {
			 ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
				   str8(s, len), handle, uid);
			 return -1;
		 }
		 si->handle = handle;
		 si->len = len;
		 memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
		 si->name[len] = '\0';
		 si->death.func = (void*) svcinfo_death;
		 si->death.ptr = si;
		 si->allow_isolated = allow_isolated;
		 si->dumpsys_priority = dumpsys_priority;
		 //系统服务以链表的形式保存
		 si->next = svclist;
		 svclist = si;
	 }

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

do_add_service函数的逻辑不难理解,值得注意的是,系统服务是以链表的形式保存。 顺便看一下do_find_service,

3.4 do_find_service
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
 {
	//从servicelist中查找s
	 struct svcinfo *si = find_svc(s, len);
	 ...
	 return si->handle;
 }
3.5 find_svc
struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
    struct svcinfo *si;

    for (si = svclist; si; si = si->next) {
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            return si;
        }
    }
    return NULL;
}

逻辑也比较简单,就不展开说了。

二、数据获取之系统服务获取

我们还是从IServiceManger::BpServiceManager的getService函数开始看起,

virtual sp<IBinder> getService(const String16& name) const{
    static bool gSystemBootCompleted = false;
    //检索已有服务
    sp<IBinder> svc = checkService(name);
    if (svc != nullptr) return svc;
    
    const long timeout = uptimeMillis() + 5000;
    ...
    const long sleepTime = gSystemBootCompleted ? 1000 : 100;

    int n = 0;
    //等待该服务启动5s
    while (uptimeMillis() < timeout) {
        n++;
        usleep(1000*sleepTime);
        sp<IBinder> svc = checkService(name);
        if (svc != nullptr) return svc;
    }
    //该服务仍未启动,返回nullptr
    return nullptr;
}

getService函数会先从已有服务中去检索要获取的服务,检索到直接返回,否则,会等待5s,这5s期间会不断去检索,检索到就返回。如果5s后,服务仍旧未启动,则返回nullptr。接下来重点就是checkService函数。

函数里面的内容就相对熟悉一些,下面我们不再对已在上面讲过的方法进行讲解,但还是列出调用顺序。

BpBinder::transact

IPCThreadState::self

IPCThreadState::transact

writeTransactionData

waitForResponse

talkWithDriver

ioctl

binder_ioctl

binder_ioctl_write_read

老实说,获取服务的过程中还有一些东西没理清,所以这里先搁置一下,等后续补充。

接下来,看一下parcel::readStrongBinder

1.1 readStrongBinder
sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    readNullableStrongBinder(&val);
    return val;
}

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
    return unflattenBinder(val);
}
1.2 unflattenBinder
status_t Parcel::unflattenBinder(sp<IBinder>* out) const{

    //从parcel中取出flat_binder_object,也就是binder,
    //至于是binder实体还是binder引用,需要接着判断
    const flat_binder_object* flat = readObject(false);

    if (flat) {
        switch (flat->hdr.type) {
            case BINDER_TYPE_BINDER: {
                sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
                return finishUnflattenBinder(binder, out);
            }
            case BINDER_TYPE_HANDLE: {
                sp<IBinder> binder =
                        ProcessState::self()->getStrongProxyForHandle(flat->handle);
                return finishUnflattenBinder(binder, out);
            }
        }
    }
    return BAD_TYPE;
}

unflattenBinder对应上一篇的flattenBinder,还记得球场上大妈捡易拉罐的那个例子吗,unflattenBinder则是从parcel中提取flat_binder_object,也就是binder。然后,判断flat_binder_object是binder实体还是binder引用。现在,在以client进程的角度获取系统服务,而binder在client进程中的表述为binder引用,所以,进入BINDER_TYPE_HANDLE分支,调用getStrongProxyForHandle,这个函数在【2】中已经见过了,返回的是BpBinder的对象。ProcessState维护着一个元素类型为handle_entry的容器mHandleToObject。这样根据服务名称,获得了服务的代理对象,服务代理本来就继承了功能接口(IxxxInterface),调用相应了的函数即可,这样完成数据的跨进程通信。

三、再谈Binder通信模型

这一篇完结后,想了想还是把这个话题从上一篇放到这儿吧,也许更合适一些。截至目前,【1】中提到的Binder通信模型的四个组成部分:server进程、client进程、binder驱动、servicemanager进程都已悉数亮相。这时,我们再回过头来回味一下这个概念会不会有些更深一些的理解呢。包括【1】对binder在各部分中表述的总结,我会发现这就是一篇Binder通信机制纲领性的博文(请允许我再吹一波吧),作者的功力可见一斑。吾心向往之。

说明

这两篇的文章在方法调用的小标题标号时没有遵循严格的方法调用,比如1.1,1.2不是并列关系,而是调用与被调用关系,这块参考了gityuan博客中的写法,因为,如果按照严格的平行、调用关系去编号,方法调用栈可能会比较深,可能平行的编号不存在几个,都是诸如1.1.2.3这样的形式,甚至可能存在五、六级标题编号,所以,为了目录更好看,使用了以上的编号方法,特此说明。

Binder机制通信暂且告一段落,但是两篇内容不足以包含Binder的方方面面,很多细节我现在还没弄明白,所以这是一个需要长期复习再理解的过程。文章内容有误的地方欢迎指出,也欢迎评论,在探讨中共同进步。

参考资料

github.com/aosp-mirror…

aosp.tuna.tsinghua.edu.cn/platform/fr…(git clone)

androidxref.com/kernel_3.18…

blog.csdn.net/universus/a…

gityuan.com/2015/10/31/…

《Android的设计与实现 卷一》杨云君。

《深入理解Android 卷一》邓凡平。