概述:
Service Manager是整个Binder机制的守护进程,用来管理开发者创建的Server,并且向Client提供查询Server远程接口(即句柄)的功能。
注:
- 当Service Manager向Client提供查询Server远程接口时,Service Manager为特殊的Server,它的句柄为0。其他Server的句柄是由Binder驱动程序自动分配的。Binder通信机制使用句柄来代表远程接口
- Service Manager也是通过Binder机制与Server和Client进行通信的。
Service Manager是如何成为守护进程的:
int main(int argc, char **argv)
{
struct binder_state *bs;
//#define BINDER_SERVICE_MANAGER ((void*) 0)
//表示Service Manager的句柄为0
void *svcmgr = BINDER_SERVICE_MANAGER;
//打开Binder驱动程序的设备文件/dev/binder
//建立128K内存映射,映射打开的设备文件/dev/binder
bs = binder_open(128*1024);
//将Service Manager注册到Binder,成为Binder上下文管理者(守护进程)
if (binder_become_context_manager(bs)) {
LOGE("cannot become context manager (%s)\n",strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
//进入死循环(binder_loop),充当Server的角色,等待Client的请求
//即,监听来自Binder的消息
binder_loop(bs, svcmgr_handler);
return 0;
}
struct binder_state
{
int fd; //文件描述符,即表示打开的/dev/binder设备文件描述符
void *mapped; //把设备文件/dev/binder映射到进程空间的起始地址
unsigned mapsize; //上述内存映射空间的大小
};
struct binder_state *binder_open(unsigned mapsize)
{
struct binder_state *bs;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return 0;
}
bs->fd = open("/dev/binder", O_RDWR);
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open device (%s)\n",
strerror(errno));
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;
}
/* TODO: check version */
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return 0;
}
映射打开的设备文件/dev/binder:
同时使用进程虚拟地址空间和内核虚拟地址空间来映射同一个物理页面,这样,进程和内核之间就可以减少一次内存拷贝了,提到了进程间通信效率。
比如,Client要将一块内存数据传递给Server,一般的做法是,Client将这块数据从它的进程空间拷贝到内核空间中,然后内核再将这个数据从内核空间拷贝到Server的进程空间,这样,Server就可以访问这个数据了。但是在这种方法中,执行了两次内存拷贝操作,而采用我们上面提到的方法,只需要把Client进程空间的数据拷贝一次到内核空间,然后Server与内核共享这个数据就可以了,整个过程只需要执行一次内存拷贝,提高了效率。
一个进程打开设备文件/dev/binder时,它的上下文消息会保存在文件结构struct file的私有数据成员变量private_data中。在执行其它文件操作时,就通过打开文件结构struct file来取回这个进程上下文信息了。
这个进程上下文信息同时还会保存在一个全局哈希表binder_procs中,供Binder驱动程序内部使用。
总结:
1. 打开/dev/binder文件
2. 建立128K内存映射
3. 通知Binder驱动程序它是守护进程:
4. 进入循环等待Client的请求