Android笔记 - Binder之Client请求Service代理对象

来源:互联网 发布:模拟量用电流没数据 编辑:程序博客网 时间:2024/05/16 15:38

前言

之前两篇文章以 MediaPlayerService 为例,分析了 Service 注册到服务管理者 servicemanager 的历程。我们知道,在请求注册 Service 之前,需要获取到 servicemanager 的代理对象。同理,在 Client 使用 Service 提供的服务之前,也需要获取到 Service 的代理对象。本文以 MediaPlayer 为例,分析 Client 端如何获取到 Service 代理对象 BpMediaPlayerService 的过程。BpMediaPlayerService 的类关系图如下所示:
这里写图片描述

由于 servicemanager 也是一个特殊的 Service,因此获取 servicemanager 的代理对象和获取 MediaPlayerService 的代理对象有很多相似之处。获取 servicemanager 代理对象的分析过程请参考文章 Binder之servicemanager代理对象。

MediaPlayer 进程发起请求

客户端 MediaPlayer 的实现在 frameworks/av/media/libmedia/mediaplayer.cpp 文件中,它通过 getMediaPlayerService 函数来获取 MediaPlayerService 的代理对象,下面看看 getMediaPlayerService 函数的定义:

代码路径:frameworks/av/media/libmedia/IMediaDeathNotifier.cpp/*static*/const sp<IMediaPlayerService>&IMediaDeathNotifier::getMediaPlayerService(){    Mutex::Autolock _l(sServiceLock);    if (sMediaPlayerService == 0) {        sp<IServiceManager> sm = defaultServiceManager();        sp<IBinder> binder;        do {            binder = sm->getService(String16("media.player"));            if (binder != 0) {                break;            }            usleep(500000); // 0.5 s        } while (true);        if (sDeathNotifier == NULL) {            sDeathNotifier = new DeathNotifier();        }        binder->linkToDeath(sDeathNotifier);        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);    }    return sMediaPlayerService;}

首先通过 defaultServiceManager 函数获取 servicemanager 的代理对象 BpServiceManager,然后调用 BpServiceManager 的 getService 函数,注意函数参数为字符串 media.player。getService 函数内部又调用了 checkService 函数,接下来看看 checkService 函数的定义:

代码路径:frameworks/native/libs/binder/IServiceManager.cppvirtual sp<IBinder> checkService(const String16& name) const{    Parcel data, reply;    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());                                        [1]    data.writeString16(name);                                                                                   [2]    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);                                                [3]    return reply.readStrongBinder();                                                                            [4]}

[1] 通过 writeInterfaceToken 函数写入 RPC 头部信息。
[2] 使用 writeString16 函数写入请求服务的服务名,内容为 media.player
[3] 通过 remote 函数得到 BpServiceManager 保存在 BpRefBase 中的 BpBinder 对象,然后调用其 transact 函数。transact 函数包含三个参数:参数 CHECK_SERVICE_TRANSACTION 是获取 Service 代理对象的协议;参数 data 是一个 Parcel 对象,用于保存写入 Binder 驱动的数据;参数 reply 也是一个 Parcel 对象,用于接收返回数据。
[4] 通过 readStrongBinder 函数获取 Binder 驱动返回 的 Binder 对象,后文会详细分析此过程。

调用 transact 函数后,通过如下流程进入 Binder 驱动:

-> BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);-> IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);-> IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult);-> IPCThreadState::talkWithDriver(bool doReceive);-> ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);

上述流程在 Binder之请求注册Service组件 这篇文章有分析,这里不再赘述。

Binder 驱动传递请求

ioctl 是一个系统调用,最终会进入 Binder 驱动的 binder_ioctl 函数。binder_ioctl 函数对用户空间传过来的 BINDER_WRITE_READ 命令进行处理,之前的文章也有分析。接下来进入 Binder 驱动的核心处理函数 binder_transaction,该函数定义如下:

