ServiceManager是什么
-
ServiceManager(SM)是Binder机制的大管家,主要用于管理系统中各种服务,无论是注册服务还是获取服务,都要通过SM。(binder通信过程中,更多的情形是BpBinder与BBinder之间的通信,例如ActivityManagerProxy与AcitivityManagerService之间的通信)
这里提到的ServiceManager是Native层的ServiceManager(C++)而不是Framework层的 ServiceManager(Java)
-
ServiceManager是Binder ipc通信中的守护进程,也是一个Binder服务
ServiceManager没有采用libbinder中的多线程模型来与Binder驱动通信,而是自行编写了binder.c直接和Binder驱动来通信,并且只有一个循环binder_loop来进行读取和处理事务,这样的好处是简单而高效
启动过程
源码链接http://androidxref.com/9.0.0_r3/xref/system/core/rootdir/init.rc
由rc语法
Commands: trigger < event >
触发事件event,由一个action触发到另一个action队列
late-init的时候触发事件post-fs,而late-init在init.cpp的main方法中添加到执行队列,调用am.ExecuteOneCommand();按照插入的顺序执行触发器对应的命令
而Android.bp中把编译出的可执行文件的名字定为servicemanager
Android.bp学习笔记
对应的rc文件是servicemanager.rc
对应的源码service_manager.c
bs = binder_open(128*1024) 打开binder驱动,申请128k字节大小的内存空间
binder_become_context_manager(bs) 设为守护进程,注册成为binder服务的大管家,
binder_loop(bs, svcmgr_handler) 进入无限循环,处理client端发来的请求
binder_open
-
binder_state结构体记录了binder的相关信息
-
open 打开binder驱动,返回文件描述符
当用户空间调用open方法,最终会调用到binder驱动的binder_open方法。
该方法会在binder驱动层创建一个binder_proc对象,再将binder_proc对象赋值给fd->private_data,同时放入binder_procs全局链表中 -
mmap 通过系统调用,mmap内存映射,mmap必须是 page的整数倍(4kb的整数倍)
当用户空间调用mmap方法,最终会调用到binder驱动的binder_mmap方法。
该方法会在binder驱动层创建Binder_buffer对象,并放入当前binder_proc的proc->buffers链表中
binder_become_context_manager
binder_become_context_manager方法中调用ioctl方法,传入binder的文件描述符,BINDER_SET_CONTEXT_MGR指令,ioctl方法对应binder驱动的binder_ioctl方法
-
binder_ioctl()
kernel/drivers/staging/android/binder.c
-
binder_ioctl_set_ctx_mgr
kernel/drivers/staging/android/binder.c
-
binder_new_node
这一步主要的工作是: -
在Binder驱动层创建binder_node结构体对象
-
将当前binder_proc加入到binder_node的node->proc
-
创建binder_node的async_todo和binder_work两个队列。
binder_loop
binder_write_read结构体(kernel\drivers\staging\android\binder.h)
binder_write()
binder_ioctl()
ioctl调用到binder驱动的binder_ioctl方法
此处将用户空间的binder_write_read结构体通过copy_from_user() 拷贝到内核空间(内核空间中触发的copy_from_user,注意此处只是拷贝的命令信息并不是“一次拷贝”的数据)
接上面代码
binder_write通过ioctl()将BC_ENTER_LOOPER命令发送给binder驱动,此时bwr只有write_buffer有数据,进入binder_thread_write()方法。 接下来进入for循环,执行ioctl(),此时bwr只有read_buffer有数据,那么进入binder_thread_read()方法。
binder_parse()
由于binder_loop()传入的第二个参数是svcmgr_hander,也就是func,所以当有请求到来的时候,调用svcmgr_handler
服务都是使用svcinfo结构体表示
其中的handle值事服务在注册的过程中,由服务所在进程那一端确定的。
bio_put_ref,将查询到的handle 封装到reply
binder_loop这一步的主要工作是
进入循环状态,等待Client端的请求,通过binder_parse处理BR_XXX命令
ServiceManager的核心工作
do_find_service
do_add_service
注册服务主要的工作:
* svc_can_register检查selinux权限是否满足
* find_svc 服务检索,根据服务名查询匹配的服务
* svcinfo_death 释放服务,当查询到已经存在的服务,先释放服务
binder_link_to_death 注册死亡通知
根据binder_loop的介绍binder_write,最终会调用到binder驱动层的binder_ioctl_write_read方法
write_size>0,进入binder_thread_write
binder_thread_write
(kernel\drivers\staging\android\binder.c)
接上面的代码
此方法中的proc, thread都是指当前servicemanager进程的信息. 此时TODO队列有数据,则进入binder_thread_read.
那么哪些场景会向队列增加BINDER_WORK_DEAD_BINDER事务呢? 那就是当binder所在进程死亡后,会调用binder_release方法, 然后调用binder_node_release.这个过程便会发出死亡通知的回调.
而binder_thread_read中
接上面的代码
将命令BR_DEAD_BINDER写到用户空间, 此处的cookie是前面传递的svcinfo_death. 当binder_loop下一次 执行binder_parse的过程便会处理该消息。
binder_parse
(/frameworks/native/cmds/servicemanager/binder.c)
由do_add_service方法中si->death.func = (void*) svcinfo_death,所以death->func是执行svcinfo_death()
在binder_release中,向binder驱动中写入BC_RELEASE命令,最终在binder驱动中执行binder_dec_ref(ref,1)来减少binder_node的以用。
总结
流程图
ServiceManager是所有服务的大管家,通过权限控制进程是否有权注册服务,通过比较服务名字的字符串来查找Service,也可以通过ServiceManage获取Server进程的情况。
ServiceManage进程建立了跟所有想起注册服务的死亡通知,当服务所在进程死亡后,会通知给ServiceManage
ServiceManager的核心工作:注册服务、查询服务
注册流程:
打开binder驱动,并调用mmap()方法分配128k的内存映射空间:binder_open();
通知binder驱动使其成为守护进程:binder_become_context_manager();
验证selinux权限,判断进程是否有权注册或查看指定服务;
进入循环状态,等待Client端的请求:binder_loop()。
注册服务的过程,根据服务名称,但同一个服务已注册,重新注册前会先移除之前的注册信息;
死亡通知: 当binder所在进程死亡后,会调用binder_release方法,然后调用binder_node_release.这个过程便会发出死亡通知的回调.
参考
http://gityuan.com/2015/11/07/binder-start-sm/
总结和学习中,如有错误欢迎指正