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

Posted demonyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android笔记 - Binder之Client请求Service代理对象相关的知识,希望对你有一定的参考价值。

前言

之前两篇文章以 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.cpp

virtual 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.c

static void binder_transaction(struct binder_proc *proc,
                   struct binder_thread *thread,
                   struct binder_transaction_data *tr, int reply)

    struct binder_transaction *t;
    struct binder_work *tcomplete;
    size_t *offp, *off_end;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    struct binder_transaction_log_entry *e;
    uint32_t return_error;

    ......

    if (reply) 
        ......
     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.c

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uint32_t *ptr, uint32_t size, binder_handler func)

    int r = 1;
    uint32_t *end = ptr + (size / 4);

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

        switch(cmd) 
        case BR_NOOP:
            break;
        case BR_TRANSACTION_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.c

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

    struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;
    uint32_t strict_policy;
    int allow_isolated;

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

    // 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.c

struct 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.c

void 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.c

static void binder_transaction(struct binder_proc *proc,
                   struct binder_thread *thread,
                   struct binder_transaction_data *tr, int reply)

    struct binder_transaction *t;
    struct binder_work *tcomplete;
    size_t *offp, *off_end;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;

    ......
    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.cpp

status_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.cpp

virtual 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.cpp

sp<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.cpp

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) 
                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远程接口过程源代码分析

以上是关于Android笔记 - Binder之Client请求Service代理对象的主要内容,如果未能解决你的问题,请参考以下文章

Android笔记 - Binder之servicemanager代理对象

Android笔记 - Binder之servicemanager代理对象

Android笔记 - Binder之守护进程servicemanager

Android笔记 - Binder之请求注册Service组件

Android笔记 - Binder之基本概念

Android笔记 - Binder之数据结构