代码路径:linux/drivers/staging/android/binder.cstatic 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) {        ......    } else {        if (tr->target.handle) {            ......        } else {            target_node = binder_context_mgr_node;                                                              [1]            if (target_node == NULL) {                return_error = BR_DEAD_REPLY;                goto err_no_context_mgr_node;            }        }        target_proc = target_node->proc;                                                                        [2]        ......    }    if (target_thread) {        ......    } else {        target_list = &target_proc->todo;                                                                       [3]        target_wait = &target_proc->wait;                                                                       [4]    }    /* TODO: reuse incoming transaction for reply */    t = kzalloc(sizeof(*t), GFP_KERNEL);                                                              if (t == NULL) {        return_error = BR_FAILED_REPLY;        goto err_alloc_t_failed;    }    binder_stats_created(BINDER_STAT_TRANSACTION);    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);                                              ......    if (!reply && !(tr->flags & TF_ONE_WAY))        t->from = thread;                                                                                       [5]    else        t->from = NULL;    t->sender_euid = proc->tsk->cred->euid;    t->to_proc = target_proc;    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;    t->buffer->target_node = target_node;    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)) {                                  [6]        ......    }    ......    off_end = (void *)offp + tr->offsets_size;    for (; offp < off_end; offp++) {                                                                            [7]        ......    }    if (reply) {        ......    } else if (!(t->flags & TF_ONE_WAY)) {        BUG_ON(t->buffer->async_transaction != 0);        t->need_reply = 1;        t->from_parent = thread->transaction_stack;        thread->transaction_stack = t;                                                                          [8]    } else {        ......    }    t->work.type = BINDER_WORK_TRANSACTION;    list_add_tail(&t->work.entry, target_list);                                                                 [9]    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;    list_add_tail(&tcomplete->entry, &thread->todo);                                                           [10]    if (target_wait)        wake_up_interruptible(target_wait);                                                                    [11]    return;    ......}

binder_transaction 函数包含四个参数,其中参数 proc 为指向请求发起进程也就是 MediaPlayer 进程的指针;参数 thread 为指向请求发起线程也就是 MediaPlayer 当前线程的指针;参数 tr 是结构体 binder_transaction_data 的指针,指向需要处理的事务数据,也就是从 MediaPlayer 传递过来通信数据;参数 reply 是一个布尔变量,如果值为 true,表示正在处理 BC_REPLY 协议,否则表示正在处理 BC_TRANSACTION 协议。
[1] 由于 tr->target.handle 值为0,因此 target_node 变量赋值为 servicemanager 的 Binder 实体对象。
[2] 由于需要通过 servicemanager 获取服务的句柄值,因此 target_proc 赋值为 servicemanager 的宿主进程。
[3] 根据 target_proc 获取 servicemanager 进程的待处理工作队列 target_list。
[4] 根据 target_proc 获取 servicemanager 进程的等待队列 target_wait。
[5] 初始化发起事务的线程 t->from 为 MediaPlayer 的当前线程。
[6] 使用 copy_from_user 函数从 tr 中拷贝通信数据到待处理事务 t 中。
[7] 由于通信数据不存在 Binder 对象,因此不会进入 for 循环。
[8] 将待处理事务 t 添加到事务发起线程(MediaPlayer 的当前线程)的事务堆栈。
[9] 将待处理事务 t 加入到 servicemanager 进程的待处理工作队列 target_list 中,注意事务类型为 BINDER_WORK_TRANSACTION。
[10] 将待完成工作项 tcomplete 加入到事务发起线程(MediaPlayer 的当前线程)的待处理工作队列中。MediaPlayer 当前线程对工作项 tcomplete 的处理过程请查阅文章 Binder之请求注册Service组件 。
[11] 唤醒目标进程 servicemanager 处理刚刚添加到待处理工作队列 target_list 中的待处理事务 t。

