Binder之ServiceManager启动

ServiceManager涉及到服务的注册和代理服务的获取,是android Binder 通信的关键


启动

init进程解析init.rc配置文件来启动ServiceManager进程(在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。ServiceManager的启动脚本在 servicemanager.rc中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/system/core/rootdir/init.rc 
start servicemanager //319行 ,执行servicemanager.rc脚本

/frameworks/native/cmds/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
……

//servicemanager的入口函数在service_manager.c中:
//frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char** argv){
……
struct binder_state *bs;
driver = "/dev/binder";

bs = binder_open(driver, 128*1024);//1
……
if (binder_become_context_manager(bs)) {//2
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
……
binder_loop(bs, svcmgr_handler);//3
}

//其中bainder_state结构体
struct binder_state{
int fd; //binder设备的文件描述符
void *mapped; //binder设备文件映射到进程的地址空间
size_t mapsize; //内存映射后,系统分配的地址空间的大小,默认为128KB
};
  1. binder_open 打开binder设备,申请128k大小的内存空间
  2. binder_become_context_manager 将自己注册为管理者
  3. binder_loop 循环等待处理客户端的请求
binder_open 打开binder设备
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//frameworks/native/cmds/servicemanager/binder.c
//open()、mmap()最后都是调用kernel层Binder驱动的binder_open()、binder_mmap()
struct binder_state *binder_open(......){
......
//打开binder设备
bs->fd = open(driver, O_RDWR | O_CLOEXEC);//1
......
//binder驱动内申请的空间 映射到 SM进程,映射完毕后会将地址空间的起始地址和大小保存在binder_state 结构体中的mapped和mapsize变量中。
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//2
......
}

//https://www.androidos.net.cn/androidkernel/3.4/xref/drivers/staging/android/binder.c
static int binder_open(struct inode *nodp, struct file *filp){
//这个结构体代表Binder进程
struct binder_proc *proc;
......
//分配内存空间
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
......
filp->private_data = proc;//3
......
}
binder_become_context_manager 注册自己为服务管理者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//ioctl会调用kernel层Binder驱动的binder_ioctl()
int binder_become_context_manager(struct binder_state *bs){
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

//https://www.androidos.net.cn/androidkernel/3.4/xref/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
......
//在binder_open中可以看到这是Binder进程
struct binder_proc *proc = filp->private_data; //1
......
//获取binder线程
thread = binder_get_thread(proc);//2
......
//全局变量binder_context_mgr_node代表的是Binder机制的上下文管理者对应的一个Binder node对象,如果它不为NULL,说明此前自身已经被注册为Binder的上下文管理者了,Binder的上下文管理
//唯一性
switch (cmd) {
case BINDER_SET_CONTEXT_MGR:
if (binder_context_mgr_node != NULL) {//3
printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
}
......
//创建一个binder_node对象赋值给binder_context_mgr_node
binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
}
binder_loop 循环等待处理客户端的请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func){
......
//发送BC_ENTER_LOOPER指令到binder驱动
//这样当前线程 (ServiceManager的主线程)就成为了一个Binder线程
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));//1
......
for (;;) {
......
//不断发送BINDER_WRITE_READ指令去查询是否有新的请求
//如果有,就交给binder_parse处理,如果没有就阻塞
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//2
......
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed,func);//3
......
}
......
}

//frameworks/native/cmds/servicemanager/binder.c
int binder_write(struct binder_state *bs, void *data, size_t len){
//定义binder_write_read结构体
struct binder_write_read bwr;//1
......
//此处data = BC_ENTER_LOOPER
bwr.write_buffer = (uintptr_t) data;//2
......
//调用binder_ioctl,发送BINDER_WRITE_READ指令
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//3
......
return res;
}

//https://www.androidos.net.cn/androidkernel/3.4/xref/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
......
void __user *ubuf = (void __user *)arg;
......
switch (cmd)
case BINDER_WRITE_READ:
struct binder_write_read bwr;
//把用户空间数据ubuf拷贝出来保存到内核数据 bwr(binder_write_read结构体)中。
copy_from_user(&bwr, ubuf, sizeof(bwr))
......
if (bwr.write_size > 0) {//2
//这里处理BC_ENTER_LOOPER指令(write_buffer = BC_ENTER_LOOPER)
//其内部会将目标线程的状态设置为BINDER_LOOPER_STATE_ENTERED,这样目标线程就是一个Binder线程。
ret = binder_thread_write(proc, thread, (void __user*)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);//3
}
......
//内核数据拷贝到用户空间
copy_to_user(ubuf, &bwr, sizeof(bwr))
......
}
copy_from_user / copy_to_user
1
2
3
//用__user修饰的指针说明指向用户空间的内存;函数成功则返回0,否则返回没有拷贝成功的数据字节数
long copy_to_user(void __user *to, const void *from, unsigned long n)
long copy_from_user(void *to, const void __user * from, unsigned long n)

用户空间是虚拟地址,和内核空间的地址不一样,不能简单的使用memecopy来进行数据拷贝,copy_to_user和copy_from_user在拷贝数据之前会进行地址安全检测


总结:

ServiceManager的启动过程实际上就是分析ServiceManager的入口函数,在入口函数中主要做了三件事:

  1. binder_open 打开binder设备,申请128k大小的内存空间并映射到SM进程
  2. binder_become_context_manager 将自己注册为管理者
  3. binder_loop 循环等待处理客户端的请求