这里来分析一下ServiceManager的启动过程,ServiceManager是管理系统所有服务的进程,用于提供API给用户注册以及查找相应的服务。ServiceManager直接与binder驱动打交道去实现跨进程的IPC。下面首先来看一下ServiceManager启动的地方,它是在init.rc脚本,这个脚本会被init程序解析并执行其中不同的服务。首先来看ServiceManager的启动命令:
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
上面命令会启动路径/system/bin/servicemanager下面的servicemanager可执行程序,并且这个service的名字也是servicemanager,后面会设置这个service的一些属性。可执行程序servicemanager的源文件是service_manager.c,我们来分析它的main函数:
int main(int argc, char **argv)
{
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
binder_state结构如下:
struct binder_state
{
int fd;
void *mapped;
unsigned mapsize;
};
fd描述打开的/dev/binder文件句柄;mapped是映射到用户空间的内存起始地址;mapsize为映射内存区域的大小。BINDER_SERVICE_MANAGER在binder.h中定义为(void*) 0,因为ServiceManager在binder驱动中的hander ID为0,后面分析中我们会看到。接着调用binder_open去打开binder设备文件并映射到用户空间:
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;
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return 0;
}
首先调用open方法去打开设备文件,我们到binder驱动文件中去分析,代码在kernel-3.4/drivers/staging/android/binder.c:
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "binder",
.fops = &binder_fops
};
根据上面的定义,open和mmap方法最终会调用到file_operations里面的binder_open和binder_mmap两个函数指针。首先来看binder驱动中的binder_open方法:
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
get_task_struct(current);
proc->tsk = current;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);
hlist_add_head(&proc->proc_node, &binder_procs);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
binder_unlock(__func__);
return 0;
}
binder_open首先构造一个binder_proc数据结构,binder_proc保存了打开/dev/binder设备进程的上下文信息,先来总体看一下binder_proc的结构:
struct binder_proc {
struct hlist_node proc_node; //用来链接所有的binder_proc到binder_procs的节点
struct rb_root threads; //binder threads红黑树根节点,链接当前进程上所有的binder thread
struct rb_root nodes; //nodes红黑树根节点,存放当前进程上所有的binder实体
struct rb_root refs_by_desc; //引用binder的红黑树根节点,通过decs id号来索引
struct rb_root refs_by_node; //引用binder的红黑树根节点,通过node来索引
int pid; //当前进程的group leader的进程号
struct vm_area_struct *vma; //用户空间内存映射地址
struct mm_struct *vma_vm_mm; //内核空间内存映射地址
struct task_struct *tsk; //保存当前进程的task struck
struct files_struct *files; //保存打开的文件
struct hlist_node deferred_work_node;
int deferred_work;
void *buffer; //内核虚拟空间起始地址
ptrdiff_t user_buffer_offset; //用户映射地址和内核虚拟空间地址之间的偏移
struct list_head buffers;
struct rb_root free_buffers; //free buffer的红黑树根节点
struct rb_root allocated_buffers;
size_t free_async_space;
struct page **pages; //实际物理内存页面
size_t buffer_size; //分配的内存大小
uint32_t buffer_free; //剩下的free buffer
struct list_head todo; //待完成的事务
wait_queue_head_t wait; //等待信号
struct binder_stats stats; //当前binder的状态记录
struct list_head delivered_death;
int max_threads;
int requested_threads;
int requested_threads_started;
int ready_threads;
long default_priority;
struct dentry *debugfs_entry;
};
上面的binder_open方法会去初始化binder_proc中的todo、wait等链表,并把当前binder_proc保存在/dev/binder打开文件filp的private_data中,方便以后访问。接着来看binder_mmap函数:
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
struct binder_proc *proc = filp->private_data;
const char *failure_string;