目录
引言
概念
启动
流程图
main
binder_open
binder_become_context_manager
binder_ioctl
binder_ioctl_set_ctx_mgr
binder_new_node
binder_loop
binder_write
binder_ioctl
binder_ioctl_write_read
binder_thread_write
binder_parse
bio_init
bio_init_from_txn
svcmgr_handler
svcinfo
查询服务
do_find_service
find_svc
bio_put_ref
bio_alloc_obj
bio_alloc
do_add_service
注册服务
svc_can_register
svcinfo_death
bio_get_ref
binder_link_to_death
binder_ioctl_write_read
binder_thread_write
binder_thread_read
引言
ServiceManager是Binder IPC通信中的守护进程,就是为Binder IPC通信的实现服务的。所以ServiceManager本身就是一个服务,而且是binder服务。
ServiceManager有两个特点:
1、没有采用libbinder中的多线程模型来与Binder驱动通信,而是通过自信编写的binder.c直接和Binder驱动通信,并且只有一个循环binder_loop来读取和处理事务,这样才能保持简单高效
2、ServiceManager功能主要有两个:注册服务和查询服务。
概念
ServiceManager启动流程(精简版):
1)打开binder驱动
2)注册为上下文管理者
3)进入loop循环,处理事务
ServiceManager最核心的两个功能:
注册服务:记录服务名和handler,保存到svclist列表
查询服务:根据服务名查询相应的handler信息
启动
流程图
framework/native/cmds/servicemanager/
- service_manager.c
- binder.c
kernel/drivers/ (不同Linux分支路径略有不同)
- android/binder.c
ServiceManager是由init进程创建的
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
onrestart restart keystore
onrestart restart gatekeeperd
onrestart restart thermalservice
writepid /dev/cpuset/system-background/tasks
shutdown critical
main
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
bs = binder_open(driver, 128*1024);
if (!bs) {
#ifdef VENDORSERVICEMANAGER
ALOGW("failed to open binder driver %s\n", driver);
while (true) {
sleep(UINT_MAX);
}
#else
ALOGE("failed to open binder driver %s\n", driver);
#endif
return -1;
}
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
cb.func_log = selinux_vendor_log_callback;
#else
cb.func_log = selinux_log_callback;
#endif
selinux_set_callback(SELINUX_CB_LOG, cb);
#ifdef VENDORSERVICEMANAGER
sehandle = selinux_android_vendor_service_context_handle();
#else
sehandle = selinux_android_service_context_handle();
#endif
selinux_status_open(true);
if (sehandle == NULL) {
ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
abort();
}
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
binder_loop(bs, svcmgr_handler);
return 0;
}
ServiceManager启动流程(普通版):
1)打开binder驱动,并调用mmap方法分配128K的内存映射空间:binder_open
2)注册成上下文管理者:binder_become_context_manager
3)验证selinux权限,判断进程是否有权限注册或查看指定服务
4)进入循环,等待client的请求:bind_loop
binder_open
struct binder_state
{
int fd;
void *mapped;
size_t mapsize;
};
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open %s (%s)\n",
driver, strerror(errno));
goto fail_open;
}
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
fprintf(stderr,
"binder: kernel driver version (%d) differs from user space version (%d)\n",
vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
goto fail_open;
}
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
void binder_close(struct binder_state *bs)
{
munmap(bs->mapped, bs->mapsize);
close(bs->fd);
free(bs);
}
用户空间通过open的方法会调用到driver的open方法,创建binder_proc结构体对象,再将binder_proc对象赋值给fd->private_data,同时放入全局链表binder_procs
通过ioctl(bs->fd, BINDER_VERSION, &vers)可以获取驱动的binder版本。
调用mmap()进行内存映射,同理mmap()方法经过系统调用,对应于Binder驱动层的binder_mmap()方法,该方法会在Binder驱动层创建Binder_buffer对象,并放入当前binder_proc的proc->buffers链表。
int fd; // dev/binder的文件描述符
void *mapped; //指向mmap的内存地址
size_t mapsize; //分配的内存大小,默认为128KB
binder_become_context_manager
成为上下文的管理者,整个系统中只有一个这样的管理者。 通过ioctl()方法经过系统调用,对应于Binder驱动层的binder_ioctl()方法.
binder_ioctl
根据参数BINDER_SET_CONTEXT_MGR,最终调用binder_ioctl_set_ctx_mgr()方法,这个过程会持有binder_main_lock。
binder_ioctl_set_ctx_mgr
创建了全局的binder_node对象binder_context_mgr_node,并将binder_context_mgr_node的强弱引用各加1.
binder_new_node
在Binder驱动层创建binder_node结构体对象,并将当前binder_proc加入到binder_node的node->proc。并创建binder_node的async_todo和binder_work两个队列。
binder_loop
进入循环读写操作,由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()方法。
binder_write
根据传递进来的参数,初始化bwr,其中write_size大小为4,write_buffer指向缓冲区的起始地址,其内容为BC_ENTER_LOOPER请求协议号。通过ioctl将bwr数据发送给binder驱动,则调用其binder_ioctl方法,如下:
binder_ioctl
binder_ioctl_write_read
binder_thread_write
从bwr.write_buffer拿出cmd数据,此处为BC_ENTER_LOOPER. 可见上层本次调用binder_write()方法,主要是完成设置当前线程的looper状态为BINDER_LOOPER_STATE_ENTERED。
binder_parse
解析binder信息,此处参数ptr指向BC_ENTER_LOOPER,func指向svcmgr_handler。故有请求到来,则调用svcmgr_handler。
bio_init
bio_init_from_txn
svcmgr_handler
该方法的功能:查询服务,注册服务,以及列举所有服务
svcinfo
每一个服务用svcinfo结构体来表示,该handle值是在注册服务的过程中,由服务所在进程那一端所确定的。
查询服务
do_find_service
查询到目标服务,并返回该服务所对应的handle
find_svc
从svclist服务列表中,根据服务名遍历查找是否已经注册。当服务已存在svclist,则返回相应的服务名,否则返回NULL。
当找到服务的handle, 则调用bio_put_ref(reply, handle),将handle封装到reply.
bio_put_ref
bio_alloc_obj
bio_alloc
do_add_service
注册服务
注册服务的分以下3部分工作:
- svc_can_register:检查权限,检查selinux权限是否满足;
- find_svc:服务检索,根据服务名来查询匹配的服务;
- svcinfo_death:释放服务,当查询到已存在同名的服务,则先清理该服务信息,再将当前的服务加入到服务列表svclist;
svc_can_register
svcinfo_death
bio_get_ref
binder_link_to_death
binder_write, 进入Binder driver后,直接调用后进入binder_thread_write, 处理BC_REQUEST_DEATH_NOTIFICATION命令
binder_ioctl_write_read
binder_thread_write
此方法中的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的过程便会处理该消息。