综上,binder_transaction 函数的工作主要是创建一个待处理事务 t,初始化完成后将其添加到目标进程 servicemanager 的待处理工作队列 target_list 中,最后唤醒 servicemanager 来处理该事务。

servicemanager 处理请求

如果没有进程间通信请求需要处理,servicemanager 会在 binder_thread_read 函数中调用 wait_event_freezable_exclusive 进入睡眠等待状态。servicemanager 被唤醒后,会通过 binder_has_proc_work 函数来检查是否有新的请求需要处理,也就是检查当前进程的待处理工作队列 todo 是否为空。由于之前 Binder 驱动将待处理事务 t 添加到了 servicemanager 进程的待处理工作队列中,接下来继续执行 binder_thread_read 函数,将待处理事务从 Binder 驱动转发到 servicemanager 用户空间,这个过程请参考文章 Binder之处理注册Service组件请求 第2小节。

binder_thread_read 函数执行完后会回到 binder_ioctl 函数,然后从 ioctl 系统调用返回到 binder_loop 函数中,也就是从 Binder 驱动重新回到了 servicemanager 用户空间。接下来 binder_loop 调用 binder_parse 函数解析从 Binder 驱动程序拷贝回来的 binder_transaction_data 结构体内容,如下所示:

代码路径:frameworks/native/cmds/servicemanager/binder.cint 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_COMPLETE:            break;        ......        case BR_TRANSACTION: {            struct binder_txn *txn = (void *) ptr;            ......            if (func) {                unsigned rdata[256/4];                struct binder_io msg;                struct binder_io reply;                int res;                bio_init(&reply, rdata, sizeof(rdata), 4);                                                      [1]                bio_init_from_txn(&msg, txn);                                                                   [2]                res = func(bs, txn, &msg, &reply);                                                              [3]                binder_send_reply(bs, &reply, txn->data, res);                                                  [4]            }            ptr += sizeof(*txn) / sizeof(uint32_t);            break;        }        ......        }    }    return r;}

[1] 使用函数 bio_init 初始化保存返回结果的变量 reply。
[2] 使用函数 bio_init_from_txn 初始化通信数据 msg。

注:binder_io 结构体对应于 Client 端的 Parcel 类,binder_txn 结构体对应于 Client 端的 binder_transaction_data 结构体。(-。-;),很喜欢这种对称美。

[3] 调用函数指针 func 指向的函数,这里 func 实际指向 svcmgr_handler 函数。
[4] 使用函数 binder_send_reply 返回查询服务的结果。

在分析 svcmgr_handler 函数的实现之前,回顾下之前 checkService 函数写入的请求内容:
这里写图片描述

接下来看看 svcmgr_handler 函数的具体内容,如下所示:

代码路径:frameworks/native/cmds/servicemanager/service_manager.cint 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;    // Equivalent to Parcel::enforceInterface(), reading the RPC    // header with the strict mode policy mask and the interface name.    // Note that we ignore the strict_policy and don't propagate it    // further (since we do no outbound RPCs anyway).    strict_policy = bio_get_uint32(msg);    s = bio_get_string16(msg, &len);                                                                            [1]    if ((len != (sizeof(svcmgr_id) / 2)) ||        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {        fprintf(stderr,"invalid id %s\n", str8(s));        return -1;    }    switch(txn->code) {    case SVC_MGR_GET_SERVICE:    case SVC_MGR_CHECK_SERVICE:        s = bio_get_string16(msg, &len);                                                                        [2]        ptr = do_find_service(bs, s, len, txn->sender_euid);                                                    [3]        if (!ptr)            break;        bio_put_ref(reply, ptr);                                                                                [4]        return 0;        ......    }    bio_put_uint32(reply, 0);    return 0;}

[1] 使用 bio_get_string16 函数从 msg 中读取接口名 android.os.IServiceManager
[2] 使用 bio_get_string16 函数从 msg 中读取服务名 media.player
[3] 调用 do_find_service 查询服务名 media.player 对应的句柄值。
[4] 调用 bio_put_ref 将句柄值保存到一个 Bind 引用对象。

