Binder系列3—启动ServiceManager

基于Android 6.0的源码剖析, 本文详细地讲解了ServiceManager启动流程


一. 概述

ServiceManager是Binder IPC通信过程中的守护进程,本身也是一个Binder服务,但并没有采用libbinder中的多线程模型来与Binder驱动通信,而是自行编写了binder.c直接和Binder驱动来通信,并且只有一个循环binder_loop来进行读取和处理事务,这样的好处是简单而高效。

ServiceManager本身工作相对简单,其功能:查询和注册服务。 对于Binder IPC通信过程中,其实更多的情形是BpBinder和BBinder之间的通信,比如ActivityManagerProxy和ActivityManagerService之间的通信等。

1.1 流程图


启动过程主要以下几个阶段:

打开binder驱动:binder_open;

注册成为binder服务的大管家:binder_become_context_manager;

进入无限循环,处理client端发来的请求:binder_loop;

二. 启动过程

ServiceManager是由init进程通过解析init.rc文件而创建的,其所对应的可执行程序/system/bin/servicemanager,所对应的源文件是service_manager.c,进程名为/system/bin/servicemanager。


启动Service Manager的入口函数是service_manager.c中的main()方法,代码如下:

2.1 main

[ -> service_manager.c]


2.2 binder_open

[-> servicemanager/binder.c]


打开binder驱动相关操作:

先调用open()打开binder设备,open()方法经过系统调用,进入Binder驱动,然后调用方法binder_open(),该方法会在Binder驱动层创建一个binder_proc对象,再将binder_proc对象赋值给fd->private_data,同时放入全局链表binder_procs。再通过ioctl()检验当前binder版本与Binder驱动层的版本是否一致。

调用mmap()进行内存映射,同理mmap()方法经过系统调用,对应于Binder驱动层的binder_mmap()方法,该方法会在Binder驱动层创建Binder_buffer对象,并放入当前binder_proc的proc->buffers链表。

2.2.1 binder_state

[-> servicemanager/binder.c]


2.3 binder_become_context_manager

[-> servicemanager/binder.c]


成为上下文的管理者,整个系统中只有一个这样的管理者。 通过ioctl()方法经过系统调用,对应于Binder驱动层的binder_ioctl()方法.

2.3.1 binder_ioctl


[-> kernel/drivers/android/binder.c]


根据参数BINDER_SET_CONTEXT_MGR,最终调用binder_ioctl_set_ctx_mgr()方法,这个过程会持有binder_main_lock。

2.3.2 binder_ioctl_set_ctx_mgr

[-> kernel/drivers/android/binder.c]


进入binder驱动,在Binder驱动中定义的静态变量


创建了全局的binder_node对象binder_context_mgr_node,并将binder_context_mgr_node的强弱引用各加1.

2.3.3 binder_new_node

[-> kernel/drivers/android/binder.c]



在Binder驱动层创建binder_node结构体对象,并将当前binder_proc加入到binder_node的node->proc。并创建binder_node的async_todo和binder_work两个队列。

2.4 binder_loop

[-> servicemanager/binder.c]


进入循环读写操作,由main()方法传递过来的参数func指向svcmgr_handler。

binder_write通过ioctl()将BC_ENTER_LOOPER命令发送给binder驱动,此时bwr只有write_buffer有数据,进入binder_thread_write()方法。 接下来进入for循环,执行ioctl(),此时bwr只有read_buffer有数据,那么进入binder_thread_read()方法。

2.4.1 binder_write

[-> servicemanager/binder.c]


根据传递进来的参数,初始化bwr,其中write_size大小为4,write_buffer指向缓冲区的起始地址,其内容为BC_ENTER_LOOPER请求协议号。通过ioctl将bwr数据发送给binder驱动,则调用其binder_ioctl方法,如下:

2.4.2 binder_ioctl

[-> kernel/drivers/android/binder.c]


2.4.3 binder_ioctl_write_read

[-> kernel/drivers/android/binder.c]


此处将用户空间的binder_write_read结构体 拷贝到内核空间.

2.4.4 binder_thread_write

[-> kernel/drivers/android/binder.c]

从bwr.write_buffer拿出cmd数据,此处为BC_ENTER_LOOPER. 可见上层本次调用binder_write()方法,主要是完成设置当前线程的looper状态为BINDER_LOOPER_STATE_ENTERED。

2.5 binder_parse

[-> servicemanager/binder.c]

解析binder信息,此处参数ptr指向BC_ENTER_LOOPER,func指向svcmgr_handler。故有请求到来,则调用svcmgr_handler。

2.5.1 bio_init

[-> servicemanager/binder.c]


其中


