浅谈Service Manager成为Android进程间通信(IPC)机制

上一篇文章Android进程间通信(IPC)机制Binder简要介绍和学习计划简要介绍了Android系统进程间通信机制Binder的总体架构,它由Client、Server、Service Manager和驱动程序Binder四个组件构成。本文着重介绍组件Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能。

相关阅读:Android进程间通信(IPC)机制Binder简要介绍和学习计划 

既然Service Manager组件是用来管理Server并且向Client提供查询Server远程接口的功能,那么,Service Manager就必然要和Server以及Client进行通信了。我们知道,Service Manger、Client和Server三者分别是运行在独立的进程当中,这样它们之间的通信也属于进程间通信了,而且也是采用Binder机制进行进程间通信,因此,Service Manager在充当Binder机制的守护进程的角色的同时,也在充当Server的角色,然而,它是一种特殊的Server,下面我们将会看到它的特殊之处。

       与Service Manager相关的源代码较多,这里不会完整去分析每一行代码,主要是带着Service Manager是如何成为整个Binder机制中的守护进程这条主线来一步一步地深入分析相关源代码,包括从用户空间到内核空间的相关源代码。希望读者在阅读下面的内容之前,先阅读一下前一篇文章提到的两个参考资料Android深入浅出之Binder机制Android Binder设计与实现,熟悉相关概念和数据结构,这有助于理解下面要分析的源代码。

Service Manager在用户空间的源代码位于frameworks/base/cmds/servicemanager目录下,主要是由binder.h、binder.c和service_manager.c三个文件组成。Service Manager的入口位于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)) {           LOGE("cannot become context manager (%s)\n", strerror(errno));           return -1;       }          svcmgr_handle = svcmgr;       binder_loop(bs, svcmgr_handler);       return 0;   }  

        main函数主要有三个功能:一是打开Binder设备文件;二是告诉Binder驱动程序自己是Binder上下文管理者,即我们前面所说的守护进程;三是进入一个无穷循环,充当Server的角色,等待Client的请求。进入这三个功能之间,先来看一下这里用到的结构体binder_state、宏BINDER_SERVICE_MANAGER的定义:

struct binder_state定义在frameworks/base/cmds/servicemanager/binder.c文件中:

struct binder_state   {       int fd;       void *mapped;       unsigned mapsize;   };  

        fd是文件描述符,即表示打开的/dev/binder设备文件描述符;mapped是把设备文件/dev/binder映射到进程空间的起始地址;mapsize是上述内存映射空间的大小。

宏BINDER_SERVICE_MANAGER定义frameworks/base/cmds/servicemanager/binder.h文件中:

 

/* the one magic object */   #define BINDER_SERVICE_MANAGER ((void*) 0)  

        它表示Service Manager的句柄为0。Binder通信机制使用句柄来代表远程接口,这个句柄的意义和Windows编程中用到的句柄是差不多的概念。前面说到,Service Manager在充当守护进程的同时,它充当Server的角色,当它作为远程接口使用时,它的句柄值便为0,这就是它的特殊之处,其余的Server的远程接口句柄值都是一个大于0 而且由Binder驱动程序自动进行分配的。

函数首先是执行打开Binder设备文件的操作binder_open,这个函数位于frameworks/base/cmds/servicemanager/binder.c文件中:

 

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;   }  

       通过文件操作函数open来打开/dev/binder设备文件。设备文件/dev/binder是在Binder驱动程序模块初始化的时候创建的,我们先看一下这个设备文件的创建过程。进入到kernel/common/drivers/staging/android目录中,打开binder.c文件,可以看到模块初始化入口binder_init:

 

static 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   };      static int __init binder_init(void)   {       int ret;          binder_proc_dir_entry_root = proc_mkdir("binder", NULL);       if (binder_proc_dir_entry_root)           binder_proc_dir_entry_proc = proc_mkdir("proc", binder_proc_dir_entry_root);       ret = misc_register(&binder_miscdev);       if (binder_proc_dir_entry_root) {           create_proc_read_entry("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL);           create_proc_read_entry("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL);           create_proc_read_entry("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL);           create_proc_read_entry("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log);           create_proc_read_entry("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_failed);       }       return ret;   }      device_initcall(binder_init);  

        创建设备文件的地方在misc_register函数里面,关于misc设备的注册,我们在Android日志系统驱动程序Logger源代码分析一文中有提到,有兴趣的读取不访去了解一下。其余的逻辑主要是在/proc目录创建各种Binder相关的文件,供用户访问。从设备文件的操作方法binder_fops可以看出,前面的binder_open函数执行语句:

bs->fd = open("/dev/binder", O_RDWR);  

就进入到Binder驱动程序的binder_open函数了:

 

static int binder_open(struct inode *nodp, struct file *filp)   {       struct binder_proc *proc;          if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)           printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid);          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);       mutex_lock(&binder_lock);       binder_stats.obj_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;       mutex_unlock(&binder_lock);          if (binder_proc_dir_entry_proc) {           char strbuf[11];           snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);           remove_proc_entry(strbuf, binder_proc_dir_entry_proc);           create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc);       }          return 0;   }  

         这个函数的主要作用是创建一个struct binder_proc数据结构来保存打开设备文件/dev/binder的进程的上下文信息,并且将这个进程上下文信息保存在打开文件结构struct file的私有数据成员变量private_data中,这样,在执行其它文件操作时,就通过打开文件结构struct file来取回这个进程上下文信息了。这个进程上下文信息同时还会保存在一个全局哈希表binder_procs中,驱动程序内部使用。binder_procs定义在文件的开头:

 

static HLIST_HEAD(binder_procs);  

        结构体struct binder_proc也是定义在kernel/common/drivers/staging/android/binder.c文件中:

 

struct binder_proc {       struct hlist_node proc_node;       struct rb_root threads;       struct rb_root nodes;       struct rb_root refs_by_desc;       struct rb_root refs_by_node;       int pid;       struct vm_area_struct *vma;       struct task_struct *tsk;       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;       struct rb_root allocated_buffers;       size_t free_async_space;          struct page **pages;       size_t buffer_size;       uint32_t buffer_free;       struct list_head todo;       wait_queue_head_t wait;       struct binder_stats stats;       struct list_head delivered_death;       int max_threads;       int requested_threads;       int requested_threads_started;       int ready_threads;       long default_priority;   };  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwjjww.html