在上一篇博客《Android源码分析之Binder进程间通信一》中,我详细的讲述了Android进程间通信为什么会选择Binder进行通信,而且在文章末尾,我还提议从4个方面来理解整个Binder进程间通信机制。当然这篇博客的重点就是介绍ServiceManager组件的,它是整个Binder机制的守护进程,用来管理开发创建的各种Server,并且向Client提供查询Server的远程接口的功能。
那该如何阅读ServiceManager的源代码呢?我们都知道ServiceManager处于用户空间,所以其源代码必然是在frameworks/base/cmds/servicemanager中的:主要由3个文件(binder.h,binder.c和service_manager.c)组成,service_manager.c是ServiceManager的入口函数的:
位于:frameworks\base\cmds\servicemanager\service_manager.c
int main(int argc, char **argv)
{
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
//打开binder设备
<span style="color:#ff0000;">bs = binder_open(128*1024);</span>
//成为manager
if (<span style="color:#ff0000;">binder_become_context_manager(bs)</span>) {
LOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
//处理客户端发过来的请求
<span style="color:#ff0000;">binder_loop(bs, svcmgr_handler);</span>
return 0;
}
该主函数主要完成三个功能:
1)调用binder_open(int)打开Binder驱动设备;
2)调用binder_become_context_manager通知Binder驱动程序自己是Binder的上下文管理者;
3)调用binder_loop进入休眠,充当Server,等待Client请求;
可能大家对住函数中的struct binder_state和宏BINDER_SERVICE_MANAGER不太了解,下面我简要的从定义讲解下它们:
结构体binder_state定义:在frameworks/base/cmds/servicemanager/binder.c文件中
struct binder_state
{
//文件描述符
int fd;
void *mapped;
unsigned mapsize;
};
成员变量:
1)fd:文件描述符,表示要打开的binder设备文件描述符;
2)mapped:把设备文件binder映射到进程空间的起始地址;
3)mapSize:内存空间映射的大小;
宏BINDER_SERVICE_MANAGER定义:在frameworks/base/cmds/servicemanager/binder.h文件中
/* the one magic object*/
#define BINDER_SERVICE_MANAGER ((void*) 0)
上面介绍完了主函数一些代码情况,下面详细的从上面所说的3步来描述ServiceManager如何成为Binder进程通信的守护进程:
第一步:binder_open打开Binder设备操作
位于frameworks/base/cmds/servicemanager/binder.c文件中
//打开binder设备
struct binder_state *binder_open(unsigned mapsize)
{
struct binder_state *bs;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return 0;
}
bs->fd = open("/dev/binder", O_RDWR);
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open device (%s)\n",
strerror(errno));
goto fail_open;
}
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
/* TODO: check version */
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return 0;
}
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
通过binder_become_context_manager函数来完成,该函数位于 frameworks/base/cmds/servicemanager/binder.c文件中,
//成为manager
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
通过调用ioctl文件操作函数来通知Binder驱动程序自己是守护进程,命令号是BINDER_SET_CONTEXT_MGR。
/*
注意binder_handler参数,它是一个函数指针,binder_loop读取请求后将解析这些请求
最后,调用bind_handler完成最终的处理
*/
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
unsigned readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(unsigned));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
//接收请求,交给binder_parse,最终会调用func来处理这些请求
res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
if (res == 0) {
LOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
LOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}