ServiceManager是Binder进程间通信机制的核心组件之一,它扮演着Binder进程间通信机制上下文管理者( ContextManager)的角色,同时负责管理系统中的Service组件,并且向Client组件提供获取Service代理对象的服务。
Service Manager运行在一个独立的进程中, 因此,Service组件和Client组件也需要通过进程间通信机制来和它交互, 而采用的进程间通信机制正好也是Binder进程间通信机制。 从这个角度来看, Service Manager除了是Binder进程间通信机制的上下文管理者( Context Manager )之外, 它也是一个特殊的Service组件。
Service Manager是由init进程负责启动的, 而init进程是在系统启动时启动的, 因此, ServiceManager也是在系统启动时启动的。
如果不懂init进程解析,请参考
Android8.0.0-r4系统的启动过程:http://blog.csdn.net/nwpushuai/article/details/79346665
Android8.0.0-r4 init.rc文件解析: http://blog.csdn.net/nwpushuai/article/details/79368065
ServiceManager的rc文件:
代码路径:/frameworks/native/cmds/servicemanager/servicemanager.rc
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/servicemanager.rc)
1service servicemanager /system/bin/servicemanager #关键字service表明Service Manager是以服务的形式启动的 2 class core animation 3 user system #关键字user表明Service Manager是以系统用户system的身份运行的 4 group system readproc 5 critical #关键字critical表明ServiceManager是系统中的一个关键服务。在系统的运行过程中,关键服务是不可退出的,一旦退出,就会被系统重启,但是如果一个关键服务在4分钟内退出的次数大于4,那么系统就会重启,然后进入恢复模式 6 onrestart restart healthd #关键字onrestart表示一旦Service Manager被系统重启,此进程将被重启 7 onrestart restart zygote 8 onrestart restart audioserver 9 onrestart restart media 10 onrestart restart surfaceflinger 11 onrestart restart inputflinger 12 onrestart restart drm 13 onrestart restart cameraserver 14 writepid /dev/cpuset/system-background/tasks #关键字writepid表示将pid写入给定的文件。
1、打开和映射Binder设备文件
1.1 调用binder_open函数
代码路径:/frameworks/native/cmds/servicemanager/service_manager.c
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/service_manager.c)
362int main(int argc, char** argv) 363{ 364 struct binder_state *bs; 365 union selinux_callback cb; 366 char *driver; 367 368 if (argc > 1) { 369 driver = argv[1]; 370 } else { 371 driver = "/dev/binder"; 372 } 373 374 bs = binder_open(driver, 128*1024);//参数mapsize的大小为128×1024, 即128K 386 387 if (binder_become_context_manager(bs)) { 388 ALOGE("cannot become context manager (%s)\n", strerror(errno)); 389 return -1; 390 } 413 414 415 binder_loop(bs, svcmgr_handler); 416 417 return 0; 418}
在374行调用binder_open函数
1.2 binder_open函数
代码路径:/frameworks/native/cmds/servicemanager/binder.c
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/binder.c)
97struct binder_state *binder_open(const char* driver, size_t mapsize) 98{ 99 struct binder_state *bs; 100 struct binder_version vers; 101 102 bs = malloc(sizeof(*bs)); 103 if (!bs) { 104 errno = ENOMEM; 105 return NULL; 106 } 107 108 bs->fd = open(driver, O_RDWR | O_CLOEXEC);//调用函数open打开设备文件/dev/binder 109 if (bs->fd < 0) { 110 fprintf(stderr,"binder: cannot open %s (%s)\n", 111 driver, strerror(errno)); 112 goto fail_open; 113 } 114 115 if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || 116 (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { 117 fprintf(stderr, 118 "binder: kernel driver version (%d) differs from user space version (%d)\n", 119 vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); 120 goto fail_open; 121 } 122 123 bs->mapsize = mapsize; 124 bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//调用函数mmap将设备文件/dev/binder映射到进程的地址空间 125 if (bs->mapped == MAP_FAILED) { 126 fprintf(stderr,"binder: cannot map device (%s)\n", 127 strerror(errno)); 128 goto fail_map; 129 } 130 131 return bs;//将binder_state结构体返回给调用者 132 133fail_map: 134 close(bs->fd); 135fail_open: 136 free(bs); 137 return NULL; 138}
108行当使用进程函数open 打开设备文件/dev/binder时, Binder驱动程序中的函数binder_open就会被调用, 它会为当前进程创建 一个binder_proc结构体, 用来描述当前进程的Binder进程间通信状态。
124行请求Binder驱动程序为进程分配128K大小的内核缓冲区。映射后得到的地址空间的起始地址和大小分别保存在一个binder_state结构体bs的成员变量mapped和mapsize中
2、注册为 Binder进程间通信机制的上下文管理者
Service Manager要成为Binder进程间通信机制的上下文管理者, 就必须要通过IO控制命令BINDER_ SET_CONTEXT_MGR将自己注册到Binder驱动程序中, 这是通过调用函数binder_become_context_ manager来实现的。
代码路径:/frameworks/native/cmds/servicemanager/service_manager.c
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/service_manager.c)
362int main(int argc, char** argv) 363{ 364 struct binder_state *bs; 365 union selinux_callback cb; 366 char *driver; 367 368 if (argc > 1) { 369 driver = argv[1]; 370 } else { 371 driver = "/dev/binder"; 372 } 373 374 bs = binder_open(driver, 128*1024); 386 387 if (binder_become_context_manager(bs)) { 388 ALOGE("cannot become context manager (%s)\n", strerror(errno)); 389 return -1; 390 } 413 414 415 binder_loop(bs, svcmgr_handler); 416 417 return 0; 418}
在387行调用binder_become_context_manager函数
147int binder_become_context_manager(struct binder_state *bs) 148{ 149 return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); 150}
ServiceManager对应的Binder本地对象是一个虚拟的对象,并且它的地址值等于0,因此函数binder_become_context_manager就将IO控制命令BINDER_SET_CONTEXT_MGR的参数设置为0。
3、调用函数binder_loop来循环等待和处理Client进程的通信请求
由于Service Manager需要在系统运行期间为Service组件和Client组件提供服务, 因此, 它就需要通过一个无限循环来等待和处理Service组件和Client组件的进程间通信请求, 这是通过调用函数binder_loop 来实现的
代码路径:/frameworks/native/cmds/servicemanager/service_manager.c
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/service_manager.c)
362int main(int argc, char** argv) 363{ 364 struct binder_state *bs; 365 union selinux_callback cb; 366 char *driver; 367 368 if (argc > 1) { 369 driver = argv[1]; 370 } else { 371 driver = "/dev/binder"; 372 } 373 374 bs = binder_open(driver, 128*1024);//参数mapsize的大小为128×1024, 即128K 386 387 if (binder_become_context_manager(bs)) { 388 ALOGE("cannot become context manager (%s)\n", strerror(errno)); 389 return -1; 390 } 413 414 415 binder_loop(bs, svcmgr_handler); 416 417 return 0; 418}
在415行调用binder_loop函数
代码路径:/frameworks/native/cmds/servicemanager/binder.c
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/binder.c)389void binder_loop(struct binder_state *bs, binder_handler func) 390{ 391 int res; 392 struct binder_write_read bwr; 393 uint32_t readbuf[32]; 394 395 bwr.write_size = 0; 396 bwr.write_consumed = 0; 397 bwr.write_buffer = 0; 398 399 readbuf[0] = BC_ENTER_LOOPER;//将BC_ENTER_LOOPER协议代码写入到缓冲区read buf中 400 binder_write(bs, readbuf, sizeof(uint32_t));//调用函数 binder_write将它发送到Binder驱动程序中 401 402 for (;;) { 403 bwr.read_size = sizeof(readbuf); 404 bwr.read_consumed = 0; 405 bwr.read_buffer = (uintptr_t) readbuf; 406 407 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 408 409 if (res < 0) { 410 ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); 411 break; 412 } 413 414 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); 415 if (res == 0) { 416 ALOGE("binder_loop: unexpected reply?!\n"); 417 break; 418 } 419 if (res < 0) { 420 ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); 421 break; 422 } 423 } 424}
一个线程要通过协议BC_ENTER_LOOPER或者BC_REGISTER_LOOPER将自己注册为Binder线程,以便Binder驱动程序可以将进程间通信请求分发给它处理。 由于ServiceManager进程的主线程是主动成为一个Binder线程的, 因此,它就使用BC_ENTER_LOOPER协议将自己注册到Binder驱动程序中。
152int binder_write(struct binder_state *bs, void *data, size_t len)
153{
154 struct binder_write_read bwr;
155 int res;
156
157 bwr.write_size = len;
158 bwr.write_consumed = 0;
159 bwr.write_buffer = (uintptr_t) data;
160 bwr.read_size = 0;
161 bwr.read_consumed = 0;
162 bwr.read_buffer = 0;
163 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
164 if (res < 0) {
165 fprintf(stderr,"binder_write: ioctl failed (%s)\n",
166 strerror(errno));
167 }
168 return res;
169}
由于BC_ENTER_LOOPER协议是通过IO控制命令BINDER_WRITE_READ发送到Binder驱动程序中的,而IO控制命令BINDER_WRITE_READ后面跟的参数是一个binder_write_read结构体, 因此, 在154行首先定义一个binder_write_read结构体bwr, 接着在159行将参数data所指向的一块缓冲区作为它的输入缓冲区。将binder_write_read结构体bwr的输出缓冲区设置为空, 这样, 当前线程将 自己注册到Binder驱动程序中之后, 就会马上返回到用户空间, 而不会在Binder驱动程序中等待Client 进程的通信请求。 由于参数data所指向的一块缓冲区的内容已经被设置为BC_ENTER_LOOPER协议代码, 因此, 接下来在163行就可以调用函数ioctl将当前线程注册到Binder驱动程序中了。
函数binder_thread_write处理完成BC_ENTER_LOOPER协议之后, 就返回到函数binder_ioctl中, 后者接着又返回到用户空间中, l:!PService Manager进程的函数binder_write中, 最后返回到函数binder_loop 中。
在函数binder_loop中, 不断使用IO控制命令BINDER_WRITE_READ来检查Binder 驱动程序是否有新的进程间通信请求需要它来处理。 如果有, 就将它们交给函数binder_parse来处理;否则, 当前线程就会在Binder驱动程序中睡眠等待, 直到有新的进程间通信请求到来为止。
4、总结:
Service Manager的启动过程由三个步骤组成:第一步是调用函数binder_open打开设备文件/dev/binder, 以及将它映射到本进程的地址空间;第二步是调用函数binder_become_context_manager将自己注册为 Binder进程间通信机制的上下文管理者;第三步是调用函数binder_loop来循环等待和处理Client进程的通信请求