- 浏览: 21515141 次
- 性别:
- 来自: 杭州
最新评论
-
ZY199266:
配置文件还需要额外的配置ma
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
ZY199266:
我的一访问为什么是 /mavenwebdemo/WEB-I ...
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
lvgaga:
我又一个问题就是 如果像你的这种形式写。配置文件还需要额外的 ...
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
lvgaga:
我的一访问为什么是 /mavenwebdemo/WEB-I ...
Android 客户端通过内置API(HttpClient) 访问 服务器(用Spring MVC 架构) 返回的json数据全过程 -
y1210251848:
你的那个错误应该是项目所使用的目标框架不支持吧
log4net配置(web中使用log4net,把web.config放在单独的文件中)
浅谈Service Manager成为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函数:
- intmain(intargc,char**argv)
- {
- structbinder_state*bs;
- void*svcmgr=BINDER_SERVICE_MANAGER;
- bs=binder_open(128*1024);
- if(binder_become_context_manager(bs)){
- LOGE("cannotbecomecontextmanager(%s)\n",strerror(errno));
- return-1;
- }
- svcmgr_handle=svcmgr;
- binder_loop(bs,svcmgr_handler);
- return0;
- }
structbinder_state定义在frameworks/base/cmds/servicemanager/binder.c文件中:
- structbinder_state
- {
- intfd;
- void*mapped;
- unsignedmapsize;
- };
宏BINDER_SERVICE_MANAGER定义frameworks/base/cmds/servicemanager/binder.h文件中:
- /*theonemagicobject*/
- #defineBINDER_SERVICE_MANAGER((void*)0)
函数首先是执行打开Binder设备文件的操作binder_open,这个函数位于frameworks/base/cmds/servicemanager/binder.c文件中:
- structbinder_state*binder_open(unsignedmapsize)
- {
- structbinder_state*bs;
- bs=malloc(sizeof(*bs));
- if(!bs){
- errno=ENOMEM;
- return0;
- }
- bs->fd=open("/dev/binder",O_RDWR);
- if(bs->fd<0){
- fprintf(stderr,"binder:cannotopendevice(%s)\n",
- strerror(errno));
- gotofail_open;
- }
- bs->mapsize=mapsize;
- bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->fd,0);
- if(bs->mapped==MAP_FAILED){
- fprintf(stderr,"binder:cannotmapdevice(%s)\n",
- strerror(errno));
- gotofail_map;
- }
- /*TODO:checkversion*/
- returnbs;
- fail_map:
- close(bs->fd);
- fail_open:
- free(bs);
- return0;
- }
- staticstructfile_operationsbinder_fops={
- .owner=THIS_MODULE,
- .poll=binder_poll,
- .unlocked_ioctl=binder_ioctl,
- .mmap=binder_mmap,
- .open=binder_open,
- .flush=binder_flush,
- .release=binder_release,
- };
- staticstructmiscdevicebinder_miscdev={
- .minor=MISC_DYNAMIC_MINOR,
- .name="binder",
- .fops=&binder_fops
- };
- staticint__initbinder_init(void)
- {
- intret;
- 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);
- }
- returnret;
- }
- 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函数了:
- staticintbinder_open(structinode*nodp,structfile*filp)
- {
- structbinder_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){
- charstrbuf[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);
- }
- return0;
- }
- staticHLIST_HEAD(binder_procs);
- structbinder_proc{
- structhlist_nodeproc_node;
- structrb_rootthreads;
- structrb_rootnodes;
- structrb_rootrefs_by_desc;
- structrb_rootrefs_by_node;
- intpid;
- structvm_area_struct*vma;
- structtask_struct*tsk;
- structfiles_struct*files;
- structhlist_nodedeferred_work_node;
- intdeferred_work;
- void*buffer;
- ptrdiff_tuser_buffer_offset;
- structlist_headbuffers;
- structrb_rootfree_buffers;
- structrb_rootallocated_buffers;
- size_tfree_async_space;
- structpage**pages;
- size_tbuffer_size;
- uint32_tbuffer_free;
- structlist_headtodo;
- wait_queue_head_twait;
- structbinder_statsstats;
- structlist_headdelivered_death;
- intmax_threads;
- intrequested_threads;
- intrequested_threads_started;
- intready_threads;
- longdefault_priority;
- };
这样,打开设备文件/dev/binder的操作就完成了,接着是对打开的设备文件进行内存映射操作mmap:
- bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->fd,0);
对应Binder驱动程序的binder_mmap函数:
- staticintbinder_mmap(structfile*filp,structvm_area_struct*vma)
- {
- intret;
- structvm_struct*area;
- structbinder_proc*proc=filp->private_data;
- constchar*failure_string;
- structbinder_buffer*buffer;
- if((vma->vm_end-vma->vm_start)>SZ_4M)
- vma->vm_end=vma->vm_start+SZ_4M;
- if(binder_debug_mask&BINDER_DEBUG_OPEN_CLOSE)
- printk(KERN_INFO
- "binder_mmap:%d%lx-%lx(%ldK)vma%lxpagep%lx\n",
- proc->pid,vma->vm_start,vma->vm_end,
- (vma->vm_end-vma->vm_start)/SZ_1K,vma->vm_flags,
- (unsignedlong)pgprot_val(vma->vm_page_prot));
- if(vma->vm_flags&FORBIDDEN_MMAP_FLAGS){
- ret=-EPERM;
- failure_string="badvm_flags";
- gotoerr_bad_arg;
- }
- vma->vm_flags=(vma->vm_flags|VM_DONTCOPY)&~VM_MAYWRITE;
- if(proc->buffer){
- ret=-EBUSY;
- failure_string="alreadymapped";
- gotoerr_already_mapped;
- }
- area=get_vm_area(vma->vm_end-vma->vm_start,VM_IOREMAP);
- if(area==NULL){
- ret=-ENOMEM;
- failure_string="get_vm_area";
- gotoerr_get_vm_area_failed;
- }
- proc->buffer=area->addr;
- proc->user_buffer_offset=vma->vm_start-(uintptr_t)proc->buffer;
- #ifdefCONFIG_CPU_CACHE_VIPT
- if(cache_is_vipt_aliasing()){
- while(CACHE_COLOUR((vma->vm_start^(uint32_t)proc->buffer))){
- printk(KERN_INFO"binder_mmap:%d%lx-%lxmaps%pbadalignment\n",proc->pid,vma->vm_start,vma->vm_end,proc->buffer);
- vma->vm_start+=PAGE_SIZE;
- }
- }
- #endif
- proc->pages=kzalloc(sizeof(proc->pages[0])*((vma->vm_end-vma->vm_start)/PAGE_SIZE),GFP_KERNEL);
- if(proc->pages==NULL){
- ret=-ENOMEM;
- failure_string="allocpagearray";
- gotoerr_alloc_pages_failed;
- }
- proc->buffer_size=vma->vm_end-vma->vm_start;
- vma->vm_ops=&binder_vm_ops;
- vma->vm_private_data=proc;
- if(binder_update_page_range(proc,1,proc->buffer,proc->buffer+PAGE_SIZE,vma)){
- ret=-ENOMEM;
- failure_string="allocsmallbuf";
- gotoerr_alloc_small_buf_failed;
- }
- buffer=proc->buffer;
- INIT_LIST_HEAD(&proc->buffers);
- list_add(&buffer->entry,&proc->buffers);
- buffer->free=1;
- binder_insert_free_buffer(proc,buffer);
- proc->free_async_space=proc->buffer_size/2;
- barrier();
- proc->files=get_files_struct(current);
- proc->vma=vma;
- /*printk(KERN_INFO"binder_mmap:%d%lx-%lxmaps%p\n",proc->pid,vma->vm_start,vma->vm_end,proc->buffer);*/
- return0;
- err_alloc_small_buf_failed:
- kfree(proc->pages);
- proc->pages=NULL;
- err_alloc_pages_failed:
- vfree(proc->buffer);
- proc->buffer=NULL;
- err_get_vm_area_failed:
- err_already_mapped:
- err_bad_arg:
- printk(KERN_ERR"binder_mmap:%d%lx-%lx%sfailed%d\n",proc->pid,vma->vm_start,vma->vm_end,failure_string,ret);
- returnret;
- }
函数首先通过filp->private_data得到在打开设备文件/dev/binder时创建的struct binder_proc结构。内存映射信息放在vma参数中,注意,这里的vma的数据类型是struct vm_area_struct,它表示的是一块连续的虚拟地址空间区域,在函数变量声明的地方,我们还看到有一个类似的结构体struct vm_struct,这个数据结构也是表示一块连续的虚拟地址空间区域,那么,这两者的区别是什么呢?在Linux中,struct vm_area_struct表示的虚拟地址是给进程使用的,而struct vm_struct表示的虚拟地址是给内核使用的,它们对应的物理页面都可以是不连续的。struct vm_area_struct表示的地址空间范围是0~3G,而struct vm_struct表示的地址空间范围是(3G + 896M + 8M) ~ 4G。struct vm_struct表示的地址空间范围为什么不是3G~4G呢?原来,3G ~ (3G + 896M)范围的地址是用来映射连续的物理页面的,这个范围的虚拟地址和对应的实际物理地址有着简单的对应关系,即对应0~896M的物理地址空间,而(3G + 896M) ~ (3G + 896M + 8M)是安全保护区域(例如,所有指向这8M地址空间的指针都是非法的),因此struct vm_struct使用(3G + 896M + 8M) ~ 4G地址空间来映射非连续的物理页面。有关Linux的内存管理知识,可以参考Android学习启动篇一文提到的《Understanding the Linux Kernel》一书中的第8章。
这里为什么会同时使用进程虚拟地址空间和内核虚拟地址空间来映射同一个物理页面呢?这就是Binder进程间通信机制的精髓所在了,同一个物理页面,一方映射到进程虚拟地址空间,一方面映射到内核虚拟地址空间,这样,进程和内核之间就可以减少一次内存拷贝了,提到了进程间通信效率。举个例子如,Client要将一块内存数据传递给Server,一般的做法是,Client将这块数据从它的进程空间拷贝到内核空间中,然后内核再将这个数据从内核空间拷贝到Server的进程空间,这样,Server就可以访问这个数据了。但是在这种方法中,执行了两次内存拷贝操作,而采用我们上面提到的方法,只需要把Client进程空间的数据拷贝一次到内核空间,然后Server与内核共享这个数据就可以了,整个过程只需要执行一次内存拷贝,提高了效率。
binder_mmap的原理讲完了,这个函数的逻辑就好理解了。不过,这里还是先要解释一下struct binder_proc结构体的几个成员变量。buffer成员变量是一个void*指针,它表示要映射的物理内存在内核空间中的起始位置;buffer_size成员变量是一个size_t类型的变量,表示要映射的内存的大小;pages成员变量是一个struct page*类型的数组,struct page是用来描述物理页面的数据结构;user_buffer_offset成员变量是一个ptrdiff_t类型的变量,它表示的是内核使用的虚拟地址与进程使用的虚拟地址之间的差值,即如果某个物理页面在内核空间中对应的虚拟地址是addr的话,那么这个物理页面在进程空间对应的虚拟地址就为addr +user_buffer_offset。
再解释一下Binder驱动程序管理这个内存映射地址空间的方法,即是如何管理buffer ~ (buffer + buffer_size)这段地址空间的,这个地址空间被划分为一段一段来管理,每一段是结构体struct binder_buffer来描述:
- structbinder_buffer{
- structlist_headentry;/*freeandallocatedentriesbyaddesss*/
- structrb_noderb_node;/*freeentrybysizeorallocatedentry*/
- /*byaddress*/
- unsignedfree:1;
- unsignedallow_user_free:1;
- unsignedasync_transaction:1;
- unsigneddebug_id:29;
- structbinder_transaction*transaction;
- structbinder_node*target_node;
- size_tdata_size;
- size_toffsets_size;
- uint8_tdata[0];
- };
终于可以回到binder_mmap这个函数来了,首先是对参数作一些健康体检(sanity check),例如,要映射的内存大小不能超过SIZE_4M,即4M,回到service_manager.c中的main 函数,这里传进来的值是128 * 1024个字节,即128K,这个检查没有问题。通过健康体检后,调用get_vm_area函数获得一个空闲的vm_struct区间,并初始化proc结构体的buffer、user_buffer_offset、pages和buffer_size和成员变量,接着调用binder_update_page_range来为虚拟地址空间proc->buffer ~ proc->buffer + PAGE_SIZE分配一个空闲的物理页面,同时这段地址空间使用一个binder_buffer来描述,分别插入到proc->buffers链表和proc->free_buffers红黑树中去,最后,还初始化了proc结构体的free_async_space、files和vma三个成员变量。
这里,我们继续进入到binder_update_page_range函数中去看一下Binder驱动程序是如何实现把一个物理页面同时映射到内核空间和进程空间去的:
- staticintbinder_update_page_range(structbinder_proc*proc,intallocate,
- void*start,void*end,structvm_area_struct*vma)
- {
- void*page_addr;
- unsignedlonguser_page_addr;
- structvm_structtmp_area;
- structpage**page;
- structmm_struct*mm;
- if(binder_debug_mask&BINDER_DEBUG_BUFFER_ALLOC)
- printk(KERN_INFO"binder:%d:%spages%p-%p\n",
- proc->pid,allocate?"allocate":"free",start,end);
- if(end<=start)
- return0;
- if(vma)
- mm=NULL;
- else
- mm=get_task_mm(proc->tsk);
- if(mm){
- down_write(&mm->mmap_sem);
- vma=proc->vma;
- }
- if(allocate==0)
- gotofree_range;
- if(vma==NULL){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailedto"
- "mappagesinuserspace,novma\n",proc->pid);
- gotoerr_no_vma;
- }
- for(page_addr=start;page_addr<end;page_addr+=PAGE_SIZE){
- intret;
- structpage**page_array_ptr;
- page=&proc->pages[(page_addr-proc->buffer)/PAGE_SIZE];
- BUG_ON(*page);
- *page=alloc_page(GFP_KERNEL|__GFP_ZERO);
- if(*page==NULL){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
- "forpageat%p\n",proc->pid,page_addr);
- gotoerr_alloc_page_failed;
- }
- tmp_area.addr=page_addr;
- tmp_area.size=PAGE_SIZE+PAGE_SIZE/*guardpage?*/;
- page_array_ptr=page;
- ret=map_vm_area(&tmp_area,PAGE_KERNEL,&page_array_ptr);
- if(ret){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
- "tomappageat%pinkernel\n",
- proc->pid,page_addr);
- gotoerr_map_kernel_failed;
- }
- user_page_addr=
- (uintptr_t)page_addr+proc->user_buffer_offset;
- ret=vm_insert_page(vma,user_page_addr,page[0]);
- if(ret){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
- "tomappageat%lxinuserspace\n",
- proc->pid,user_page_addr);
- gotoerr_vm_insert_page_failed;
- }
- /*vm_insert_pagedoesnotseemtoincrementtherefcount*/
- }
- if(mm){
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
- return0;
- free_range:
- for(page_addr=end-PAGE_SIZE;page_addr>=start;
- page_addr-=PAGE_SIZE){
- page=&proc->pages[(page_addr-proc->buffer)/PAGE_SIZE];
- if(vma)
- zap_page_range(vma,(uintptr_t)page_addr+
- proc->user_buffer_offset,PAGE_SIZE,NULL);
- err_vm_insert_page_failed:
- unmap_kernel_range((unsignedlong)page_addr,PAGE_SIZE);
- err_map_kernel_failed:
- __free_page(*page);
- *page=NULL;
- err_alloc_page_failed:
- ;
- }
- err_no_vma:
- if(mm){
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
- return-ENOMEM;
- }
- for(page_addr=start;page_addr<end;page_addr+=PAGE_SIZE){
- intret;
- structpage**page_array_ptr;
- page=&proc->pages[(page_addr-proc->buffer)/PAGE_SIZE];
- BUG_ON(*page);
- *page=alloc_page(GFP_KERNEL|__GFP_ZERO);
- if(*page==NULL){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
- "forpageat%p\n",proc->pid,page_addr);
- gotoerr_alloc_page_failed;
- }
- tmp_area.addr=page_addr;
- tmp_area.size=PAGE_SIZE+PAGE_SIZE/*guardpage?*/;
- page_array_ptr=page;
- ret=map_vm_area(&tmp_area,PAGE_KERNEL,&page_array_ptr);
- if(ret){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
- "tomappageat%pinkernel\n",
- proc->pid,page_addr);
- gotoerr_map_kernel_failed;
- }
- user_page_addr=
- (uintptr_t)page_addr+proc->user_buffer_offset;
- ret=vm_insert_page(vma,user_page_addr,page[0]);
- if(ret){
- printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
- "tomappageat%lxinuserspace\n",
- proc->pid,user_page_addr);
- gotoerr_vm_insert_page_failed;
- }
- /*vm_insert_pagedoesnotseemtoincrementtherefcount*/
- }
这样,frameworks/base/cmds/servicemanager/binder.c文件中的binder_open函数就描述完了,回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函数,下一步就是调用binder_become_context_manager来通知Binder驱动程序自己是Binder机制的上下文管理者,即守护进程。binder_become_context_manager函数位于frameworks/base/cmds/servicemanager/binder.c文件中:
- intbinder_become_context_manager(structbinder_state*bs)
- {
- returnioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0);
- }
- #defineBINDER_SET_CONTEXT_MGR_IOW('b',7,int)
- staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
- {
- intret;
- structbinder_proc*proc=filp->private_data;
- structbinder_thread*thread;
- unsignedintsize=_IOC_SIZE(cmd);
- void__user*ubuf=(void__user*)arg;
- /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
- ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- if(ret)
- returnret;
- mutex_lock(&binder_lock);
- thread=binder_get_thread(proc);
- if(thread==NULL){
- ret=-ENOMEM;
- gotoerr;
- }
- switch(cmd){
- ......
- caseBINDER_SET_CONTEXT_MGR:
- if(binder_context_mgr_node!=NULL){
- printk(KERN_ERR"binder:BINDER_SET_CONTEXT_MGRalreadyset\n");
- ret=-EBUSY;
- gotoerr;
- }
- if(binder_context_mgr_uid!=-1){
- if(binder_context_mgr_uid!=current->cred->euid){
- printk(KERN_ERR"binder:BINDER_SET_"
- "CONTEXT_MGRbaduid%d!=%d\n",
- current->cred->euid,
- binder_context_mgr_uid);
- ret=-EPERM;
- gotoerr;
- }
- }else
- binder_context_mgr_uid=current->cred->euid;
- binder_context_mgr_node=binder_new_node(proc,NULL,NULL);
- if(binder_context_mgr_node==NULL){
- ret=-ENOMEM;
- gotoerr;
- }
- binder_context_mgr_node->local_weak_refs++;
- binder_context_mgr_node->local_strong_refs++;
- binder_context_mgr_node->has_strong_ref=1;
- binder_context_mgr_node->has_weak_ref=1;
- break;
- ......
- default:
- ret=-EINVAL;
- gotoerr;
- }
- ret=0;
- err:
- if(thread)
- thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
- mutex_unlock(&binder_lock);
- wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- if(ret&&ret!=-ERESTARTSYS)
- printk(KERN_INFO"binder:%d:%dioctl%x%lxreturned%d\n",proc->pid,current->pid,cmd,arg,ret);
- returnret;
- }
- structbinder_thread{
- structbinder_proc*proc;
- structrb_noderb_node;
- intpid;
- intlooper;
- structbinder_transaction*transaction_stack;
- structlist_headtodo;
- uint32_treturn_error;/*Writefailed,returnerrorcodeinreadbuf*/
- uint32_treturn_error2;/*Writefailed,returnerrorcodeinread*/
- /*buffer.Usedwhensendingareplytoadeadprocessthat*/
- /*wearealsowaitingon*/
- wait_queue_head_twait;
- structbinder_statsstats;
- };
- enum{
- BINDER_LOOPER_STATE_REGISTERED=0x01,
- BINDER_LOOPER_STATE_ENTERED=0x02,
- BINDER_LOOPER_STATE_EXITED=0x04,
- BINDER_LOOPER_STATE_INVALID=0x08,
- BINDER_LOOPER_STATE_WAITING=0x10,
- BINDER_LOOPER_STATE_NEED_RETURN=0x20
- };
另外一个数据结构是struct binder_node,它表示一个binder实体:
- structbinder_node{
- intdebug_id;
- structbinder_workwork;
- union{
- structrb_noderb_node;
- structhlist_nodedead_node;
- };
- structbinder_proc*proc;
- structhlist_headrefs;
- intinternal_strong_refs;
- intlocal_weak_refs;
- intlocal_strong_refs;
- void__user*ptr;
- void__user*cookie;
- unsignedhas_strong_ref:1;
- unsignedpending_strong_ref:1;
- unsignedhas_weak_ref:1;
- unsignedpending_weak_ref:1;
- unsignedhas_async_transaction:1;
- unsignedaccept_fds:1;
- intmin_priority:8;
- structlist_headasync_todo;
- };
现在回到binder_ioctl函数中,首先是通过filp->private_data获得proc变量,这里binder_mmap函数是一样的。接着通过binder_get_thread函数获得线程信息,我们来看一下这个函数:
- staticstructbinder_thread*binder_get_thread(structbinder_proc*proc)
- {
- structbinder_thread*thread=NULL;
- structrb_node*parent=NULL;
- structrb_node**p=&proc->threads.rb_node;
- while(*p){
- parent=*p;
- thread=rb_entry(parent,structbinder_thread,rb_node);
- if(current->pid<thread->pid)
- p=&(*p)->rb_left;
- elseif(current->pid>thread->pid)
- p=&(*p)->rb_right;
- else
- break;
- }
- if(*p==NULL){
- thread=kzalloc(sizeof(*thread),GFP_KERNEL);
- if(thread==NULL)
- returnNULL;
- binder_stats.obj_created[BINDER_STAT_THREAD]++;
- thread->proc=proc;
- thread->pid=current->pid;
- init_waitqueue_head(&thread->wait);
- INIT_LIST_HEAD(&thread->todo);
- rb_link_node(&thread->rb_node,parent,p);
- rb_insert_color(&thread->rb_node,&proc->threads);
- thread->looper|=BINDER_LOOPER_STATE_NEED_RETURN;
- thread->return_error=BR_OK;
- thread->return_error2=BR_OK;
- }
- returnthread;
- }
回到binder_ioctl函数,继续往下面,有两个全局变量binder_context_mgr_node和binder_context_mgr_uid,它定义如下:
- staticstructbinder_node*binder_context_mgr_node;
- staticuid_tbinder_context_mgr_uid=-1;
- staticstructbinder_node*
- binder_new_node(structbinder_proc*proc,void__user*ptr,void__user*cookie)
- {
- structrb_node**p=&proc->nodes.rb_node;
- structrb_node*parent=NULL;
- structbinder_node*node;
- while(*p){
- parent=*p;
- node=rb_entry(parent,structbinder_node,rb_node);
- if(ptr<node->ptr)
- p=&(*p)->rb_left;
- elseif(ptr>node->ptr)
- p=&(*p)->rb_right;
- else
- returnNULL;
- }
- node=kzalloc(sizeof(*node),GFP_KERNEL);
- if(node==NULL)
- returnNULL;
- binder_stats.obj_created[BINDER_STAT_NODE]++;
- rb_link_node(&node->rb_node,parent,p);
- rb_insert_color(&node->rb_node,&proc->nodes);
- node->debug_id=++binder_last_id;
- node->proc=proc;
- node->ptr=ptr;
- node->cookie=cookie;
- node->work.type=BINDER_WORK_NODE;
- INIT_LIST_HEAD(&node->work.entry);
- INIT_LIST_HEAD(&node->async_todo);
- if(binder_debug_mask&BINDER_DEBUG_INTERNAL_REFS)
- printk(KERN_INFO"binder:%d:%dnode%du%pc%pcreated\n",
- proc->pid,current->pid,node->debug_id,
- node->ptr,node->cookie);
- returnnode;
- }
binder_new_node返回到binder_ioctl函数后,就把新建的binder_node指针保存在binder_context_mgr_node中了,紧接着,又初始化了binder_context_mgr_node的引用计数值。
这样,BINDER_SET_CONTEXT_MGR命令就执行完毕了,binder_ioctl函数返回之前,执行了下面语句:
- if(thread)
- thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
回忆上面执行binder_get_thread时,thread->looper =BINDER_LOOPER_STATE_NEED_RETURN,执行了这条语句后,thread->looper = 0。
回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函数,下一步就是调用binder_loop函数进入循环,等待Client来请求了。binder_loop函数定义在frameworks/base/cmds/servicemanager/binder.c文件中:
- voidbinder_loop(structbinder_state*bs,binder_handlerfunc)
- {
- intres;
- structbinder_write_readbwr;
- unsignedreadbuf[32];
- bwr.write_size=0;
- bwr.write_consumed=0;
- bwr.write_buffer=0;
- readbuf[0]=BC_ENTER_LOOPER;
- binder_write(bs,readbuf,sizeof(unsigned));
- for(;;){
- bwr.read_size=sizeof(readbuf);
- bwr.read_consumed=0;
- bwr.read_buffer=(unsigned)readbuf;
- res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr);
- if(res<0){
- LOGE("binder_loop:ioctlfailed(%s)\n",strerror(errno));
- break;
- }
- res=binder_parse(bs,0,readbuf,bwr.read_consumed,func);
- if(res==0){
- LOGE("binder_loop:unexpectedreply?!\n");
- break;
- }
- if(res<0){
- LOGE("binder_loop:ioerror%d%s\n",res,strerror(errno));
- break;
- }
- }
- }
这里又要介绍一下设备文件/dev/binder文件操作函数ioctl的操作码BINDER_WRITE_READ了,首先看定义:
- #defineBINDER_WRITE_READ_IOWR('b',1,structbinder_write_read)
- structbinder_write_read{
- signedlongwrite_size;/*bytestowrite*/
- signedlongwrite_consumed;/*bytesconsumedbydriver*/
- unsignedlongwrite_buffer;
- signedlongread_size;/*bytestoread*/
- signedlongread_consumed;/*bytesconsumedbydriver*/
- unsignedlongread_buffer;
- };
- structbinder_transaction_data{
- /*ThefirsttwoareonlyusedforbcTRANSACTIONandbrTRANSACTION,
- *identifyingthetargetandcontentsofthetransaction.
- */
- union{
- size_thandle;/*targetdescriptorofcommandtransaction*/
- void*ptr;/*targetdescriptorofreturntransaction*/
- }target;
- void*cookie;/*targetobjectcookie*/
- unsignedintcode;/*transactioncommand*/
- /*Generalinformationaboutthetransaction.*/
- unsignedintflags;
- pid_tsender_pid;
- uid_tsender_euid;
- size_tdata_size;/*numberofbytesofdata*/
- size_toffsets_size;/*numberofbytesofoffsets*/
- /*Ifthistransactionisinline,thedataimmediately
- *followshere;otherwise,itendswithapointerto
- *thedatabuffer.
- */
- union{
- struct{
- /*transactiondata*/
- constvoid*buffer;
- /*offsetsfrombuffertoflat_binder_objectstructs*/
- constvoid*offsets;
- }ptr;
- uint8_tbuf[8];
- }data;
- };
flags成员变量表示事务标志:
- enumtransaction_flags{
- TF_ONE_WAY=0x01,/*thisisaone-waycall:async,noreturn*/
- TF_ROOT_OBJECT=0x04,/*contentsarethecomponent'srootobject*/
- TF_STATUS_CODE=0x08,/*contentsarea32-bitstatuscode*/
- TF_ACCEPT_FDS=0x10,/*allowreplieswithfiledescriptors*/
- };
sender_pid和sender_euid表示发送者进程的pid和euid。
data_size表示data.buffer缓冲区的大小,offsets_size表示data.offsets缓冲区的大小。这里需要解释一下data成员变量,命令的真正要传输的数据就保存在data.buffer缓冲区中,前面的一成员变量都是一些用来描述数据的特征的。data.buffer所表示的缓冲区数据分为两类,一类是普通数据,Binder驱动程序不关心,一类是Binder实体或者Binder引用,这需要Binder驱动程序介入处理。为什么呢?想想,如果一个进程A传递了一个Binder实体或Binder引用给进程B,那么,Binder驱动程序就需要介入维护这个Binder实体或者引用的引用计数,防止B进程还在使用这个Binder实体时,A却销毁这个实体,这样的话,B进程就会crash了。所以在传输数据时,如果数据中含有Binder实体和Binder引和,就需要告诉Binder驱动程序它们的具体位置,以便Binder驱动程序能够去维护它们。data.offsets的作用就在这里了,它指定在data.buffer缓冲区中,所有Binder实体或者引用的偏移位置。每一个Binder实体或者引用,通过struct flat_binder_object 来表示:
- /*
- *ThisistheflattenedrepresentationofaBinderobjectfortransfer
- *betweenprocesses.The'offsets'suppliedaspartofabindertransaction
- *containsoffsetsintothedatawherethesestructuresoccur.TheBinder
- *drivertakescareofre-writingthestructuretypeanddataasitmoves
- *betweenprocesses.
- */
- structflat_binder_object{
- /*8bytesforlarge_flat_header.*/
- unsignedlongtype;
- unsignedlongflags;
- /*8bytesofdata.*/
- union{
- void*binder;/*localobject*/
- signedlonghandle;/*remoteobject*/
- };
- /*extradataassociatedwithlocalobject*/
- void*cookie;
- };
- enum{
- BINDER_TYPE_BINDER=B_PACK_CHARS('s','b','*',B_TYPE_LARGE),
- BINDER_TYPE_WEAK_BINDER=B_PACK_CHARS('w','b','*',B_TYPE_LARGE),
- BINDER_TYPE_HANDLE=B_PACK_CHARS('s','h','*',B_TYPE_LARGE),
- BINDER_TYPE_WEAK_HANDLE=B_PACK_CHARS('w','h','*',B_TYPE_LARGE),
- BINDER_TYPE_FD=B_PACK_CHARS('f','d','*',B_TYPE_LARGE),
- };
type和flags的具体意义可以参考Android Binder设计与实现一文。
最后,binder表示这是一个Binder实体,handle表示这是一个Binder引用,当这是一个Binder实体时,cookie才有意义,表示附加数据,由进程自己解释。
数据结构分析完了,回到binder_loop函数中,首先是执行BC_ENTER_LOOPER命令:
- readbuf[0]=BC_ENTER_LOOPER;
- binder_write(bs,readbuf,sizeof(unsigned));
- intbinder_write(structbinder_state*bs,void*data,unsignedlen)
- {
- structbinder_write_readbwr;
- intres;
- bwr.write_size=len;
- bwr.write_consumed=0;
- bwr.write_buffer=(unsigned)data;
- bwr.read_size=0;
- bwr.read_consumed=0;
- bwr.read_buffer=0;
- res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr);
- if(res<0){
- fprintf(stderr,"binder_write:ioctlfailed(%s)\n",
- strerror(errno));
- }
- returnres;
- }
- staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
- {
- intret;
- structbinder_proc*proc=filp->private_data;
- structbinder_thread*thread;
- unsignedintsize=_IOC_SIZE(cmd);
- void__user*ubuf=(void__user*)arg;
- /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
- ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- if(ret)
- returnret;
- mutex_lock(&binder_lock);
- thread=binder_get_thread(proc);
- if(thread==NULL){
- ret=-ENOMEM;
- gotoerr;
- }
- switch(cmd){
- caseBINDER_WRITE_READ:{
- structbinder_write_readbwr;
- if(size!=sizeof(structbinder_write_read)){
- ret=-EINVAL;
- gotoerr;
- }
- if(copy_from_user(&bwr,ubuf,sizeof(bwr))){
- ret=-EFAULT;
- gotoerr;
- }
- if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
- printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",
- proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);
- if(bwr.write_size>0){
- ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
- if(ret<0){
- bwr.read_consumed=0;
- if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
- ret=-EFAULT;
- gotoerr;
- }
- }
- if(bwr.read_size>0){
- ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);
- if(!list_empty(&proc->todo))
- wake_up_interruptible(&proc->wait);
- if(ret<0){
- if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
- ret=-EFAULT;
- gotoerr;
- }
- }
- if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
- printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",
- proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);
- if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
- ret=-EFAULT;
- gotoerr;
- }
- break;
- }
- ......
- default:
- ret=-EINVAL;
- gotoerr;
- }
- ret=0;
- err:
- if(thread)
- thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
- mutex_unlock(&binder_lock);
- wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- if(ret&&ret!=-ERESTARTSYS)
- printk(KERN_INFO"binder:%d:%dioctl%x%lxreturned%d\n",proc->pid,current->pid,cmd,arg,ret);
- returnret;
- }
首先是通过copy_from_user(&bwr, ubuf, sizeof(bwr))语句把用户传递进来的参数转换成struct binder_write_read结构体,并保存在本地变量bwr中,这里可以看出bwr.write_size等于4,于是进入binder_thread_write函数,这里我们只关注BC_ENTER_LOOPER相关的代码:
- int
- binder_thread_write(structbinder_proc*proc,structbinder_thread*thread,
- void__user*buffer,intsize,signedlong*consumed)
- {
- uint32_tcmd;
- void__user*ptr=buffer+*consumed;
- void__user*end=buffer+size;
- while(ptr<end&&thread->return_error==BR_OK){
- if(get_user(cmd,(uint32_t__user*)ptr))
- return-EFAULT;
- ptr+=sizeof(uint32_t);
- if(_IOC_NR(cmd)<ARRAY_SIZE(binder_stats.bc)){
- binder_stats.bc[_IOC_NR(cmd)]++;
- proc->stats.bc[_IOC_NR(cmd)]++;
- thread->stats.bc[_IOC_NR(cmd)]++;
- }
- switch(cmd){
- ......
- caseBC_ENTER_LOOPER:
- if(binder_debug_mask&BINDER_DEBUG_THREADS)
- printk(KERN_INFO"binder:%d:%dBC_ENTER_LOOPER\n",
- proc->pid,thread->pid);
- if(thread->looper&BINDER_LOOPER_STATE_REGISTERED){
- thread->looper|=BINDER_LOOPER_STATE_INVALID;
- binder_user_error("binder:%d:%dERROR:"
- "BC_ENTER_LOOPERcalledafter"
- "BC_REGISTER_LOOPER\n",
- proc->pid,thread->pid);
- }
- thread->looper|=BINDER_LOOPER_STATE_ENTERED;
- break;
- ......
- default:
- printk(KERN_ERR"binder:%d:%dunknowncommand%d\n",proc->pid,thread->pid,cmd);
- return-EINVAL;
- }
- *consumed=ptr-buffer;
- }
- return0;
- }
回到binder_ioctl函数,由于bwr.read_size == 0,binder_thread_read函数就不会被执行了,这样,binder_ioctl的任务就完成了。
回到binder_loop函数,进入for循环:
- for(;;){
- bwr.read_size=sizeof(readbuf);
- bwr.read_consumed=0;
- bwr.read_buffer=(unsigned)readbuf;
- res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr);
- if(res<0){
- LOGE("binder_loop:ioctlfailed(%s)\n",strerror(errno));
- break;
- }
- res=binder_parse(bs,0,readbuf,bwr.read_consumed,func);
- if(res==0){
- LOGE("binder_loop:unexpectedreply?!\n");
- break;
- }
- if(res<0){
- LOGE("binder_loop:ioerror%d%s\n",res,strerror(errno));
- break;
- }
- }
- bwr.write_size=0;
- bwr.write_consumed=0;
- bwr.write_buffer=0;
- readbuf[0]=BC_ENTER_LOOPER;
- bwr.read_size=sizeof(readbuf);
- bwr.read_consumed=0;
- bwr.read_buffer=(unsigned)readbuf;
- staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
- {
- intret;
- structbinder_proc*proc=filp->private_data;
- structbinder_thread*thread;
- unsignedintsize=_IOC_SIZE(cmd);
- void__user*ubuf=(void__user*)arg;
- /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
- ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- if(ret)
- returnret;
- mutex_lock(&binder_lock);
- thread=binder_get_thread(proc);
- if(thread==NULL){
- ret=-ENOMEM;
- gotoerr;
- }
- switch(cmd){
- caseBINDER_WRITE_READ:{
- structbinder_write_readbwr;
- if(size!=sizeof(structbinder_write_read)){
- ret=-EINVAL;
- gotoerr;
- }
- if(copy_from_user(&bwr,ubuf,sizeof(bwr))){
- ret=-EFAULT;
- gotoerr;
- }
- if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
- printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",
- proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);
- if(bwr.write_size>0){
- ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
- if(ret<0){
- bwr.read_consumed=0;
- if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
- ret=-EFAULT;
- gotoerr;
- }
- }
- if(bwr.read_size>0){
- ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);
- if(!list_empty(&proc->todo))
- wake_up_interruptible(&proc->wait);
- if(ret<0){
- if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
- ret=-EFAULT;
- gotoerr;
- }
- }
- if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
- printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",
- proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);
- if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
- ret=-EFAULT;
- gotoerr;
- }
- break;
- }
- ......
- default:
- ret=-EINVAL;
- gotoerr;
- }
- ret=0;
- err:
- if(thread)
- thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
- mutex_unlock(&binder_lock);
- wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- if(ret&&ret!=-ERESTARTSYS)
- printk(KERN_INFO"binder:%d:%dioctl%x%lxreturned%d\n",proc->pid,current->pid,cmd,arg,ret);
- returnret;
- }
- staticint
- binder_thread_read(structbinder_proc*proc,structbinder_thread*thread,
- void__user*buffer,intsize,signedlong*consumed,intnon_block)
- {
- void__user*ptr=buffer+*consumed;
- void__user*end=buffer+size;
- intret=0;
- intwait_for_proc_work;
- if(*consumed==0){
- if(put_user(BR_NOOP,(uint32_t__user*)ptr))
- return-EFAULT;
- ptr+=sizeof(uint32_t);
- }
- retry:
- wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);
- if(thread->return_error!=BR_OK&&ptr<end){
- if(thread->return_error2!=BR_OK){
- if(put_user(thread->return_error2,(uint32_t__user*)ptr))
- return-EFAULT;
- ptr+=sizeof(uint32_t);
- if(ptr==end)
- gotodone;
- thread->return_error2=BR_OK;
- }
- if(put_user(thread->return_error,(uint32_t__user*)ptr))
- return-EFAULT;
- ptr+=sizeof(uint32_t);
- thread->return_error=BR_OK;
- gotodone;
- }
- thread->looper|=BINDER_LOOPER_STATE_WAITING;
- if(wait_for_proc_work)
- proc->ready_threads++;
- mutex_unlock(&binder_lock);
- if(wait_for_proc_work){
- if(!(thread->looper&(BINDER_LOOPER_STATE_REGISTERED|
- BINDER_LOOPER_STATE_ENTERED))){
- binder_user_error("binder:%d:%dERROR:Threadwaiting"
- "forprocessworkbeforecallingBC_REGISTER_"
- "LOOPERorBC_ENTER_LOOPER(state%x)\n",
- proc->pid,thread->pid,thread->looper);
- wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
- }
- binder_set_nice(proc->default_priority);
- if(non_block){
- if(!binder_has_proc_work(proc,thread))
- ret=-EAGAIN;
- }else
- ret=wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc,thread));
- }else{
- if(non_block){
- if(!binder_has_thread_work(thread))
- ret=-EAGAIN;
- }else
- ret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));
- }
- .......
- }
至此,我们就从源代码一步一步地分析完Service Manager是如何成为Android进程间通信(IPC)机制Binder守护进程的了。总结一下,Service Manager是成为Android进程间通信(IPC)机制Binder守护进程的过程是这样的:
1. 打开/dev/binder文件:open("/dev/binder", O_RDWR);
2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
3. 通知Binder驱动程序它是守护进程:binder_become_context_manager(bs);
4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);
在这个过程中,在Binder驱动程序中建立了一个struct binder_proc结构、一个struct binder_thread结构和一个struct binder_node结构,这样,Service Manager就在Android系统的进程间通信机制Binder担负起守护进程的职责了
相关推荐
浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
Android进程间通信(IPC)机制Binder简要介绍和学习计划
【一图流】_02_一张图看懂 Android 进程间通信(IPC)Binder机制: 此图表述了Android系统_进程间通信(IPC)机制全部体系,其中重点放在 Android系统中 重用 的 Binder机制 上,详尽细致,希望对大家有用;
Android 进程间通信机制 (Binder) 介绍
在前面一篇文章浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路中,介绍了Service Manager是如何成为Binder机制的守护进程的。既然作为守护进程,Service Manager的职责当然就是为Server和...
android 的ipc通信机制,详细说明了IPC的通信原理
Android进程间通信-Binder机制详解
简要介绍Android IPC机制Binder
Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
二.Service Manager 成为Binder 守护进程之路 三.Server 和Client 获得Service Manager 接口之路 四.Server 启动过程源代码分析 五.Client 获得Server 远程接口过程源代码分析 六.应用程序框架层的Java 接口源...
Deep Dive into Android IPC-Binder Framework 深入Android IPB/Binder 框架
Android 进程间通信AIDL demo 博客地址:http://blog.csdn.net/bigboysunshine/article/details/70228223
ANDROID系统进程间通信BINDER机制在低层的C接口源代码文件分析[归纳].pdf
在前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中,介绍了在Android系统中Binder进程间通信机制中的Server角色是如何获得Service Manager远程接口的,即...
Android_之_Binder与进程间通信
本文主要介绍 Android进程间通信(IPC)机制Binder简要介绍,这里介绍了Binder机制如何实现进程通信机制,有研究Android源码的朋友可以看下
Deep Dive into Android IPC & Binder.pdf Deep Dive into Android IPC/Binder Framework at Android Builders Summit 2013 Binder Overview IPC Advantages of Binder Binder vs Intent/ContentProvider/...