do_find_service 又是通过调用 find_svc 函数来查询句柄值,后者定义如下:

代码路径:frameworks/native/cmds/servicemanager/service_manager.cstruct svcinfo{    struct svcinfo *next;    void *ptr;    struct binder_death death;    int allow_isolated;    unsigned len;    uint16_t name[0];};struct svcinfo *find_svc(uint16_t *s16, unsigned 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 0;}

其中参数 s16 的值为 media.player ,假设之前 MediaPlayerService 已经注册成功,那么肯定可以找到 name 为 media.player 的 svcinfo 结构体,该结构体的成员变量 ptr 指向对应的句柄值。

返回到 svcmgr_handler,调用函数 bio_put_ref 保存查询到的句柄值,如下所示:

代码路径:frameworks/native/cmds/servicemanager/binder.cvoid bio_put_ref(struct binder_io *bio, void *ptr){    struct binder_object *obj;    if (ptr)        obj = bio_alloc_obj(bio);                                                                               [1]    else        obj = bio_alloc(bio, sizeof(*obj));    if (!obj)        return;    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;    obj->type = BINDER_TYPE_HANDLE;                                                                             [2]    obj->pointer = ptr;                                                                                         [3]    obj->cookie = 0;}

[1] 调用 bio_alloc_obj 函数创建一个 Binder 对象。
[2] Binder 对象的成员变量 type 赋值为 BINDER_TYPE_HANDLE。
[3] Binder 对象的成员变量 pointer 赋值为指向句柄值的指针。

binder_io 结构体对应于 Client 端的 flat_binder_object 结构体。

svcmgr_handler 执行完后,返回到 binder_parse 中,继续调用 binder_send_reply 函数返回查询服务的结果 reply。binder_send_reply 内部会调用 binder_write 函数将查询结果传递给 Binder 驱动,该过程请参考文章 Binder之处理注册Service组件请求第3节。

Binder 驱动传递结果

binder_write 函数内部通过系统调用 ioctl(bs->fd, BINDER_WRITE_READ, &bwr) 来与 Binder 驱动进行交互,最终又一次进入 Binder 驱动的 binder_transaction 函数,注意此时参数 reply 的值为 true,接下来看看这个过程:

代码路径:linux/drivers/staging/android/binder.cstatic 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;    ......    if (reply) {        in_reply_to = thread->transaction_stack;                                                                [1]        ......        thread->transaction_stack = in_reply_to->to_parent;        target_thread = in_reply_to->from;                                                                      [2]        ......        target_proc = target_thread->proc;                                                                      [3]    } 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;    /* TODO: reuse incoming transaction for reply */    t = kzalloc(sizeof(*t), GFP_KERNEL);    ......    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);    ......    if (!reply && !(tr->flags & TF_ONE_WAY))        t->from = thread;    else        t->from = NULL;    t->sender_euid = proc->tsk->cred->euid;    t->to_proc = target_proc;    t->to_thread = target_thread;    t->code = tr->code;    t->flags = tr->flags;    t->priority = task_nice(current);    trace_binder_transaction(reply, t, target_node);    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;    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++) {        struct flat_binder_object *fp;        ......        fp = (struct flat_binder_object *)(t->buffer->data + *offp);                                            [4]        switch (fp->type) {        ......        case BINDER_TYPE_HANDLE:        case BINDER_TYPE_WEAK_HANDLE: {            struct binder_ref *ref = binder_get_ref(proc, fp->handle);                                          [5]            ......            if (ref->node->proc == target_proc) {                                                               [6]                ......            } else {                struct binder_ref *new_ref;                new_ref = binder_get_ref_for_node(target_proc, ref->node);                                      [7]                if (new_ref == NULL) {                    return_error = BR_FAILED_REPLY;                    goto err_binder_get_ref_for_node_failed;                }                fp->handle = new_ref->desc;                                                                     [8]                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);                ......            }        } break;        ......        }    }    if (reply) {        BUG_ON(t->buffer->async_transaction != 0);        binder_pop_transaction(target_thread, in_reply_to);    }    ......    t->work.type = BINDER_WORK_TRANSACTION;    list_add_tail(&t->work.entry, target_list);                                                                 [9]    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;    list_add_tail(&tcomplete->entry, &thread->todo);    if (target_wait)        wake_up_interruptible(target_wait);                                                                    [10]    return;    ......}

