基于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信息。