您的位置:首页 > 移动开发 > Android开发

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

2016-01-30 10:55 465 查看

前言

之前两篇文章以 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远程接口过程源代码分析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息