[1] 初始化 in_reply_to 为指向当前线程 thread(servicemanager 线程) 的事务堆栈 binder_transaction 的指针。之前 binder_thread_read 函数将处理事务加入到了 thread 的事务堆栈,因此 in_reply_to 指针实际指向了之前加入的事务。
[2] 根据事务 in_reply_to 初始化目标线程 target_thread 为 MediaPlayer 的当前线程。
[3] 根据 target_thread 初始化目标进程 target_proc 为 MediaPlayer 进程。
[4] 从接收到的查询结果数据中获得一个 flat_binder_object 对象,该对象就是之前调用 bio_alloc_obj 函数创建的对象。
[5] 通过 binder_get_ref 函数找到句柄值 fp->handle 对应的 Binder 引用对象,实际上就是找到 MediaPlayerService 在 Binder 驱动中的引用对象。

由文章 Binder之请求注册Service组件可知,Service 在第一次请求注册时,Binder 驱动会通过 binder_get_ref_for_node 函数为 servicemanager 进程创建一个 Binder 引用对象,注册处理过程就是将 Binder 引用对象对应的句柄值保存到 servicemanager 的结构体 svcinfo 中。

[6] ref->node->proc 为创建 MediaPlayerService 的进程也就是 servicemanager 进程,而 target_proc 为 MediaPlayer 进程。两者不是同一进程,因此 if 条件判断不满足。
[7] 通过 binder_get_ref_for_node 函数为 MediaPlayer 进程创建一个 Binder 引用对象。

注:虽然 servicemanager 进程和 MediaPlayer 进程中的 Binder 引用对象不同,但引用对象都指向同一个 Binder 实体对象。

[8] 修改 fp->handle 的值为刚创建 Binder 引用对象的句柄值。
[9] 将待处理事务 t 加入到目标线程 MediaPlayer 的待处理工作队列 target_list 中。
[10] 唤醒目标线程 MediaPlayer 处理刚刚添加到待处理工作队列 target_list 中的待处理事务 t。

MediaPlayer 当前线程被唤醒后,继续执行 binder_thread_read 函数处理刚刚添加的事务,最终通过 copy_to_user 系统函数将事务中的数据传递到 MediaPlayer 进程的用户空间。

MediaPlayer 进程封装代理对象

回到 MediaPlayer 进程的用户空间,接下来执行流程返回到 waitForResponse 函数,如下所示:

代码路径:frameworks/native/libs/binder/IPCThreadState.cppstatus_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){    int32_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 = mIn.readInt32();        switch (cmd) {        case BR_TRANSACTION_COMPLETE:            if (!reply && !acquireResult) goto finish;            break;        ......        case BR_REPLY:            {                binder_transaction_data tr;                err = mIn.read(&tr, sizeof(tr));                                                                [1]                if (err != NO_ERROR) goto finish;                if (reply) {                    if ((tr.flags & TF_STATUS_CODE) == 0) {                        reply->ipcSetDataReference(                                                             [2]                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),                            tr.data_size,                            reinterpret_cast<const size_t*>(tr.data.ptr.offsets),                            tr.offsets_size/sizeof(size_t),                            freeBuffer, this);                    } else {                        ......                    }                }                 ......            }            goto finish;        default:            ......        }    }finish:    if (err != NO_ERROR) {        if (acquireResult) *acquireResult = err;        if (reply) reply->setError(err);        mLastError = err;    }    return err;}

