概述
笔者阅读了很多博客和相关书籍,自己也浏览了Android8.1系统源代码中关于ServiceManager的部分,有些书中称ServiceManager为Binder机制中的DNS服务器,负责某Binder服务在ServiceManager注册时提供的名称到底层Binder驱动分配的值的解析,我觉得这么理解倒也很贴切,在笔者整理关于ServiceManager的这篇博客时,发现想绕过Binder机制来单独来分析ServiceManager不太现实,而将Binder和ServiceManager合并一起来分析,篇幅过长,因此,笔者还是觉得先从最基本的开始,由简入深,逐个击破。
ServiceManager的启动
之前的博客已经大致分析了Android系统的启动过长,也大致了解了启动过程,今天的主角是ServiceManager,ServiceManager分为framework层和native层,我们这里要说的native层的ServiceManager,它在system/core/rootdir/init.rc脚本中描述并由init进程启动。
下面是关于init.rc脚本中,关于servicemanager启动的描述:
on post-fs
......
load_system_props
# start essential services
start logd
//启动servicemanager
start servicemanager
start hwservicemanager
start vndservicemanager
这里对应frameworks/native/cmds/servicemanager.rc描述脚本
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
writepid /dev/cpuset/system-background/tasks
shutdown critical
在学习源码的过程中,笔者强烈建议大家用画图的形式来理解这些模块的实现机制,这里笔者综合一些优秀的博文和一些书籍(文章结尾参考)以及笔者阅读Android8.1系统源代码相关的模块整理出的一张启动流程图

你一定很疑惑,上面那张图里面为什么会有两个binder.c的源代码,这里要说明的是native层的那个binder.c源代码在frameworks/native/cmds/servicemanager这个目录

它的实现如下:
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
......
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
......
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
......
}
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
......
return NULL;
}
以binder_open为例,它实际是对用户空间open,mmap,ioctl等操作的封装,用户态的程序调用内核层驱动需要陷入内核态,进行系统调用Syscall,比如打开Binder驱动方法的调用链为:open-> __open() -> binder_open()。 open()为用户空间的方法,__open()便是系统调用中相应的处理方法,通过查找,对应调用到内核binder驱动的binder_open()方法,其他的从用户态陷入内核态的流程也基本一致,而内核层的那个binder.c源代码则对应goldfish/drivers/staging/android/binder.c,它会通过copy_from_user和copy_to_user函数和用户空间以共享内存的方式进行数据交换
启动过程分析
下面是native层的源代码frameworks/native/cmds/servicemanager/service_manager.c中比较关键的几个函数,servicemanager进程启动之后会从main函数执行:
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
//打开/dev/binder驱动,映射区块大小为128K
bs = binder_open(driver, 128*1024);
......
//有些书上说是将自己注册成`Binder机制`的管家,当然你也可以这么理解
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
......
//进入循环等待客户进程的请求
binder_loop(bs, svcmgr_handler);
return 0;
}
基于事件驱动的消息循环模型:
void binder_loop(struct binder_state *bs, binder_handler func)
{
......
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
......
}
}
下面这个函数,是我们在binder_loop循环里,经过binder_parse处理后,最终回调的一个函数:
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
......
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
//遍历内部链表,获取目标Server对象的句柄
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
//添加具体的服务
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
txn->sender_euid);
return -1;
}
si = svclist;
while ((n-- > 0) && si)
si = si->next;
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
default:
ALOGE("unknown code %d\n", txn->code);
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
struct svcinfo
{
struct svcinfo *next;
uint32_t handle;
struct binder_death death;
int allow_isolated;
size_t len;
uint16_t name[0];
};
struct svcinfo *svclist = NULL;
有了上述的代码块,看到了do_add_service,do_find_service,svcinfo等相关关键字,这些是干什么的呢?你可以按照你对进程间通信等的理解,猜猜看,这些操作实现的具体作用?
其实在
servicemanager内部维护着一个svclist链表,用于存储所有Server相关信息,查询和注册都是基于这个数据结构展开的
当函数svcmgr_handler处理完成之后,binder_parse会进一步通过binder_send_reply来将执行结果返回给底层的Binder驱动,进而传递给客户端进程
接着binder_parse会进入下一轮的循环
由上面的过程我们基本可以归纳出,servicemanager的启动过程由三个步骤组成:
1. 通过binder_open()打开设备文件/dev/binder,以及将它映射到本进程的地址空间;
2. 通过binder_become_context_manager()将自己注册为Binder进程间通信机制的上下文管理者;
3. 通过binder_loop()来循环等待并通过binder_parse()处理Client进程的通信请求。
小结
当然了,关于ServiceManager和Binder通信机制远比想象的要复杂,后续笔者会基于进程间通信有更详细的博客来逐步分析。
参考
https://blog.youkuaiyun.com/freekiteyu/article/details/70082302
《Android系统源代码情景分析》
《深入理解android内核设计思想 第2版》

本文详细介绍了Android系统中ServiceManager的启动过程,包括打开设备文件、注册为Binder上下文管理者及循环处理客户端请求等关键步骤。
1835





