Android8.0.0-r4——ServiceManager

     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函数


代码路径:/frameworks/native/cmds/servicemanager/binder.c
(http://androidxref.com/8.0.0_r4/xref/frameworks/native/cmds/servicemanager/binder.c)
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进程的通信请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值