[1] 将事务数据从成员变量 mIn 读取到结构体 binder_transaction_data 中。
[2] ipcSetDataReference 函数又将 binder_transaction_data 中的数据保存到参数 reply,此时 reply 中的数据就是 servicemanager 调用 binder_send_reply 函数返回的查询结果。

注:Binder 引用对象的句柄值在 binder_transaction 函数中被修改了。

接下来通过 goto 语句跳出 while 循环,继续一路向北返回到 checkService 函数,如下所示:

代码路径:frameworks/native/libs/binder/IServiceManager.cppvirtual sp<IBinder> checkService(const String16& name) const{    Parcel data, reply;    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());    data.writeString16(name);    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);    return reply.readStrongBinder();}

注:无论走了多远,都不忘来时的路。

最后调用 readStrongBinder 函数读取 MediaPlayService 对应的 Binder 代理对象,如下所示:

代码路径:frameworks/native/libs/binder/Parcel.cppsp<IBinder> Parcel::readStrongBinder() const{    sp<IBinder> val;    unflatten_binder(ProcessState::self(), *this, &val);    return val;}status_t unflatten_binder(const sp<ProcessState>& proc,    const Parcel& in, sp<IBinder>* out){    const flat_binder_object* flat = in.readObject(false);    if (flat) {        switch (flat->type) {            ......            case BINDER_TYPE_HANDLE:                *out = proc->getStrongProxyForHandle(flat->handle);                return finish_unflatten_binder(                    static_cast<BpBinder*>(out->get()), *flat, in);        }    }    return BAD_TYPE;}

getStrongProxyForHandle 函数根据句柄值 flat->handle 获取代理对象,该函数第一次调用时会新建一个 BpBinder 代理对象并保存在 Vector 中,之后调用时 lookupHandleLocked 函数直接从 Vector 中获取 BpBinder 代理对象。getStrongProxyForHandle 函数定义如下:

代码路径:frameworks/native/libs/binder/ProcessState.cppsp<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) {                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 {            result.force_set(b);            e->refs->decWeak(this);        }    }    return result;}

回到 readStrongBinder 函数,此时 val 的值为新建的 Binder 代理对象。接下来返回到刚开始的 getMediaPlayerService 函数。

代码路径:frameworks/av/media/libmedia/IMediaDeathNotifier.cpp/*static*/const sp<IMediaPlayerService>&IMediaDeathNotifier::getMediaPlayerService(){    Mutex::Autolock _l(sServiceLock);    if (sMediaPlayerService == 0) {        sp<IServiceManager> sm = defaultServiceManager();        sp<IBinder> binder;        do {            binder = sm->getService(String16("media.player"));            if (binder != 0) {                break;            }            usleep(500000); // 0.5 s        } while (true);        if (sDeathNotifier == NULL) {            sDeathNotifier = new DeathNotifier();        }        binder->linkToDeath(sDeathNotifier);        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);    }    return sMediaPlayerService;}

历经艰难险阻,语句 sm->getService(String16("media.player")) 终于执行完并返回了 BpBinder 代理对象。

为了方便 Client 端使用,使用函数模板 interface_cast<IMediaPlayerService> 将返回的代理对象 BpBinder 封装成 MediaPlayerService 的代理对象 sMediaPlayerService,详细过程请参考文章 Binder之servicemanager代理对象第2小节。

至此,以 MediaPlayer 为例,在 Client 端获取 Service 代理对象的整个流程分析完成。当然,由于个人水平和篇幅所限,文章忽略掉相当多的细节内容,只介绍了我所理解的关键点部分。如果对这部分内容很感兴趣,可以按照这个分析流程走几遍代码,再结合 Binder之基本概念这篇文章中 Binder 各角色之间的关系图去理解,相信会很有收获。以下是 Binder 各角色之间的关系图:
这里写图片描述

参考资料:
1. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

0 0