2.5.2 bio_init_from_txn

[-> servicemanager/binder.c]


将readbuf的数据赋给bio对象的data

2.6 svcmgr_handler

[-> service_manager.c]

......

该方法的功能:查询服务,注册服务,以及列举所有服务

2.6.1 svcinfo


每一个服务用svcinfo结构体来表示,该handle值是在注册服务的过程中,由服务所在进程那一端所确定的。

三. 核心工作

servicemanager的核心工作就是注册服务和查询服务。

3.1 do_find_service

[-> service_manager.c]

uint32_tdo_find_service(structbinder_state *bs,


查询到目标服务,并返回该服务所对应的handle

3.1.1 find_svc


从svclist服务列表中,根据服务名遍历查找是否已经注册。当服务已存在svclist,则返回相应的服务名,否则返回NULL。

当找到服务的handle, 则调用bio_put_ref(reply, handle),将handle封装到reply.

3.1.2 bio_put_ref


3.1.3 bio_alloc_obj


3.1.4 bio_alloc


3.2 do_add_service

[-> service_manager.c]


注册服务的分以下3部分工作:

svc_can_register:检查权限,检查selinux权限是否满足;

find_svc:服务检索,根据服务名来查询匹配的服务;

svcinfo_death:释放服务,当查询到已存在同名的服务,则先清理该服务信息,再将当前的服务加入到服务列表svclist;

3.2.1 svc_can_register

[-> service_manager.c]


3.2.2 svcinfo_death

[-> service_manager.c]


3.2.3 bio_get_ref

[-> servicemanager/binder.c]


3.3 binder_link_to_death

[-> servicemanager/binder.c]


binder_write经过跟小节2.4.1一样的方式, 进入Binder driver后,直接调用后进入binder_thread_write, 处理BC_REQUEST_DEATH_NOTIFICATION命令

3.3.1 binder_ioctl_write_read

[-> kernel/drivers/android/binder.c]


3.3.2 binder_thread_write

[-> kernel/drivers/android/binder.c]

.....

此方法中的proc, thread都是指当前servicemanager进程的信息. 此时TODO队列有数据,则进入binder_thread_read.

那么哪些场景会向队列增加BINDER_WORK_DEAD_BINDER事务呢? 那就是当binder所在进程死亡后,会调用binder_release方法, 然后调用binder_node_release.这个过程便会发出死亡通知的回调.

3.3.3 binder_thread_read

将命令BR_DEAD_BINDER写到用户空间, 此处的cookie是前面传递的svcinfo_death. 当binder_loop下一次 执行binder_parse的过程便会处理该消息。

3.3.4 binder_parse

[-> servicemanager/binder.c]

由小节3.2的 si->death.func = (void*) svcinfo_death; 可知此处 death->func便是执行svcinfo_death()方法.

3.3.5 svcinfo_death

[-> service_manager.c]


3.3.6 binder_release

[-> service_manager.c]


向Binder Driver写入BC_RELEASE命令, 最终进入Binder Driver后执行binder_dec_ref(ref, 1)来减少binder node的引用.

3.4 binder_send_reply

[-> servicemanager/binder.c]

当小节2.5执行binder_parse方法,先调用svcmgr_handler(),再然后执行binder_send_reply过程。该方法会调用 [小节2.4.1] binder_write进入binder驱动后,将BC_FREE_BUFFER和BC_REPLY命令协议发送给Binder驱动,向client端发送reply. 其中data的数据区中保存的是TYPE为HANDLE.

四. 总结

ServiceManger集中管理系统内的所有服务,通过权限控制进程是否有权注册服务,通过字符串名称来查找对应的Service; 由于ServiceManger进程建立跟所有向其注册服务的死亡通知, 那么当服务所在进程死亡后, 会只需告知ServiceManager. 每个Client通过查询ServiceManager可获取Server进程的情况,降低所有Client进程直接检测会导致负载过重。

ServiceManager启动流程:

打开binder驱动,并调用mmap()方法分配128k的内存映射空间:binder_open();

通知binder驱动使其成为守护进程:binder_become_context_manager();

验证selinux权限,判断进程是否有权注册或查看指定服务;

进入循环状态,等待Client端的请求:binder_loop()。

注册服务的过程,根据服务名称,但同一个服务已注册,重新注册前会先移除之前的注册信息;

死亡通知: 当binder所在进程死亡后,会调用binder_release方法,然后调用binder_node_release.这个过程便会发出死亡通知的回调.

ServiceManager最核心的两个功能为查询和注册服务:

注册服务:记录服务名和handle信息,保存到svclist列表;

查询服务:根据服务名查询相应的的handle信息。

推荐阅读更多精彩内容