概述
笔者阅读了很多博客和相关书籍,自己也浏览了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.csdn.net/freekiteyu/article/details/70082302
《Android系统源代码情景分析》
《深入理解android内核设计思想 第2版》