Android 系统中大量采用了组件化的设计思路,将大量的核心服务以 Service 组件来对外提供。Service 只有注册到 servicemanager 后,Client 端才能通过 servicemanager 获取到 Service 的代理对象,从而使用到 Service 提供的服务。由于 Service 组件的注册过程异常复杂,因此以系统中的 MediaPlayerService 为例,分为两篇文章来介绍 Service 的注册流程。这篇文章从 MediaPlayerService 的角度来分析如何发送注册请求,下一篇文章从 servicemanager 的角度来分析如何处理注册请求。
1. MediaPlayerService 用户空间
MediaPlayerService 的注册过程从调用 instantiate 函数开始,如下所示:
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
defaultServiceManager 函数用于获得 servicemanager 的代理对象 BpServiceManager,详细过程请查看上一篇文件 Binder之servicemanager代理对象。接下来调用代理对象 BpServiceManager 的 addService 函数,实现如下:
代码路径:frameworks/native/libs/binder/IServiceManager.cppvirtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); [1] data.writeString16(name); [2] data.writeStrongBinder(service); [3] data.writeInt32(allowIsolated ? 1 : 0); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); [4] return err == NO_ERROR ? reply.readExceptionCode() : err; }
[1] 通过 writeInterfaceToken 函数写入头部信息,内容为 STRICT_MODE_PENALTY_GATHER 和 android.os.IServiceManager
。
[2] 使用 writeString16 函数写入正在注册的服务名,内容为 media.player
。
[3] 使用 writeStrongBinder 函数将 MediaPlayerService 对象保存进 flat_binder_object 结构体中。关于 flat_binder_object 结构体,请参考 Binder之数据结构(二)。
Binder 通信机制使用 Parcel 类来序列化需要进行远程传输的内容。Parcel 是包裹的意思,可以理解成发送方将要传输的内容 flattened,然后通过 Binder 驱动进行传输,到达接收方后再 unflattened。更多内容请查阅官网 Parcel 小节。最终 Parcel 类型变量 data 中内容如下图所示:
[4] 通过 remote 函数得到保存在 BpRefBase 中的 BpBinder 对象,然后调用其 transact 函数,参数 ADD_SERVICE_TRANSACTION 是注册 Service 的命令,参数 data 是上述步骤准备好的通信请求数据,参数 reply 是请求应答结果。transact 函数定义如下所示:
代码路径:frameworks/native/libs/binder/BpBinder.cppstatus_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ // Once a binder has died, it will never come back to life. if (mAlive) { status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT;}
transact 函数实际上是调用 IPCThreadState 的同名函数来完成 addService 请求,函数定义如下:
代码路径:frameworks/native/libs/binder/IPCThreadState.cppstatus_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ ...... if (err == NO_ERROR) { LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(), (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY"); err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); [1] } if (err != NO_ERROR) { if (reply) reply->setError(err); return (mLastError = err); } if ((flags & TF_ONE_WAY) == 0) { if (reply) { err = waitForResponse(reply); [2] } else { Parcel fakeReply; err = waitForResponse(&fakeReply); } ...... } else { err = waitForResponse(NULL, NULL); } return err;}
[1] writeTransactionData 函数初始化要传输给 Binder 驱动的 binder_transaction_data 结构体,并将该结构体写入 IPCThreadState 类的成员变量 mOut 中。mOut 变量的类型是 Parcel,其内容如下图所示:
注意这里使用的事务命令是 BC_TRANSACTION,Binder 驱动中的 binder_thread_write 函数会处理此命令。关于 binder_transaction_data 结构体,请参考 Binder之数据结构(二)。
[2] waitForResponse 函数向 Binder 驱动发送请求,并等待应答结果,应答结果通过 reply 变量返回。
接下来分析 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)); if (err != NO_ERROR) goto finish; if (reply) { if ((tr.flags & TF_STATUS_CODE) == 0) { reply->ipcSetDataReference( 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); } ...... } ...... } goto finish; default: err = executeCommand(cmd); if (err != NO_ERROR) goto finish; break; } }finish: if (err != NO_ERROR) { if (acquireResult) *acquireResult = err; if (reply) reply->setError(err); mLastError = err; } return err;}
waitForResponse 函数在 while 循环中通过 talkWithDriver 来与 Binder 驱动进行通信,实际上是通过 ioctl 系统调用来完成与 Binder 驱动的通信,如下所示:
代码路径:frameworks/native/libs/binder/IPCThreadState.cppstatus_t IPCThreadState::talkWithDriver(bool doReceive){ if (mProcess->mDriverFD <= 0) { return -EBADF; } binder_write_read bwr; // Is the read buffer empty? const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // We don't want to write anything if we are still reading // from data left in the input buffer and the caller // has requested to read the next data. const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; [1] bwr.write_size = outAvail; [2] bwr.write_buffer = (long unsigned int)mOut.data(); [3] // This is what we'll read. if (doReceive && needRead) { bwr.read_size = mIn.dataCapacity(); [4] bwr.read_buffer = (long unsigned int)mIn.data(); [5] } else { bwr.read_size = 0; bwr.read_buffer = 0; } // Return immediately if there is nothing to do. if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; bwr.write_consumed = 0; bwr.read_consumed = 0; status_t err; do { if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) [6] err = NO_ERROR; if (mProcess->mDriverFD <= 0) { err = -EBADF; } } while (err == -EINTR); if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { if (bwr.write_consumed < (ssize_t)mOut.dataSize()) mOut.remove(0, bwr.write_consumed); else mOut.setDataSize(0); } if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0); } return NO_ERROR; } return err;}
talkWithDriver 函数会初始化一个 binder_write_read 结构体变量 bwr,之前也对通信数据进行过多次封装,这里是进入 Binder 驱动之前的最后一次封装。
[1] 由于 doReceive 和 needRead 的值都为1,因此 outAvail 的值为 mOut 中保存的数据量。
[2] 初始化成员变量 write_size,写入 Binder 驱动的数据量为 outAvail 。
[3] 初始化成员变量 write_buffer,写入 Binder 驱动数据的首地址为 mOut.data()
。
[4] 初始化成员变量 read_size,读取 Binder 驱动的数据量最大为 mIn.dataCapacity()
。
[5] 初始化成员变量 read_buffer,将 Binder 驱动数据读取到 mIn.data()
地址处。
[6] 通过 ioctl 系统调用进入 Binder 驱动,ioctl 使用命令为 BINDER_WRITE_READ,传入参数为 bwr。
关于 binder_write_read 结构体,请参考 Binder之数据结构(二)。
2. Binder 驱动
ioctl 系统调用最终会进入 Binder 驱动的 binder_ioctl 函数,binder_ioctl 函数处理所有用户空间传入的命令,其中与 BINDER_WRITE_READ 命令有关的代码如下所示:
代码路径:linux/drivers/staging/android/binder.cstatic long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ int ret; struct binder_proc *proc = filp->private_data; [1] struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; trace_binder_ioctl(cmd, arg); ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) goto err_unlocked; binder_lock(__func__); thread = binder_get_thread(proc); [2] if (thread == NULL) { ret = -ENOMEM; goto err; } switch (cmd) { case BINDER_WRITE_READ: { struct binder_write_read bwr; if (size != sizeof(struct binder_write_read)) { ret = -EINVAL; goto err; } if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto err; } if (bwr.write_size > 0) { ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); [3] trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto err; } } if (bwr.read_size > 0) { ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); [4] 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 err; } } if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; } break; } ......}
[1] 通过 filp 结构体的 private_data 变量获得用于描述进程的 binder_proc 结构体,该结构体在进程打开设备文件 /dev/binder
时创建。
[2] 调用 binder_get_thread 函数获取用于描述当前线程的 binder_thread 结构体。第一次调用 binder_get_thread 时由于不存在,因此会创建一个 binder_thread 结构体,并保存在红黑树 proc->threads
中。
[3] 如果 bwr.write_size
的值大于0,调用 binder_thread_write 函数写入请求内容。参数 bwr.write_buffer
为之前writeTransactionData 函数中初始化的内容。
[4] 如果 bwr.read_size
的值大于0,调用 binder_thread_read 函数读取处理结果。
由上述分析过程可知,bwr.write_size
的值大于0,而且事务命令是 BC_TRANSACTION,因此 binder_thread_write 中会调用 binder_transaction 函数进一步处理通信数据。binder_transaction 函数是 Binder 驱动的核心处理函数,该函数定义如下:
代码路径: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); [5] 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); [6] ...... if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; [7] 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)); [8] 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 *))); [9] if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { [10] ...... } if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { [11] ...... } ...... 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); switch (fp->type) { case BINDER_TYPE_BINDER: case BINDER_TYPE_WEAK_BINDER: { struct binder_ref *ref; struct binder_node *node = binder_get_node(proc, fp->binder); [12] if (node == NULL) { node = binder_new_node(proc, fp->binder, fp->cookie); [13] 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) { ...... } if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } ref = binder_get_ref_for_node(target_proc, node); [14] 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; [15] else fp->type = BINDER_TYPE_WEAK_HANDLE; fp->handle = ref->desc; [16] binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo); ...... } break; ...... } } 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; [17] thread->transaction_stack = t; [18] } else { ...... } t->work.type = BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry, target_list); [19] tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry, &thread->todo); [20] if (target_wait) wake_up_interruptible(target_wait); [21] return; ......}
binder_transaction 函数中参数 tr 的类型是 binder_transaction_data 结构体,里面保存的实际上是用户空间的 writeTransactionData 函数初始化的内容。
[1] 由于 tr->target.handle
值为0,因此 target_node 变量赋值为 binder_context_mgr_node,也就是赋值为 servicemanager 的 Binder 实体。
binder_context_mgr_node 在 servicemanager 注册成为上下文管理者过程被赋值,具体过程请参考 Binder之守护进程servicemanager。
[2] 根据 target_node 的值初始化目标进程 target_proc 为 servicemanager 的宿主进程 。
[3] 通过 target_proc 获取 servicemanager 进程的待处理工作队列 target_list。
[4] 通过 target_proc 获取 servicemanager 进程的等待队列 target_wait。
[5] 创建一个待处理事务 t。
[6] 创建一个待完成工作项 tcomplete。
[7] 初始化发起事务的线程 t->from
为 MediaPlayerService 的当前线程。
[8] 在 servicemanager 进程中分配一块大小为 tr->data_size
和 tr->offsets_size
之和的内存,用于保存从 MediaPlayerService 用户空间传入的通信数据。
[9] 计算出待处理事务 t 中偏移数组的地址。
[10] 使用 copy_from_user 函数从 tr 中拷贝数据到待处理事务 t 中。
[11] 使用 copy_from_user 函数从 tr 中拷贝偏移数组到待处理事务 t 中。
[12] 获取目标进程 servicemanager 中 MediaPlayerService 对应的 Binder 实体对象。
[13] 第一次调用 binder_get_node 函数返回值为 NULL,所以新建一个 MediaPlayerService 的 Binder 实体对象。
[14] 为 MediaPlayerService 创建一个 Binder 引用对象。
关于 Binder 实体对象和 Binder 引用对象的相关内容,请参考 Binder之基本概念这篇博文。
[15] 由于 servicemanager 只能通过句柄值来引用 MediaPlayerService,因此修改 fp->type
的值为 BINDER_TYPE_HANDLE。
[16] 修改 fp->handle
的值为 MediaPlayerService 对应引用对象的句柄值。
[17] 待处理事务 t 依赖于 thread->transaction_stack
。
[18] 将待处理事务 t 添加到事务发起线程(MediaPlayerService 的当前线程)的事务堆栈。
[19] 将待处理事务 t 加入到 servicemanager 进程的待处理工作队列 target_list 中。
[20] 将待完成工作项 tcomplete 加入到事务发起线程的待处理项队列中。
[21] 唤醒目标进程 servicemanager 处理刚刚添加到待处理工作队列 target_list 中的待处理事务 t(下篇文章分析这个过程)。
返回到之前的 binder_ioctl 函数,由于 bwr.read_size
大于0,因此进入 binder_thread_read 函数:
代码路径:linux/drivers/staging/android/binder.cstatic int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed, int non_block){ void __user *ptr = buffer + *consumed; void __user *end = buffer + size; int ret = 0; int wait_for_proc_work; if (*consumed == 0) { if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); }retry: wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo); [1] ...... if (wait_for_proc_work) { ...... } else { if (non_block) { if (!binder_has_thread_work(thread)) ret = -EAGAIN; } else ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); [2] } ...... while (1) { uint32_t cmd; struct binder_transaction_data tr; struct binder_work *w; struct binder_transaction *t = NULL; if (!list_empty(&thread->todo)) w = list_first_entry(&thread->todo, struct binder_work, entry); [3] else if (!list_empty(&proc->todo) && wait_for_proc_work) w = list_first_entry(&proc->todo, struct binder_work, entry); else { if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */ goto retry; break; } if (end - ptr < sizeof(tr) + 4) break; switch (w->type) { ...... case BINDER_WORK_TRANSACTION_COMPLETE: { cmd = BR_TRANSACTION_COMPLETE; if (put_user(cmd, (uint32_t __user *)ptr)) [4] return -EFAULT; ptr += sizeof(uint32_t); list_del(&w->entry); kfree(w); } break; ...... } if (!t) [5] continue; ...... }done: ...... return 0;}
[1] 通过之前的分析可知 thread->transaction_stack
和 thread->todo
都不为 NULL,因此 wait_for_proc_work 的值为 False。
[2] 检查线程等待队列 thread->todo
中是否存在待处理工作项,如果没有则睡眠等待。由于之前添加了一个待完成工作项 tcomplete,因此线程不会睡眠。
[3] 从等待队列 thread->todo
中获取待处理工作项 w。
[4] 调用 put_user 系统调用往用户空间传入的 read_buffer 中写入 BR_TRANSACTION_COMPLETE 命令。然后从 thread->todo
删除待处理工作项 w。
[5] 由于没有事务需要进一步处理,所以继续 while 循环。
3. MediaPlayerService 用户空间
此时由于等待队列 thread->todo
中没有更多的待处理工作项,所以 ioctl 系统调用返回,回到 MediaPlayerService 用户空间,继续执行 talkWithDriver 函数,如下所示:
代码路径:frameworks/native/libs/binder/IPCThreadState.cpp ...... if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { if (bwr.write_consumed < (ssize_t)mOut.dataSize()) mOut.remove(0, bwr.write_consumed); else mOut.setDataSize(0); [1] } if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); [2] mIn.setDataPosition(0); } return NO_ERROR; }
[1] 设置 mOut 大小为0,说明没有更多内容需要写入 Binder 驱动。
[2] 设置 mIn 大小为 bwr.read_consumed
,说明从 Binder 驱动中读取的内容长度为 bwr.read_consumed
。
然后返回到 waitForResponse 函数,继续执行如下代码:
代码路径:frameworks/native/libs/binder/IPCThreadState.cpp while (1) { if ((err=talkWithDriver()) < NO_ERROR) break; err = mIn.errorCheck(); if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue; cmd = mIn.readInt32(); [1] ...... switch (cmd) { case BR_TRANSACTION_COMPLETE: [2] if (!reply && !acquireResult) goto finish; break; ...... }
[1] 从 IPCThreadState 类的成员变量 mIn 中读取之前 binder_thread_read 函数中写入 read_buffer 的 BR_TRANSACTION_COMPLETE 命令。
[2] 由于参数 reply 不为 NULL,说明 waitForResponse 函数并没有结束,继续执行 while 循环,从而第二次调用 talkWithDriver 函数。
对 BR_TRANSACTION_COMPLETE 命令的处理分为两种情况:如果参数 reply 为 NULL,说明是异步请求,那么从 waitForResponse 函数返回;如果参数 reply 不为 NULL,说明是同步请求,那么 waitForResponse 函数并没有结束,继续执行 while 循环。
4. Binder 驱动
在 talkWithDriver 函数中,第二次调用 ioctl 系统调用,并且 bwr.write_size
的值为0。最终再一次进入 binder_ioctl 函数,由于此时 bwr.write_size
的值为0,而 bwr.read_size
的值不为0,因此直接进入到 binder_thread_read 函数,代码如下所示:
代码路径:linux/drivers/staging/android/binder.cstatic int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed, int non_block){ void __user *ptr = buffer + *consumed; void __user *end = buffer + size; int ret = 0; int wait_for_proc_work; if (*consumed == 0) { if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); }retry: wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo); [1] ...... if (wait_for_proc_work) { ...... } else { if (non_block) { if (!binder_has_thread_work(thread)) ret = -EAGAIN; } else ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); [2] }
[1] 此时 thread->transaction_stack
不为 NULL, 而线程等待队列 thread->todo
为空,wait_for_proc_work 的值为 False。
[2] 由于线程等待队列 thread->todo
为空,MediaPlayerService 线程进入睡眠,等待 servicemanager 的注册处理结构。
至此,Service 如何通过 Binder 驱动发送注册请求到 servicemanager 已经分析完毕,下篇文章继续从 servicemanager 的角度来分析如何处理注册请求。
参考文章:
1. Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析