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

在Android系统中,每一个应用程序都是由一些Activity和Service组成的,一般Service运行在独立的进程中,而Activity有可能运行在同一个进程中,也有可能运行在不同的进程中。那么,不在同一个进程的Activity或者Service是如何通信的呢?这就是本文中要介绍的Binder进程间通信机制了。

我们知道,Android系统是基于Linux内核的,而Linux内核继承和兼容了丰富的Unix系统进程间通信(IPC)机制。有传统的管道(Pipe)、信号(Signal)和跟踪(Trace),这三项通信手段只能用于父进程与子进程之间,或者兄弟进程之间;后来又增加了命令管道(Named Pipe),使得进程间通信不再局限于父子进程或者兄弟进程之间;为了更好地支持商业应用中的事务处理,在AT&T的Unix系统V中,又增加了三种称为“System V IPC”的进程间通信机制,分别是报文队列(Message)、共享内存(Share Memory)和信号量(Semaphore);后来BSD Unix对“System V IPC”机制进行了重要的扩充,提供了一种称为插口(Socket)的进程间通信机制。若想进一步详细了解这些进程间通信机制,建议参考Android学习启动篇一文中提到《Linux内核源代码情景分析》一书。

但是,Android系统没有采用上述提到的各种进程间通信机制,而是采用Binder机制,难道是因为考虑到了移动设备硬件性能较差、内存较低的特点?不得而知。Binder其实也不是Android提出来的一套新的进程间通信机制,它是基于OpenBinder来实现的。OpenBinder最先是由Be Inc.开发的,接着Palm Inc.也跟着使用。现在OpenBinder的作者Dianne Hackborn就是在Google工作,负责Android平台的开发工作。

前面一再提到,Binder是一种进程间通信机制,它是一种类似于COM和CORBA分布式组件架构,通俗一点,其实是提供远程过程调用(RPC)功能。从英文字面上意思看,Binder具有粘结剂的意思,那么它把什么东西粘结在一起呢?在Android系统的Binder机制中,由一系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间,Binder驱动程序运行内核空间。Binder就是一种把这四个组件粘合在一起的粘结剂了,其中,核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,Client和Server正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。Service Manager和Binder驱动已经在Android平台中实现好,开发者只要按照规范实现自己的Client和Server组件就可以了。说起来简单,做起难,对初学者来说,Android系统的Binder机制是最难理解的了,而Binder机制无论从系统开发还是应用开发的角度来看,都是Android系统中最重要的组成,因此,很有必要深入了解Binder的工作方式。要深入了解Binder的工作方式,最好的方式莫过于是阅读Binder相关的源代码了,Linux的鼻祖Linus Torvalds曾经曰过一句名言RTFSC:Read The Fucking Source Code。

虽说阅读Binder的源代码是学习Binder机制的最好的方式,但是也绝不能打无准备之仗,因为Binder的相关源代码是比较枯燥无味而且比较难以理解的,如果能够辅予一些理论知识,那就更好了。闲话少说,网上关于Binder机制的资料还是不少的,这里就不想再详细写一遍了,强烈推荐下面两篇文章:

Android深入浅出之Binder机制

Android Binder设计与实现 – 设计篇

Android深入浅出之Binder机制一文从情景出发,深入地介绍了Binder在用户空间的三个组件Client、Server和Service Manager的相互关系,Android Binder设计与实现一文则是详细地介绍了内核空间的Binder驱动程序的数据结构和设计原理。非常感谢这两位作者给我们带来这么好的Binder学习资料。总结一下,Android系统Binder机制中的四个组件Client、Server、Service Manager和Binder驱动程序的关系如下图所示:

Android进程间通信IPC机制Binder_第1张图片

1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中

2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server

3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信

4. Client和Server之间的进程间通信通过Binder驱动程序间接实现

5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力

至此,对Binder机制总算是有了一个感性的认识,但仍然感到不能很好地从上到下贯穿整个IPC通信过程,于是,打算通过下面四个情景来分析Binder源代码,以进一步理解Binder机制:

1. Service Manager是如何成为一个守护进程的?即Service Manager是如何告知Binder驱动程序它是Binder机制的上下文管理者。

2. Server和Client是如何获得Service Manager接口的?即defaultServiceManager接口是如何实现的。

3. Server是如何把自己的服务启动起来的?Service Manager在Server启动的过程中是如何为Server提供服务的?即IServiceManager::addService接口是如何实现的。

4 Service Manager是如何为Client提供服务的?即IServiceManager::getService接口是如何实现的。

在接下来的四篇文章中,将按照这四个情景来分析Binder源代码,都将会涉及到用户空间到内核空间的Binder相关源代码。这里为什么没有Client和Server是如何进行进程间通信的情景呢? 这是因为Service Manager在作为守护进程的同时,它也充当Server角色。因此,只要我们能够理解第三和第四个情景,也就理解了Binder机制中Client和Server是如何通过Binder驱动程序进行进程间通信的了。

为了方便描述Android系统进程间通信Binder机制的原理和实现,在接下来的四篇文章中,我们都是基于C/C++语言来介绍Binder机制的实现的,但是,我们在Android系统开发应用程序时,都是基于Java语言的,因此,我们会在最后一篇文章中,详细介绍Android系统进程间通信Binder机制在应用程序框架层的Java接口实现:

5.Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析。

浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

分类: Android 18539人阅读 评论(45) 收藏 举报

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

既然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函数:

[cpp] view plain copy print ?
  1. intmain(intargc,char**argv)
  2. {
  3. structbinder_state*bs;
  4. void*svcmgr=BINDER_SERVICE_MANAGER;
  5. bs=binder_open(128*1024);
  6. if(binder_become_context_manager(bs)){
  7. LOGE("cannotbecomecontextmanager(%s)\n",strerror(errno));
  8. return-1;
  9. }
  10. svcmgr_handle=svcmgr;
  11. binder_loop(bs,svcmgr_handler);
  12. return0;
  13. }
main函数主要有三个功能:一是打开Binder设备文件;二是告诉Binder驱动程序自己是Binder上下文管理者,即我们前面所说的守护进程;三是进入一个无穷循环,充当Server的角色,等待Client的请求。进入这三个功能之间,先来看一下这里用到的结构体binder_state、宏BINDER_SERVICE_MANAGER的定义:

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

[cpp] view plain copy print ?
  1. structbinder_state
  2. {
  3. intfd;
  4. void*mapped;
  5. unsignedmapsize;
  6. };
fd是文件描述符,即表示打开的/dev/binder设备文件描述符;mapped是把设备文件/dev/binder映射到进程空间的起始地址;mapsize是上述内存映射空间的大小。

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

[cpp] view plain copy print ?
  1. /*theonemagicobject*/
  2. #defineBINDER_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文件中:

[cpp] view plain copy print ?
  1. structbinder_state*binder_open(unsignedmapsize)
  2. {
  3. structbinder_state*bs;
  4. bs=malloc(sizeof(*bs));
  5. if(!bs){
  6. errno=ENOMEM;
  7. return0;
  8. }
  9. bs->fd=open("/dev/binder",O_RDWR);
  10. if(bs->fd<0){
  11. fprintf(stderr,"binder:cannotopendevice(%s)\n",
  12. strerror(errno));
  13. gotofail_open;
  14. }
  15. bs->mapsize=mapsize;
  16. bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->fd,0);
  17. if(bs->mapped==MAP_FAILED){
  18. fprintf(stderr,"binder:cannotmapdevice(%s)\n",
  19. strerror(errno));
  20. gotofail_map;
  21. }
  22. /*TODO:checkversion*/
  23. returnbs;
  24. fail_map:
  25. close(bs->fd);
  26. fail_open:
  27. free(bs);
  28. return0;
  29. }
通过文件操作函数open来打开/dev/binder设备文件。设备文件/dev/binder是在Binder驱动程序模块初始化的时候创建的,我们先看一下这个设备文件的创建过程。进入到kernel/common/drivers/staging/android目录中,打开binder.c文件,可以看到模块初始化入口binder_init:

[cpp] view plain copy print ?
  1. staticstructfile_operationsbinder_fops={
  2. .owner=THIS_MODULE,
  3. .poll=binder_poll,
  4. .unlocked_ioctl=binder_ioctl,
  5. .mmap=binder_mmap,
  6. .open=binder_open,
  7. .flush=binder_flush,
  8. .release=binder_release,
  9. };
  10. staticstructmiscdevicebinder_miscdev={
  11. .minor=MISC_DYNAMIC_MINOR,
  12. .name="binder",
  13. .fops=&binder_fops
  14. };
  15. staticint__initbinder_init(void)
  16. {
  17. intret;
  18. binder_proc_dir_entry_root=proc_mkdir("binder",NULL);
  19. if(binder_proc_dir_entry_root)
  20. binder_proc_dir_entry_proc=proc_mkdir("proc",binder_proc_dir_entry_root);
  21. ret=misc_register(&binder_miscdev);
  22. if(binder_proc_dir_entry_root){
  23. create_proc_read_entry("state",S_IRUGO,binder_proc_dir_entry_root,binder_read_proc_state,NULL);
  24. create_proc_read_entry("stats",S_IRUGO,binder_proc_dir_entry_root,binder_read_proc_stats,NULL);
  25. create_proc_read_entry("transactions",S_IRUGO,binder_proc_dir_entry_root,binder_read_proc_transactions,NULL);
  26. create_proc_read_entry("transaction_log",S_IRUGO,binder_proc_dir_entry_root,binder_read_proc_transaction_log,&binder_transaction_log);
  27. create_proc_read_entry("failed_transaction_log",S_IRUGO,binder_proc_dir_entry_root,binder_read_proc_transaction_log,&binder_transaction_log_failed);
  28. }
  29. returnret;
  30. }
  31. device_initcall(binder_init);

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

[cpp] view plain copy print ?
  1. bs->fd=open("/dev/binder",O_RDWR);

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

[cpp] view plain copy print ?
  1. staticintbinder_open(structinode*nodp,structfile*filp)
  2. {
  3. structbinder_proc*proc;
  4. if(binder_debug_mask&BINDER_DEBUG_OPEN_CLOSE)
  5. printk(KERN_INFO"binder_open:%d:%d\n",current->group_leader->pid,current->pid);
  6. proc=kzalloc(sizeof(*proc),GFP_KERNEL);
  7. if(proc==NULL)
  8. return-ENOMEM;
  9. get_task_struct(current);
  10. proc->tsk=current;
  11. INIT_LIST_HEAD(&proc->todo);
  12. init_waitqueue_head(&proc->wait);
  13. proc->default_priority=task_nice(current);
  14. mutex_lock(&binder_lock);
  15. binder_stats.obj_created[BINDER_STAT_PROC]++;
  16. hlist_add_head(&proc->proc_node,&binder_procs);
  17. proc->pid=current->group_leader->pid;
  18. INIT_LIST_HEAD(&proc->delivered_death);
  19. filp->private_data=proc;
  20. mutex_unlock(&binder_lock);
  21. if(binder_proc_dir_entry_proc){
  22. charstrbuf[11];
  23. snprintf(strbuf,sizeof(strbuf),"%u",proc->pid);
  24. remove_proc_entry(strbuf,binder_proc_dir_entry_proc);
  25. create_proc_read_entry(strbuf,S_IRUGO,binder_proc_dir_entry_proc,binder_read_proc_proc,proc);
  26. }
  27. return0;
  28. }
这个函数的主要作用是创建一个struct binder_proc数据结构来保存打开设备文件/dev/binder的进程的上下文信息,并且将这个进程上下文信息保存在打开文件结构struct file的私有数据成员变量private_data中,这样,在执行其它文件操作时,就通过打开文件结构struct file来取回这个进程上下文信息了。这个进程上下文信息同时还会保存在一个全局哈希表binder_procs中,驱动程序内部使用。binder_procs定义在文件的开头:

[cpp] view plain copy print ?
  1. staticHLIST_HEAD(binder_procs);
结构体struct binder_proc也是定义在kernel/common/drivers/staging/android/binder.c文件中:

[cpp] view plain copy print ?
  1. structbinder_proc{
  2. structhlist_nodeproc_node;
  3. structrb_rootthreads;
  4. structrb_rootnodes;
  5. structrb_rootrefs_by_desc;
  6. structrb_rootrefs_by_node;
  7. intpid;
  8. structvm_area_struct*vma;
  9. structtask_struct*tsk;
  10. structfiles_struct*files;
  11. structhlist_nodedeferred_work_node;
  12. intdeferred_work;
  13. void*buffer;
  14. ptrdiff_tuser_buffer_offset;
  15. structlist_headbuffers;
  16. structrb_rootfree_buffers;
  17. structrb_rootallocated_buffers;
  18. size_tfree_async_space;
  19. structpage**pages;
  20. size_tbuffer_size;
  21. uint32_tbuffer_free;
  22. structlist_headtodo;
  23. wait_queue_head_twait;
  24. structbinder_statsstats;
  25. structlist_headdelivered_death;
  26. intmax_threads;
  27. intrequested_threads;
  28. intrequested_threads_started;
  29. intready_threads;
  30. longdefault_priority;
  31. };
这个结构体的成员比较多,这里就不一一说明了,简单解释一下四个成员变量threads、nodes、 refs_by_desc和refs_by_node,其它的我们在遇到的时候再详细解释。这四个成员变量都是表示红黑树的节点,也就是说,binder_proc分别挂会四个红黑树下。threads树用来保存binder_proc进程内用于处理用户请求的线程,它的最大数量由max_threads来决定;node树成用来保存binder_proc进程内的Binder实体;refs_by_desc树和refs_by_node树用来保存binder_proc进程内的Binder引用,即引用的其它进程的Binder实体,它分别用两种方式来组织红黑树,一种是以句柄作来key值来组织,一种是以引用的实体节点的地址值作来key值来组织,它们都是表示同一样东西,只不过是为了内部查找方便而用两个红黑树来表示。

这样,打开设备文件/dev/binder的操作就完成了,接着是对打开的设备文件进行内存映射操作mmap:

[cpp] view plain copy print ?
  1. bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->fd,0);

对应Binder驱动程序的binder_mmap函数:

[cpp] view plain copy print ?
  1. staticintbinder_mmap(structfile*filp,structvm_area_struct*vma)
  2. {
  3. intret;
  4. structvm_struct*area;
  5. structbinder_proc*proc=filp->private_data;
  6. constchar*failure_string;
  7. structbinder_buffer*buffer;
  8. if((vma->vm_end-vma->vm_start)>SZ_4M)
  9. vma->vm_end=vma->vm_start+SZ_4M;
  10. if(binder_debug_mask&BINDER_DEBUG_OPEN_CLOSE)
  11. printk(KERN_INFO
  12. "binder_mmap:%d%lx-%lx(%ldK)vma%lxpagep%lx\n",
  13. proc->pid,vma->vm_start,vma->vm_end,
  14. (vma->vm_end-vma->vm_start)/SZ_1K,vma->vm_flags,
  15. (unsignedlong)pgprot_val(vma->vm_page_prot));
  16. if(vma->vm_flags&FORBIDDEN_MMAP_FLAGS){
  17. ret=-EPERM;
  18. failure_string="badvm_flags";
  19. gotoerr_bad_arg;
  20. }
  21. vma->vm_flags=(vma->vm_flags|VM_DONTCOPY)&~VM_MAYWRITE;
  22. if(proc->buffer){
  23. ret=-EBUSY;
  24. failure_string="alreadymapped";
  25. gotoerr_already_mapped;
  26. }
  27. area=get_vm_area(vma->vm_end-vma->vm_start,VM_IOREMAP);
  28. if(area==NULL){
  29. ret=-ENOMEM;
  30. failure_string="get_vm_area";
  31. gotoerr_get_vm_area_failed;
  32. }
  33. proc->buffer=area->addr;
  34. proc->user_buffer_offset=vma->vm_start-(uintptr_t)proc->buffer;
  35. #ifdefCONFIG_CPU_CACHE_VIPT
  36. if(cache_is_vipt_aliasing()){
  37. while(CACHE_COLOUR((vma->vm_start^(uint32_t)proc->buffer))){
  38. printk(KERN_INFO"binder_mmap:%d%lx-%lxmaps%pbadalignment\n",proc->pid,vma->vm_start,vma->vm_end,proc->buffer);
  39. vma->vm_start+=PAGE_SIZE;
  40. }
  41. }
  42. #endif
  43. proc->pages=kzalloc(sizeof(proc->pages[0])*((vma->vm_end-vma->vm_start)/PAGE_SIZE),GFP_KERNEL);
  44. if(proc->pages==NULL){
  45. ret=-ENOMEM;
  46. failure_string="allocpagearray";
  47. gotoerr_alloc_pages_failed;
  48. }
  49. proc->buffer_size=vma->vm_end-vma->vm_start;
  50. vma->vm_ops=&binder_vm_ops;
  51. vma->vm_private_data=proc;
  52. if(binder_update_page_range(proc,1,proc->buffer,proc->buffer+PAGE_SIZE,vma)){
  53. ret=-ENOMEM;
  54. failure_string="allocsmallbuf";
  55. gotoerr_alloc_small_buf_failed;
  56. }
  57. buffer=proc->buffer;
  58. INIT_LIST_HEAD(&proc->buffers);
  59. list_add(&buffer->entry,&proc->buffers);
  60. buffer->free=1;
  61. binder_insert_free_buffer(proc,buffer);
  62. proc->free_async_space=proc->buffer_size/2;
  63. barrier();
  64. proc->files=get_files_struct(current);
  65. proc->vma=vma;
  66. /*printk(KERN_INFO"binder_mmap:%d%lx-%lxmaps%p\n",proc->pid,vma->vm_start,vma->vm_end,proc->buffer);*/
  67. return0;
  68. err_alloc_small_buf_failed:
  69. kfree(proc->pages);
  70. proc->pages=NULL;
  71. err_alloc_pages_failed:
  72. vfree(proc->buffer);
  73. proc->buffer=NULL;
  74. err_get_vm_area_failed:
  75. err_already_mapped:
  76. err_bad_arg:
  77. printk(KERN_ERR"binder_mmap:%d%lx-%lx%sfailed%d\n",proc->pid,vma->vm_start,vma->vm_end,failure_string,ret);
  78. returnret;
  79. }

函数首先通过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来描述:

[cpp] view plain copy print ?
  1. structbinder_buffer{
  2. structlist_headentry;/*freeandallocatedentriesbyaddesss*/
  3. structrb_noderb_node;/*freeentrybysizeorallocatedentry*/
  4. /*byaddress*/
  5. unsignedfree:1;
  6. unsignedallow_user_free:1;
  7. unsignedasync_transaction:1;
  8. unsigneddebug_id:29;
  9. structbinder_transaction*transaction;
  10. structbinder_node*target_node;
  11. size_tdata_size;
  12. size_toffsets_size;
  13. uint8_tdata[0];
  14. };
每一个binder_buffer通过其成员entry按从低址到高地址连入到struct binder_proc中的buffers表示的链表中去,同时,每一个binder_buffer又分为正在使用的和空闲的,通过free成员变量来区分,空闲的binder_buffer通过成员变量rb_node连入到struct binder_proc中的free_buffers表示的红黑树中去,正在使用的binder_buffer通过成员变量rb_node连入到struct binder_proc中的allocated_buffers表示的红黑树中去。这样做当然是为了方便查询和维护这块地址空间了,这一点我们可以从其它的代码中看到,等遇到的时候我们再分析。

终于可以回到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驱动程序是如何实现把一个物理页面同时映射到内核空间和进程空间去的:

[cpp] view plain copy print ?
  1. staticintbinder_update_page_range(structbinder_proc*proc,intallocate,
  2. void*start,void*end,structvm_area_struct*vma)
  3. {
  4. void*page_addr;
  5. unsignedlonguser_page_addr;
  6. structvm_structtmp_area;
  7. structpage**page;
  8. structmm_struct*mm;
  9. if(binder_debug_mask&BINDER_DEBUG_BUFFER_ALLOC)
  10. printk(KERN_INFO"binder:%d:%spages%p-%p\n",
  11. proc->pid,allocate?"allocate":"free",start,end);
  12. if(end<=start)
  13. return0;
  14. if(vma)
  15. mm=NULL;
  16. else
  17. mm=get_task_mm(proc->tsk);
  18. if(mm){
  19. down_write(&mm->mmap_sem);
  20. vma=proc->vma;
  21. }
  22. if(allocate==0)
  23. gotofree_range;
  24. if(vma==NULL){
  25. printk(KERN_ERR"binder:%d:binder_alloc_buffailedto"
  26. "mappagesinuserspace,novma\n",proc->pid);
  27. gotoerr_no_vma;
  28. }
  29. for(page_addr=start;page_addr<end;page_addr+=PAGE_SIZE){
  30. intret;
  31. structpage**page_array_ptr;
  32. page=&proc->pages[(page_addr-proc->buffer)/PAGE_SIZE];
  33. BUG_ON(*page);
  34. *page=alloc_page(GFP_KERNEL|__GFP_ZERO);
  35. if(*page==NULL){
  36. printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
  37. "forpageat%p\n",proc->pid,page_addr);
  38. gotoerr_alloc_page_failed;
  39. }
  40. tmp_area.addr=page_addr;
  41. tmp_area.size=PAGE_SIZE+PAGE_SIZE/*guardpage?*/;
  42. page_array_ptr=page;
  43. ret=map_vm_area(&tmp_area,PAGE_KERNEL,&page_array_ptr);
  44. if(ret){
  45. printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
  46. "tomappageat%pinkernel\n",
  47. proc->pid,page_addr);
  48. gotoerr_map_kernel_failed;
  49. }
  50. user_page_addr=
  51. (uintptr_t)page_addr+proc->user_buffer_offset;
  52. ret=vm_insert_page(vma,user_page_addr,page[0]);
  53. if(ret){
  54. printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
  55. "tomappageat%lxinuserspace\n",
  56. proc->pid,user_page_addr);
  57. gotoerr_vm_insert_page_failed;
  58. }
  59. /*vm_insert_pagedoesnotseemtoincrementtherefcount*/
  60. }
  61. if(mm){
  62. up_write(&mm->mmap_sem);
  63. mmput(mm);
  64. }
  65. return0;
  66. free_range:
  67. for(page_addr=end-PAGE_SIZE;page_addr>=start;
  68. page_addr-=PAGE_SIZE){
  69. page=&proc->pages[(page_addr-proc->buffer)/PAGE_SIZE];
  70. if(vma)
  71. zap_page_range(vma,(uintptr_t)page_addr+
  72. proc->user_buffer_offset,PAGE_SIZE,NULL);
  73. err_vm_insert_page_failed:
  74. unmap_kernel_range((unsignedlong)page_addr,PAGE_SIZE);
  75. err_map_kernel_failed:
  76. __free_page(*page);
  77. *page=NULL;
  78. err_alloc_page_failed:
  79. ;
  80. }
  81. err_no_vma:
  82. if(mm){
  83. up_write(&mm->mmap_sem);
  84. mmput(mm);
  85. }
  86. return-ENOMEM;
  87. }
这个函数既可以分配物理页面,也可以用来释放物理页面,通过allocate参数来区别,这里我们只关注分配物理页面的情况。要分配物理页面的虚拟地址空间范围为(start ~ end),函数前面的一些检查逻辑就不看了,直接看中间的for循环:

[cpp] view plain copy print ?
  1. for(page_addr=start;page_addr<end;page_addr+=PAGE_SIZE){
  2. intret;
  3. structpage**page_array_ptr;
  4. page=&proc->pages[(page_addr-proc->buffer)/PAGE_SIZE];
  5. BUG_ON(*page);
  6. *page=alloc_page(GFP_KERNEL|__GFP_ZERO);
  7. if(*page==NULL){
  8. printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
  9. "forpageat%p\n",proc->pid,page_addr);
  10. gotoerr_alloc_page_failed;
  11. }
  12. tmp_area.addr=page_addr;
  13. tmp_area.size=PAGE_SIZE+PAGE_SIZE/*guardpage?*/;
  14. page_array_ptr=page;
  15. ret=map_vm_area(&tmp_area,PAGE_KERNEL,&page_array_ptr);
  16. if(ret){
  17. printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
  18. "tomappageat%pinkernel\n",
  19. proc->pid,page_addr);
  20. gotoerr_map_kernel_failed;
  21. }
  22. user_page_addr=
  23. (uintptr_t)page_addr+proc->user_buffer_offset;
  24. ret=vm_insert_page(vma,user_page_addr,page[0]);
  25. if(ret){
  26. printk(KERN_ERR"binder:%d:binder_alloc_buffailed"
  27. "tomappageat%lxinuserspace\n",
  28. proc->pid,user_page_addr);
  29. gotoerr_vm_insert_page_failed;
  30. }
  31. /*vm_insert_pagedoesnotseemtoincrementtherefcount*/
  32. }
首先是调用alloc_page来分配一个物理页面,这个函数返回一个struct page物理页面描述符,根据这个描述的内容初始化好struct vm_struct tmp_area结构体,然后通过map_vm_area将这个物理页面插入到tmp_area描述的内核空间去,接着通过page_addr + proc->user_buffer_offset获得进程虚拟空间地址,并通过vm_insert_page函数将这个物理页面插入到进程地址空间去,参数vma代表了要插入的进程的地址空间。
这样,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文件中:

[cpp] view plain copy print ?
  1. intbinder_become_context_manager(structbinder_state*bs)
  2. {
  3. returnioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0);
  4. }
这里通过调用ioctl文件操作函数来通知Binder驱动程序自己是守护进程,命令号是BINDER_SET_CONTEXT_MGR,没有参数。BINDER_SET_CONTEXT_MGR定义为:

[cpp] view plain copy print ?
  1. #defineBINDER_SET_CONTEXT_MGR_IOW('b',7,int)
这样就进入到Binder驱动程序的binder_ioctl函数,我们只关注BINDER_SET_CONTEXT_MGR命令:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. ......
  20. caseBINDER_SET_CONTEXT_MGR:
  21. if(binder_context_mgr_node!=NULL){
  22. printk(KERN_ERR"binder:BINDER_SET_CONTEXT_MGRalreadyset\n");
  23. ret=-EBUSY;
  24. gotoerr;
  25. }
  26. if(binder_context_mgr_uid!=-1){
  27. if(binder_context_mgr_uid!=current->cred->euid){
  28. printk(KERN_ERR"binder:BINDER_SET_"
  29. "CONTEXT_MGRbaduid%d!=%d\n",
  30. current->cred->euid,
  31. binder_context_mgr_uid);
  32. ret=-EPERM;
  33. gotoerr;
  34. }
  35. }else
  36. binder_context_mgr_uid=current->cred->euid;
  37. binder_context_mgr_node=binder_new_node(proc,NULL,NULL);
  38. if(binder_context_mgr_node==NULL){
  39. ret=-ENOMEM;
  40. gotoerr;
  41. }
  42. binder_context_mgr_node->local_weak_refs++;
  43. binder_context_mgr_node->local_strong_refs++;
  44. binder_context_mgr_node->has_strong_ref=1;
  45. binder_context_mgr_node->has_weak_ref=1;
  46. break;
  47. ......
  48. default:
  49. ret=-EINVAL;
  50. gotoerr;
  51. }
  52. ret=0;
  53. err:
  54. if(thread)
  55. thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
  56. mutex_unlock(&binder_lock);
  57. wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  58. if(ret&&ret!=-ERESTARTSYS)
  59. printk(KERN_INFO"binder:%d:%dioctl%x%lxreturned%d\n",proc->pid,current->pid,cmd,arg,ret);
  60. returnret;
  61. }
继续分析这个函数之前,又要解释两个数据结构了,一个是struct binder_thread结构体,顾名思久,它表示一个线程,这里就是执行binder_become_context_manager函数的线程了。

[cpp] view plain copy print ?
  1. structbinder_thread{
  2. structbinder_proc*proc;
  3. structrb_noderb_node;
  4. intpid;
  5. intlooper;
  6. structbinder_transaction*transaction_stack;
  7. structlist_headtodo;
  8. uint32_treturn_error;/*Writefailed,returnerrorcodeinreadbuf*/
  9. uint32_treturn_error2;/*Writefailed,returnerrorcodeinread*/
  10. /*buffer.Usedwhensendingareplytoadeadprocessthat*/
  11. /*wearealsowaitingon*/
  12. wait_queue_head_twait;
  13. structbinder_statsstats;
  14. };
proc表示这个线程所属的进程。struct binder_proc有一个成员变量threads,它的类型是rb_root,它表示一查红黑树,把属于这个进程的所有线程都组织起来,struct binder_thread的成员变量rb_node就是用来链入这棵红黑树的节点了。looper成员变量表示线程的状态,它可以取下面这几个值:

[cpp] view plain copy print ?
  1. enum{
  2. BINDER_LOOPER_STATE_REGISTERED=0x01,
  3. BINDER_LOOPER_STATE_ENTERED=0x02,
  4. BINDER_LOOPER_STATE_EXITED=0x04,
  5. BINDER_LOOPER_STATE_INVALID=0x08,
  6. BINDER_LOOPER_STATE_WAITING=0x10,
  7. BINDER_LOOPER_STATE_NEED_RETURN=0x20
  8. };
其余的成员变量,transaction_stack表示线程正在处理的事务,todo表示发往该线程的数据列表,return_error和return_error2表示操作结果返回码,wait用来阻塞线程等待某个事件的发生,stats用来保存一些统计信息。这些成员变量遇到的时候再分析它们的作用。

另外一个数据结构是struct binder_node,它表示一个binder实体:

[cpp] view plain copy print ?
  1. structbinder_node{
  2. intdebug_id;
  3. structbinder_workwork;
  4. union{
  5. structrb_noderb_node;
  6. structhlist_nodedead_node;
  7. };
  8. structbinder_proc*proc;
  9. structhlist_headrefs;
  10. intinternal_strong_refs;
  11. intlocal_weak_refs;
  12. intlocal_strong_refs;
  13. void__user*ptr;
  14. void__user*cookie;
  15. unsignedhas_strong_ref:1;
  16. unsignedpending_strong_ref:1;
  17. unsignedhas_weak_ref:1;
  18. unsignedpending_weak_ref:1;
  19. unsignedhas_async_transaction:1;
  20. unsignedaccept_fds:1;
  21. intmin_priority:8;
  22. structlist_headasync_todo;
  23. };
rb_node和dead_node组成一个联合体。 如果这个Binder实体还在正常使用,则使用rb_node来连入proc->nodes所表示的红黑树的节点,这棵红黑树用来组织属于这个进程的所有Binder实体;如果这个Binder实体所属的进程已经销毁,而这个Binder实体又被其它进程所引用,则这个Binder实体通过dead_node进入到一个哈希表中去存放。proc成员变量就是表示这个Binder实例所属于进程了。refs成员变量把所有引用了该Binder实体的Binder引用连接起来构成一个链表。internal_strong_refs、local_weak_refs和local_strong_refs表示这个Binder实体的引用计数。ptr和cookie成员变量分别表示这个Binder实体在用户空间的地址以及附加数据。其余的成员变量就不描述了,遇到的时候再分析。

现在回到binder_ioctl函数中,首先是通过filp->private_data获得proc变量,这里binder_mmap函数是一样的。接着通过binder_get_thread函数获得线程信息,我们来看一下这个函数:

[cpp] view plain copy print ?
  1. staticstructbinder_thread*binder_get_thread(structbinder_proc*proc)
  2. {
  3. structbinder_thread*thread=NULL;
  4. structrb_node*parent=NULL;
  5. structrb_node**p=&proc->threads.rb_node;
  6. while(*p){
  7. parent=*p;
  8. thread=rb_entry(parent,structbinder_thread,rb_node);
  9. if(current->pid<thread->pid)
  10. p=&(*p)->rb_left;
  11. elseif(current->pid>thread->pid)
  12. p=&(*p)->rb_right;
  13. else
  14. break;
  15. }
  16. if(*p==NULL){
  17. thread=kzalloc(sizeof(*thread),GFP_KERNEL);
  18. if(thread==NULL)
  19. returnNULL;
  20. binder_stats.obj_created[BINDER_STAT_THREAD]++;
  21. thread->proc=proc;
  22. thread->pid=current->pid;
  23. init_waitqueue_head(&thread->wait);
  24. INIT_LIST_HEAD(&thread->todo);
  25. rb_link_node(&thread->rb_node,parent,p);
  26. rb_insert_color(&thread->rb_node,&proc->threads);
  27. thread->looper|=BINDER_LOOPER_STATE_NEED_RETURN;
  28. thread->return_error=BR_OK;
  29. thread->return_error2=BR_OK;
  30. }
  31. returnthread;
  32. }
这里把当前线程current的pid作为键值,在进程proc->threads表示的红黑树中进行查找,看是否已经为当前线程创建过了binder_thread信息。在这个场景下,由于当前线程是第一次进到这里,所以肯定找不到,即*p == NULL成立,于是,就为当前线程创建一个线程上下文信息结构体binder_thread,并初始化相应成员变量,并插入到proc->threads所表示的红黑树中去,下次要使用时就可以从proc中找到了。注意,这里的thread->looper =BINDER_LOOPER_STATE_NEED_RETURN。

回到binder_ioctl函数,继续往下面,有两个全局变量binder_context_mgr_node和binder_context_mgr_uid,它定义如下:

[cpp] view plain copy print ?
  1. staticstructbinder_node*binder_context_mgr_node;
  2. staticuid_tbinder_context_mgr_uid=-1;
binder_context_mgr_node用来表示Service Manager实体,binder_context_mgr_uid表示Service Manager守护进程的uid。在这个场景下,由于当前线程是第一次进到这里,所以binder_context_mgr_node为NULL,binder_context_mgr_uid为-1,于是初始化binder_context_mgr_uid为current->cred->euid,这样,当前线程就成为Binder机制的守护进程了,并且通过binder_new_node为Service Manager创建Binder实体:

[cpp] view plain copy print ?
  1. staticstructbinder_node*
  2. binder_new_node(structbinder_proc*proc,void__user*ptr,void__user*cookie)
  3. {
  4. structrb_node**p=&proc->nodes.rb_node;
  5. structrb_node*parent=NULL;
  6. structbinder_node*node;
  7. while(*p){
  8. parent=*p;
  9. node=rb_entry(parent,structbinder_node,rb_node);
  10. if(ptr<node->ptr)
  11. p=&(*p)->rb_left;
  12. elseif(ptr>node->ptr)
  13. p=&(*p)->rb_right;
  14. else
  15. returnNULL;
  16. }
  17. node=kzalloc(sizeof(*node),GFP_KERNEL);
  18. if(node==NULL)
  19. returnNULL;
  20. binder_stats.obj_created[BINDER_STAT_NODE]++;
  21. rb_link_node(&node->rb_node,parent,p);
  22. rb_insert_color(&node->rb_node,&proc->nodes);
  23. node->debug_id=++binder_last_id;
  24. node->proc=proc;
  25. node->ptr=ptr;
  26. node->cookie=cookie;
  27. node->work.type=BINDER_WORK_NODE;
  28. INIT_LIST_HEAD(&node->work.entry);
  29. INIT_LIST_HEAD(&node->async_todo);
  30. if(binder_debug_mask&BINDER_DEBUG_INTERNAL_REFS)
  31. printk(KERN_INFO"binder:%d:%dnode%du%pc%pcreated\n",
  32. proc->pid,current->pid,node->debug_id,
  33. node->ptr,node->cookie);
  34. returnnode;
  35. }
注意,这里传进来的ptr和cookie均为NULL。函数首先检查proc->nodes红黑树中是否已经存在以ptr为键值的node,如果已经存在,就返回NULL。在这个场景下,由于当前线程是第一次进入到这里,所以肯定不存在,于是就新建了一个ptr为NULL的binder_node,并且初始化其它成员变量,并插入到proc->nodes红黑树中去。

binder_new_node返回到binder_ioctl函数后,就把新建的binder_node指针保存在binder_context_mgr_node中了,紧接着,又初始化了binder_context_mgr_node的引用计数值。

这样,BINDER_SET_CONTEXT_MGR命令就执行完毕了,binder_ioctl函数返回之前,执行了下面语句:

[cpp] view plain copy print ?
  1. if(thread)
  2. 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文件中:

[cpp] view plain copy print ?
  1. voidbinder_loop(structbinder_state*bs,binder_handlerfunc)
  2. {
  3. intres;
  4. structbinder_write_readbwr;
  5. unsignedreadbuf[32];
  6. bwr.write_size=0;
  7. bwr.write_consumed=0;
  8. bwr.write_buffer=0;
  9. readbuf[0]=BC_ENTER_LOOPER;
  10. binder_write(bs,readbuf,sizeof(unsigned));
  11. for(;;){
  12. bwr.read_size=sizeof(readbuf);
  13. bwr.read_consumed=0;
  14. bwr.read_buffer=(unsigned)readbuf;
  15. res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr);
  16. if(res<0){
  17. LOGE("binder_loop:ioctlfailed(%s)\n",strerror(errno));
  18. break;
  19. }
  20. res=binder_parse(bs,0,readbuf,bwr.read_consumed,func);
  21. if(res==0){
  22. LOGE("binder_loop:unexpectedreply?!\n");
  23. break;
  24. }
  25. if(res<0){
  26. LOGE("binder_loop:ioerror%d%s\n",res,strerror(errno));
  27. break;
  28. }
  29. }
  30. }
首先是通过binder_write函数执行BC_ENTER_LOOPER命令告诉Binder驱动程序, Service Manager要进入循环了。

这里又要介绍一下设备文件/dev/binder文件操作函数ioctl的操作码BINDER_WRITE_READ了,首先看定义:

[cpp] view plain copy print ?
  1. #defineBINDER_WRITE_READ_IOWR('b',1,structbinder_write_read)
这个io操作码有一个参数,形式为struct binder_write_read:

[cpp] view plain copy print ?
  1. structbinder_write_read{
  2. signedlongwrite_size;/*bytestowrite*/
  3. signedlongwrite_consumed;/*bytesconsumedbydriver*/
  4. unsignedlongwrite_buffer;
  5. signedlongread_size;/*bytestoread*/
  6. signedlongread_consumed;/*bytesconsumedbydriver*/
  7. unsignedlongread_buffer;
  8. };
这里顺便说一下,用户空间程序和Binder驱动程序交互大多数都是通过BINDER_WRITE_READ命令的,write_bufffer和read_buffer所指向的数据结构还指定了具体要执行的操作,write_bufffer和read_buffer所指向的结构体是structbinder_transaction_data:

[cpp] view plain copy print ?
  1. structbinder_transaction_data{
  2. /*ThefirsttwoareonlyusedforbcTRANSACTIONandbrTRANSACTION,
  3. *identifyingthetargetandcontentsofthetransaction.
  4. */
  5. union{
  6. size_thandle;/*targetdescriptorofcommandtransaction*/
  7. void*ptr;/*targetdescriptorofreturntransaction*/
  8. }target;
  9. void*cookie;/*targetobjectcookie*/
  10. unsignedintcode;/*transactioncommand*/
  11. /*Generalinformationaboutthetransaction.*/
  12. unsignedintflags;
  13. pid_tsender_pid;
  14. uid_tsender_euid;
  15. size_tdata_size;/*numberofbytesofdata*/
  16. size_toffsets_size;/*numberofbytesofoffsets*/
  17. /*Ifthistransactionisinline,thedataimmediately
  18. *followshere;otherwise,itendswithapointerto
  19. *thedatabuffer.
  20. */
  21. union{
  22. struct{
  23. /*transactiondata*/
  24. constvoid*buffer;
  25. /*offsetsfrombuffertoflat_binder_objectstructs*/
  26. constvoid*offsets;
  27. }ptr;
  28. uint8_tbuf[8];
  29. }data;
  30. };
有一个联合体target,当这个BINDER_WRITE_READ命令的目标对象是本地Binder实体时,就使用ptr来表示这个对象在本进程中的地址,否则就使用handle来表示这个Binder实体的引用。只有目标对象是Binder实体时,cookie成员变量才有意义,表示一些附加数据,由Binder实体来解释这个个附加数据。code表示要对目标对象请求的命令代码,有很多请求代码,这里就不列举了,在这个场景中,就是BC_ENTER_LOOPER了,用来告诉Binder驱动程序, Service Manager要进入循环了。其余的请求命令代码可以参考kernel/common/drivers/staging/android/binder.h文件中定义的两个枚举类型BinderDriverReturnProtocol和BinderDriverCommandProtocol。

flags成员变量表示事务标志:

[cpp] view plain copy print ?
  1. enumtransaction_flags{
  2. TF_ONE_WAY=0x01,/*thisisaone-waycall:async,noreturn*/
  3. TF_ROOT_OBJECT=0x04,/*contentsarethecomponent'srootobject*/
  4. TF_STATUS_CODE=0x08,/*contentsarea32-bitstatuscode*/
  5. TF_ACCEPT_FDS=0x10,/*allowreplieswithfiledescriptors*/
  6. };
每一个标志位所表示的意义看注释就行了,遇到时再具体分析。

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 来表示:

[cpp] view plain copy print ?
  1. /*
  2. *ThisistheflattenedrepresentationofaBinderobjectfortransfer
  3. *betweenprocesses.The'offsets'suppliedaspartofabindertransaction
  4. *containsoffsetsintothedatawherethesestructuresoccur.TheBinder
  5. *drivertakescareofre-writingthestructuretypeanddataasitmoves
  6. *betweenprocesses.
  7. */
  8. structflat_binder_object{
  9. /*8bytesforlarge_flat_header.*/
  10. unsignedlongtype;
  11. unsignedlongflags;
  12. /*8bytesofdata.*/
  13. union{
  14. void*binder;/*localobject*/
  15. signedlonghandle;/*remoteobject*/
  16. };
  17. /*extradataassociatedwithlocalobject*/
  18. void*cookie;
  19. };
type表示Binder对象的类型,它取值如下所示:

[cpp] view plain copy print ?
  1. enum{
  2. BINDER_TYPE_BINDER=B_PACK_CHARS('s','b','*',B_TYPE_LARGE),
  3. BINDER_TYPE_WEAK_BINDER=B_PACK_CHARS('w','b','*',B_TYPE_LARGE),
  4. BINDER_TYPE_HANDLE=B_PACK_CHARS('s','h','*',B_TYPE_LARGE),
  5. BINDER_TYPE_WEAK_HANDLE=B_PACK_CHARS('w','h','*',B_TYPE_LARGE),
  6. BINDER_TYPE_FD=B_PACK_CHARS('f','d','*',B_TYPE_LARGE),
  7. };
flags表示Binder对象的标志,该域只对第一次传递Binder实体时有效,因为此刻驱动需要在内核中创建相应的实体节点,有些参数需要从该域取出。

type和flags的具体意义可以参考Android Binder设计与实现一文。

最后,binder表示这是一个Binder实体,handle表示这是一个Binder引用,当这是一个Binder实体时,cookie才有意义,表示附加数据,由进程自己解释。

数据结构分析完了,回到binder_loop函数中,首先是执行BC_ENTER_LOOPER命令:

[cpp] view plain copy print ?
  1. readbuf[0]=BC_ENTER_LOOPER;
  2. binder_write(bs,readbuf,sizeof(unsigned));
进入到binder_write函数中:

[cpp] view plain copy print ?
  1. intbinder_write(structbinder_state*bs,void*data,unsignedlen)
  2. {
  3. structbinder_write_readbwr;
  4. intres;
  5. bwr.write_size=len;
  6. bwr.write_consumed=0;
  7. bwr.write_buffer=(unsigned)data;
  8. bwr.read_size=0;
  9. bwr.read_consumed=0;
  10. bwr.read_buffer=0;
  11. res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr);
  12. if(res<0){
  13. fprintf(stderr,"binder_write:ioctlfailed(%s)\n",
  14. strerror(errno));
  15. }
  16. returnres;
  17. }
注意这里的binder_write_read变量bwr,write_size大小为4,表示write_buffer缓冲区大小为4,它的内容是一个BC_ENTER_LOOPER命令协议号,read_buffer为空。接着又是调用ioctl函数进入到Binder驱动程序的binder_ioctl函数,这里我们也只是关注BC_ENTER_LOOPER相关的逻辑:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. caseBINDER_WRITE_READ:{
  20. structbinder_write_readbwr;
  21. if(size!=sizeof(structbinder_write_read)){
  22. ret=-EINVAL;
  23. gotoerr;
  24. }
  25. if(copy_from_user(&bwr,ubuf,sizeof(bwr))){
  26. ret=-EFAULT;
  27. gotoerr;
  28. }
  29. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  30. printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",
  31. proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);
  32. if(bwr.write_size>0){
  33. ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
  34. if(ret<0){
  35. bwr.read_consumed=0;
  36. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  37. ret=-EFAULT;
  38. gotoerr;
  39. }
  40. }
  41. if(bwr.read_size>0){
  42. ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);
  43. if(!list_empty(&proc->todo))
  44. wake_up_interruptible(&proc->wait);
  45. if(ret<0){
  46. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  47. ret=-EFAULT;
  48. gotoerr;
  49. }
  50. }
  51. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  52. printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",
  53. proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);
  54. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  55. ret=-EFAULT;
  56. gotoerr;
  57. }
  58. break;
  59. }
  60. ......
  61. default:
  62. ret=-EINVAL;
  63. gotoerr;
  64. }
  65. ret=0;
  66. err:
  67. if(thread)
  68. thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
  69. mutex_unlock(&binder_lock);
  70. wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  71. if(ret&&ret!=-ERESTARTSYS)
  72. printk(KERN_INFO"binder:%d:%dioctl%x%lxreturned%d\n",proc->pid,current->pid,cmd,arg,ret);
  73. returnret;
  74. }
函数前面的代码就不解释了,同前面调用binder_become_context_manager是一样的,只不过这里调用binder_get_thread函数获取binder_thread,就能从proc中直接找到了,不需要创建一个新的。

首先是通过copy_from_user(&bwr, ubuf, sizeof(bwr))语句把用户传递进来的参数转换成struct binder_write_read结构体,并保存在本地变量bwr中,这里可以看出bwr.write_size等于4,于是进入binder_thread_write函数,这里我们只关注BC_ENTER_LOOPER相关的代码:

[cpp] view plain copy print ?
  1. int
  2. binder_thread_write(structbinder_proc*proc,structbinder_thread*thread,
  3. void__user*buffer,intsize,signedlong*consumed)
  4. {
  5. uint32_tcmd;
  6. void__user*ptr=buffer+*consumed;
  7. void__user*end=buffer+size;
  8. while(ptr<end&&thread->return_error==BR_OK){
  9. if(get_user(cmd,(uint32_t__user*)ptr))
  10. return-EFAULT;
  11. ptr+=sizeof(uint32_t);
  12. if(_IOC_NR(cmd)<ARRAY_SIZE(binder_stats.bc)){
  13. binder_stats.bc[_IOC_NR(cmd)]++;
  14. proc->stats.bc[_IOC_NR(cmd)]++;
  15. thread->stats.bc[_IOC_NR(cmd)]++;
  16. }
  17. switch(cmd){
  18. ......
  19. caseBC_ENTER_LOOPER:
  20. if(binder_debug_mask&BINDER_DEBUG_THREADS)
  21. printk(KERN_INFO"binder:%d:%dBC_ENTER_LOOPER\n",
  22. proc->pid,thread->pid);
  23. if(thread->looper&BINDER_LOOPER_STATE_REGISTERED){
  24. thread->looper|=BINDER_LOOPER_STATE_INVALID;
  25. binder_user_error("binder:%d:%dERROR:"
  26. "BC_ENTER_LOOPERcalledafter"
  27. "BC_REGISTER_LOOPER\n",
  28. proc->pid,thread->pid);
  29. }
  30. thread->looper|=BINDER_LOOPER_STATE_ENTERED;
  31. break;
  32. ......
  33. default:
  34. printk(KERN_ERR"binder:%d:%dunknowncommand%d\n",proc->pid,thread->pid,cmd);
  35. return-EINVAL;
  36. }
  37. *consumed=ptr-buffer;
  38. }
  39. return0;
  40. }
回忆前面执行binder_become_context_manager到binder_ioctl时,调用binder_get_thread函数创建的thread->looper值为0,所以这里执行完BC_ENTER_LOOPER时,thread->looper值就变为BINDER_LOOPER_STATE_ENTERED了,表明当前线程进入循环状态了。

回到binder_ioctl函数,由于bwr.read_size == 0,binder_thread_read函数就不会被执行了,这样,binder_ioctl的任务就完成了。

回到binder_loop函数,进入for循环:

[cpp] view plain copy print ?
  1. for(;;){
  2. bwr.read_size=sizeof(readbuf);
  3. bwr.read_consumed=0;
  4. bwr.read_buffer=(unsigned)readbuf;
  5. res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr);
  6. if(res<0){
  7. LOGE("binder_loop:ioctlfailed(%s)\n",strerror(errno));
  8. break;
  9. }
  10. res=binder_parse(bs,0,readbuf,bwr.read_consumed,func);
  11. if(res==0){
  12. LOGE("binder_loop:unexpectedreply?!\n");
  13. break;
  14. }
  15. if(res<0){
  16. LOGE("binder_loop:ioerror%d%s\n",res,strerror(errno));
  17. break;
  18. }
  19. }
又是执行一个ioctl命令,注意,这里的bwr参数各个成员的值:

[cpp] view plain copy print ?
  1. bwr.write_size=0;
  2. bwr.write_consumed=0;
  3. bwr.write_buffer=0;
  4. readbuf[0]=BC_ENTER_LOOPER;
  5. bwr.read_size=sizeof(readbuf);
  6. bwr.read_consumed=0;
  7. bwr.read_buffer=(unsigned)readbuf;
再次进入到binder_ioctl函数:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. caseBINDER_WRITE_READ:{
  20. structbinder_write_readbwr;
  21. if(size!=sizeof(structbinder_write_read)){
  22. ret=-EINVAL;
  23. gotoerr;
  24. }
  25. if(copy_from_user(&bwr,ubuf,sizeof(bwr))){
  26. ret=-EFAULT;
  27. gotoerr;
  28. }
  29. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  30. printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",
  31. proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);
  32. if(bwr.write_size>0){
  33. ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
  34. if(ret<0){
  35. bwr.read_consumed=0;
  36. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  37. ret=-EFAULT;
  38. gotoerr;
  39. }
  40. }
  41. if(bwr.read_size>0){
  42. ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);
  43. if(!list_empty(&proc->todo))
  44. wake_up_interruptible(&proc->wait);
  45. if(ret<0){
  46. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  47. ret=-EFAULT;
  48. gotoerr;
  49. }
  50. }
  51. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  52. printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",
  53. proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);
  54. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  55. ret=-EFAULT;
  56. gotoerr;
  57. }
  58. break;
  59. }
  60. ......
  61. default:
  62. ret=-EINVAL;
  63. gotoerr;
  64. }
  65. ret=0;
  66. err:
  67. if(thread)
  68. thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
  69. mutex_unlock(&binder_lock);
  70. wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  71. if(ret&&ret!=-ERESTARTSYS)
  72. printk(KERN_INFO"binder:%d:%dioctl%x%lxreturned%d\n",proc->pid,current->pid,cmd,arg,ret);
  73. returnret;
  74. }
这次,bwr.write_size等于0,于是不会执行binder_thread_write函数,bwr.read_size等于32,于是进入到binder_thread_read函数:

[cpp] view plain copy print ?
  1. staticint
  2. binder_thread_read(structbinder_proc*proc,structbinder_thread*thread,
  3. void__user*buffer,intsize,signedlong*consumed,intnon_block)
  4. {
  5. void__user*ptr=buffer+*consumed;
  6. void__user*end=buffer+size;
  7. intret=0;
  8. intwait_for_proc_work;
  9. if(*consumed==0){
  10. if(put_user(BR_NOOP,(uint32_t__user*)ptr))
  11. return-EFAULT;
  12. ptr+=sizeof(uint32_t);
  13. }
  14. retry:
  15. wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);
  16. if(thread->return_error!=BR_OK&&ptr<end){
  17. if(thread->return_error2!=BR_OK){
  18. if(put_user(thread->return_error2,(uint32_t__user*)ptr))
  19. return-EFAULT;
  20. ptr+=sizeof(uint32_t);
  21. if(ptr==end)
  22. gotodone;
  23. thread->return_error2=BR_OK;
  24. }
  25. if(put_user(thread->return_error,(uint32_t__user*)ptr))
  26. return-EFAULT;
  27. ptr+=sizeof(uint32_t);
  28. thread->return_error=BR_OK;
  29. gotodone;
  30. }
  31. thread->looper|=BINDER_LOOPER_STATE_WAITING;
  32. if(wait_for_proc_work)
  33. proc->ready_threads++;
  34. mutex_unlock(&binder_lock);
  35. if(wait_for_proc_work){
  36. if(!(thread->looper&(BINDER_LOOPER_STATE_REGISTERED|
  37. BINDER_LOOPER_STATE_ENTERED))){
  38. binder_user_error("binder:%d:%dERROR:Threadwaiting"
  39. "forprocessworkbeforecallingBC_REGISTER_"
  40. "LOOPERorBC_ENTER_LOOPER(state%x)\n",
  41. proc->pid,thread->pid,thread->looper);
  42. wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  43. }
  44. binder_set_nice(proc->default_priority);
  45. if(non_block){
  46. if(!binder_has_proc_work(proc,thread))
  47. ret=-EAGAIN;
  48. }else
  49. ret=wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc,thread));
  50. }else{
  51. if(non_block){
  52. if(!binder_has_thread_work(thread))
  53. ret=-EAGAIN;
  54. }else
  55. ret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));
  56. }
  57. .......
  58. }
传入的参数*consumed == 0,于是写入一个值BR_NOOP到参数ptr指向的缓冲区中去,即用户传进来的bwr.read_buffer缓冲区。这时候,thread->transaction_stack == NULL,并且thread->todo列表也是空的,这表示当前线程没有事务需要处理,于是wait_for_proc_work为true,表示要去查看proc是否有未处理的事务。当前thread->return_error == BR_OK,这是前面创建binder_thread时初始化设置的。于是继续往下执行,设置thread的状态为BINDER_LOOPER_STATE_WAITING,表示线程处于等待状态。调用binder_set_nice函数设置当前线程的优先级别为proc->default_priority,这是因为thread要去处理属于proc的事务,因此要将此thread的优先级别设置和proc一样。在这个场景中,proc也没有事务处理,即binder_has_proc_work(proc, thread)为false。如果文件打开模式为非阻塞模式,即non_block为true,那么函数就直接返回-EAGAIN,要求用户重新执行ioctl;否则的话,就通过当前线程就通过wait_event_interruptible_exclusive函数进入休眠状态,等待请求到来再唤醒了。

至此,我们就从源代码一步一步地分析完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担负起守护进程的职责了

浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路

分类: Android 11467人阅读 评论(15) 收藏 举报 在前面一篇文章 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路中,介绍了Service Manager是如何成为Binder机制的守护进程的。既然作为守护进程,Service Manager的职责当然就是为Server和Client服务了。那么,Server和Client如何获得Service Manager接口,进而享受它提供的服务呢?本文将简要分析Server和Client获得Service Manager的过程。

在阅读本文之前,希望读者先阅读Android进程间通信(IPC)机制Binder简要介绍和学习计划一文提到的参考资料Android深入浅出之Binder机制,这样可以加深对本文的理解。

我们知道,Service Manager在Binder机制中既充当守护进程的角色,同时它也充当着Server角色,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过Service Manager远程接口提供的getService接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于Service Manager这个Server来说,Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。

获取Service Manager远程接口的函数是defaultServiceManager,这个函数声明在frameworks/base/include/binder/IServiceManager.h文件中:

[cpp] view plain copy print ?
  1. sp<IServiceManager>defaultServiceManager();

实现在frameworks/base/libs/binder/IServiceManager.cpp文件中:

[cpp] view plain copy print ?
  1. sp<IServiceManager>defaultServiceManager()
  2. {
  3. if(gDefaultServiceManager!=NULL)returngDefaultServiceManager;
  4. {
  5. AutoMutex_l(gDefaultServiceManagerLock);
  6. if(gDefaultServiceManager==NULL){
  7. gDefaultServiceManager=interface_cast<IServiceManager>(
  8. ProcessState::self()->getContextObject(NULL));
  9. }
  10. }
  11. returngDefaultServiceManager;
  12. }
gDefaultServiceManagerLock和gDefaultServiceManager是全局变量,定义在frameworks/base/libs/binder/Static.cpp文件中:

[cpp] view plain copy print ?
  1. MutexgDefaultServiceManagerLock;
  2. sp<IServiceManager>gDefaultServiceManager;
从这个函数可以看出,gDefaultServiceManager是单例模式,调用defaultServiceManager函数时,如果gDefaultServiceManager已经创建,则直接返回,否则通过interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))来创建一个,并保存在gDefaultServiceManager全局变量中。

在继续介绍interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))的实现之前,先来看一个类图,这能够帮助我们了解Service Manager远程接口的创建过程。

Android进程间通信IPC机制Binder_第2张图片
参考资料Android深入浅出之Binder机制一文的读者,应该会比较容易理解这个图。这个图表明了,BpServiceManager类继承了BpInterface<IServiceManager>类,BpInterface是一个模板类,它定义在frameworks/base/include/binder/IInterface.h文件中:

[cpp] view plain copy print ?
  1. template<typenameINTERFACE>
  2. classBpInterface:publicINTERFACE,publicBpRefBase
  3. {
  4. public:
  5. BpInterface(constsp<IBinder>&remote);
  6. protected:
  7. virtualIBinder*onAsBinder();
  8. };
IServiceManager类继承了IInterface类,而IInterface类和BpRefBase类又分别继承了RefBase类。在BpRefBase类中,有一个成员变量mRemote,它的类型是IBinder*,实现类为BpBinder,它表示一个Binder引用,引用句柄值保存在BpBinder类的mHandle成员变量中。BpBinder类通过IPCThreadState类来和Binder驱动程序并互,而IPCThreadState又通过它的成员变量mProcess来打开/dev/binder设备文件,mProcess成员变量的类型为ProcessState。ProcessState类打开设备/dev/binder之后,将打开文件描述符保存在mDriverFD成员变量中,以供后续使用。

理解了这些概念之后,就可以继续分析创建Service Manager远程接口的过程了,最终目的是要创建一个BpServiceManager实例,并且返回它的IServiceManager接口。创建Service Manager远程接口主要是下面语句:

[cpp] view plain copy print ?
  1. gDefaultServiceManager=interface_cast<IServiceManager>(
  2. ProcessState::self()->getContextObject(NULL));
看起来简短,却暗藏玄机,具体可阅读 Android深入浅出之Binder机制这篇参考资料,这里作简要描述。

首先是调用ProcessState::self函数,self函数是ProcessState的静态成员函数,它的作用是返回一个全局唯一的ProcessState实例变量,就是单例模式了,这个变量名为gProcess。如果gProcess尚未创建,就会执行创建操作,在ProcessState的构造函数中,会通过open文件操作函数打开设备文件/dev/binder,并且返回来的设备文件描述符保存在成员变量mDriverFD中。

接着调用gProcess->getContextObject函数来获得一个句柄值为0的Binder引用,即BpBinder了,于是创建Service Manager远程接口的语句可以简化为:

[cpp] view plain copy print ?
  1. gDefaultServiceManager=interface_cast<IServiceManager>(newBpBinder(0));
再来看函数interface_cast<IServiceManager>的实现,它是一个模板函数,定义在framework/base/include/binder/IInterface.h文件中:

[cpp] view plain copy print ?
  1. template<typenameINTERFACE>
  2. inlinesp<INTERFACE>interface_cast(constsp<IBinder>&obj)
  3. {
  4. returnINTERFACE::asInterface(obj);
  5. }
这里的INTERFACE是IServiceManager,于是调用了IServiceManager::asInterface函数。IServiceManager::asInterface是通过DECLARE_META_INTERFACE(ServiceManager)宏在IServiceManager类中声明的,它位于framework/base/include/binder/IServiceManager.h文件中:

[cpp] view plain copy print ?
  1. DECLARE_META_INTERFACE(ServiceManager);

展开即为:

[cpp] view plain copy print ?
  1. #defineDECLARE_META_INTERFACE(ServiceManager)\
  2. staticconstandroid::String16descriptor;\
  3. staticandroid::sp<IServiceManager>asInterface(\
  4. constandroid::sp<android::IBinder>&obj);\
  5. virtualconstandroid::String16&getInterfaceDescriptor()const;\
  6. IServiceManager();\
  7. virtual~IServiceManager();

IServiceManager::asInterface的实现是通过IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")宏定义的,它位于framework/base/libs/binder/IServiceManager.cpp文件中:

[cpp] view plain copy print ?
  1. IMPLEMENT_META_INTERFACE(ServiceManager,"android.os.IServiceManager");
展开即为:

[cpp] view plain copy print ?
  1. #defineIMPLEMENT_META_INTERFACE(ServiceManager,"android.os.IServiceManager")\
  2. constandroid::String16IServiceManager::descriptor("android.os.IServiceManager");\
  3. constandroid::String16&\
  4. IServiceManager::getInterfaceDescriptor()const{\
  5. returnIServiceManager::descriptor;\
  6. }\
  7. android::sp<IServiceManager>IServiceManager::asInterface(\
  8. constandroid::sp<android::IBinder>&obj)\
  9. {\
  10. android::sp<IServiceManager>intr;\
  11. if(obj!=NULL){\
  12. intr=static_cast<IServiceManager*>(\
  13. obj->queryLocalInterface(\
  14. IServiceManager::descriptor).get());\
  15. if(intr==NULL){\
  16. intr=newBpServiceManager(obj);\
  17. }\
  18. }\
  19. returnintr;\
  20. }\
  21. IServiceManager::IServiceManager(){}\
  22. IServiceManager::~IServiceManager(){}
估计写这段代码的员工是从Microsoft跳槽到Google的。这里我们关注IServiceManager::asInterface的实现:

[cpp] view plain copy print ?
  1. android::sp<IServiceManager>IServiceManager::asInterface(constandroid::sp<android::IBinder>&obj)
  2. {
  3. android::sp<IServiceManager>intr;
  4. if(obj!=NULL){
  5. intr=static_cast<IServiceManager*>(
  6. obj->queryLocalInterface(IServiceManager::descriptor).get());
  7. if(intr==NULL){
  8. intr=newBpServiceManager(obj);
  9. }
  10. returnintr;
  11. }
这里传进来的参数obj就则刚才创建的new BpBinder(0)了,BpBinder类中的成员函数queryLocalInterface继承自基类IBinder,IBinder::queryLocalInterface函数位于framework/base/libs/binder/Binder.cpp文件中:

[cpp] view plain copy print ?
  1. sp<IInterface>IBinder::queryLocalInterface(constString16&descriptor)
  2. {
  3. returnNULL;
  4. }
由此可见,在IServiceManager::asInterface函数中,最终会调用下面语句:

[cpp] view plain copy print ?
  1. intr=newBpServiceManager(obj);
即为:

[cpp] view plain copy print ?
  1. intr=newBpServiceManager(newBpBinder(0));
回到defaultServiceManager函数中,最终结果为:

[cpp] view plain copy print ?
  1. gDefaultServiceManager=newBpServiceManager(newBpBinder(0));
这样,Service Manager远程接口就创建完成了,它本质上是一个BpServiceManager,包含了一个句柄值为0的Binder引用。

在Android系统的Binder机制中,Server和Client拿到这个Service Manager远程接口之后怎么用呢?

对Server来说,就是调用IServiceManager::addService这个接口来和Binder驱动程序交互了,即调用BpServiceManager::addService 。而BpServiceManager::addService又会调用通过其基类BpRefBase的成员函数remote获得原先创建的BpBinder实例,接着调用BpBinder::transact成员函数。在BpBinder::transact函数中,又会调用IPCThreadState::transact成员函数,这里就是最终与Binder驱动程序交互的地方了。回忆一下前面的类图,IPCThreadState有一个PorcessState类型的成中变量mProcess,而mProcess有一个成员变量mDriverFD,它是设备文件/dev/binder的打开文件描述符,因此,IPCThreadState就相当于间接在拥有了设备文件/dev/binder的打开文件描述符,于是,便可以与Binder驱动程序交互了。

对Client来说,就是调用IServiceManager::getService这个接口来和Binder驱动程序交互了。具体过程上述Server使用Service Manager的方法是一样的,这里就不再累述了。

IServiceManager::addService和IServiceManager::getService这两个函数的具体实现,在下面两篇文章中,会深入到Binder驱动程序这一层,进行详细的源代码分析,以便更好地理解Binder进程间通信机制,敬请关注。

Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

分类: Android 14451人阅读 评论(52) 收藏 举报

在前面一篇文章浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中,介绍了在Android系统中Binder进程间通信机制中的Server角色是如何获得Service Manager远程接口的,即defaultServiceManager函数的实现。Server获得了Service Manager远程接口之后,就要把自己的Service添加到Service Manager中去,然后把自己启动起来,等待Client的请求。本文将通过分析源代码了解Server的启动过程是怎么样的。

本文通过一个具体的例子来说明Binder机制中Server的启动过程。我们知道,在Android系统中,提供了多媒体播放的功能,这个功能是以服务的形式来提供的。这里,我们就通过分析MediaPlayerService的实现来了解Media Server的启动过程。

首先,看一下MediaPlayerService的类图,以便我们理解下面要描述的内容。

Android进程间通信IPC机制Binder_第3张图片

我们将要介绍的主角MediaPlayerService继承于BnMediaPlayerService类,熟悉Binder机制的同学应该知道BnMediaPlayerService是一个Binder Native类,用来处理Client请求的。BnMediaPlayerService继承于BnInterface<IMediaPlayerService>类,BnInterface是一个模板类,它定义在frameworks/base/include/binder/IInterface.h文件中:

[cpp] view plain copy print ?
  1. template<typenameINTERFACE>
  2. classBnInterface:publicINTERFACE,publicBBinder
  3. {
  4. public:
  5. virtualsp<IInterface>queryLocalInterface(constString16&_descriptor);
  6. virtualconstString16&getInterfaceDescriptor()const;
  7. protected:
  8. virtualIBinder*onAsBinder();
  9. };
这里可以看出,BnMediaPlayerService实际是继承了IMediaPlayerService和BBinder类。IMediaPlayerService和BBinder类又分别继承了IInterface和IBinder类,IInterface和IBinder类又同时继承了RefBase类。

实际上,BnMediaPlayerService并不是直接接收到Client处发送过来的请求,而是使用了IPCThreadState接收Client处发送过来的请求,而IPCThreadState又借助了ProcessState类来与Binder驱动程序交互。有关IPCThreadState和ProcessState的关系,可以参考上一篇文章浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路,接下来也会有相应的描述。IPCThreadState接收到了Client处的请求后,就会调用BBinder类的transact函数,并传入相关参数,BBinder类的transact函数最终调用BnMediaPlayerService类的onTransact函数,于是,就开始真正地处理Client的请求了。

了解了MediaPlayerService类结构之后,就要开始进入到本文的主题了。

首先,看看MediaPlayerService是如何启动的。启动MediaPlayerService的代码位于frameworks/base/media/mediaserver/main_mediaserver.cpp文件中:

[cpp] view plain copy print ?
  1. intmain(intargc,char**argv)
  2. {
  3. sp<ProcessState>proc(ProcessState::self());
  4. sp<IServiceManager>sm=defaultServiceManager();
  5. LOGI("ServiceManager:%p",sm.get());
  6. AudioFlinger::instantiate();
  7. MediaPlayerService::instantiate();
  8. CameraService::instantiate();
  9. AudioPolicyService::instantiate();
  10. ProcessState::self()->startThreadPool();
  11. IPCThreadState::self()->joinThreadPool();
  12. }
这里我们不关注AudioFlinger和CameraService相关的代码。

先看下面这句代码:

[cpp] view plain copy print ?
  1. sp<ProcessState>proc(ProcessState::self());
这句代码的作用是通过ProcessState::self()调用创建一个ProcessState实例。ProcessState::self()是ProcessState类的一个静态成员变量,定义在frameworks/base/libs/binder/ProcessState.cpp文件中:

[cpp] view plain copy print ?
  1. sp<ProcessState>ProcessState::self()
  2. {
  3. if(gProcess!=NULL)returngProcess;
  4. AutoMutex_l(gProcessMutex);
  5. if(gProcess==NULL)gProcess=newProcessState;
  6. returngProcess;
  7. }
这里可以看出,这个函数作用是返回一个全局唯一的ProcessState实例gProcess。全局唯一实例变量gProcess定义在frameworks/base/libs/binder/Static.cpp文件中:

[cpp] view plain copy print ?
  1. MutexgProcessMutex;
  2. sp<ProcessState>gProcess;
再来看ProcessState的构造函数:

[cpp] view plain copy print ?
  1. ProcessState::ProcessState()
  2. :mDriverFD(open_driver())
  3. ,mVMStart(MAP_FAILED)
  4. ,mManagesContexts(false)
  5. ,mBinderContextCheckFunc(NULL)
  6. ,mBinderContextUserData(NULL)
  7. ,mThreadPoolStarted(false)
  8. ,mThreadPoolSeq(1)
  9. {
  10. if(mDriverFD>=0){
  11. //XXXIdeally,thereshouldbeaspecificdefineforwhetherwe
  12. //havemmap(orwhetherwecouldpossiblyhavethekernelmodule
  13. //availabla).
  14. #if!defined(HAVE_WIN32_IPC)
  15. //mmapthebinder,providingachunkofvirtualaddressspacetoreceivetransactions.
  16. mVMStart=mmap(0,BINDER_VM_SIZE,PROT_READ,MAP_PRIVATE|MAP_NORESERVE,mDriverFD,0);
  17. if(mVMStart==MAP_FAILED){
  18. //*sigh*
  19. LOGE("Using/dev/binderfailed:unabletommaptransactionmemory.\n");
  20. close(mDriverFD);
  21. mDriverFD=-1;
  22. }
  23. #else
  24. mDriverFD=-1;
  25. #endif
  26. }
  27. if(mDriverFD<0){
  28. //Needtorunwithoutthedriver,startingourownthreadpool.
  29. }
  30. }
这个函数有两个关键地方,一是通过open_driver函数打开Binder设备文件/dev/binder,并将打开设备文件描述符保存在成员变量mDriverFD中;二是通过mmap来把设备文件/dev/binder映射到内存中。

先看open_driver函数的实现,这个函数同样位于frameworks/base/libs/binder/ProcessState.cpp文件中:

[cpp] view plain copy print ?
  1. staticintopen_driver()
  2. {
  3. if(gSingleProcess){
  4. return-1;
  5. }
  6. intfd=open("/dev/binder",O_RDWR);
  7. if(fd>=0){
  8. fcntl(fd,F_SETFD,FD_CLOEXEC);
  9. intvers;
  10. #ifdefined(HAVE_ANDROID_OS)
  11. status_tresult=ioctl(fd,BINDER_VERSION,&vers);
  12. #else
  13. status_tresult=-1;
  14. errno=EPERM;
  15. #endif
  16. if(result==-1){
  17. LOGE("Binderioctltoobtainversionfailed:%s",strerror(errno));
  18. close(fd);
  19. fd=-1;
  20. }
  21. if(result!=0||vers!=BINDER_CURRENT_PROTOCOL_VERSION){
  22. LOGE("Binderdriverprotocoldoesnotmatchuserspaceprotocol!");
  23. close(fd);
  24. fd=-1;
  25. }
  26. #ifdefined(HAVE_ANDROID_OS)
  27. size_tmaxThreads=15;
  28. result=ioctl(fd,BINDER_SET_MAX_THREADS,&maxThreads);
  29. if(result==-1){
  30. LOGE("Binderioctltosetmaxthreadsfailed:%s",strerror(errno));
  31. }
  32. #endif
  33. }else{
  34. LOGW("Opening'/dev/binder'failed:%s\n",strerror(errno));
  35. }
  36. returnfd;
  37. }
这个函数的作用主要是通过open文件操作函数来打开/dev/binder设备文件,然后再调用ioctl文件控制函数来分别执行BINDER_VERSION和BINDER_SET_MAX_THREADS两个命令来和Binder驱动程序进行交互,前者用于获得当前Binder驱动程序的版本号,后者用于通知Binder驱动程序,MediaPlayerService最多可同时启动15个线程来处理Client端的请求。

open在Binder驱动程序中的具体实现,请参考前面一篇文章浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路,这里不再重复描述。打开/dev/binder设备文件后,Binder驱动程序就为MediaPlayerService进程创建了一个struct binder_proc结构体实例来维护MediaPlayerService进程上下文相关信息。

我们来看一下ioctl文件操作函数执行BINDER_VERSION命令的过程:

[cpp] view plain copy print ?
  1. status_tresult=ioctl(fd,BINDER_VERSION,&vers);
这个函数调用最终进入到Binder驱动程序的binder_ioctl函数中,我们只关注BINDER_VERSION相关的部分逻辑:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. ......
  20. caseBINDER_VERSION:
  21. if(size!=sizeof(structbinder_version)){
  22. ret=-EINVAL;
  23. gotoerr;
  24. }
  25. if(put_user(BINDER_CURRENT_PROTOCOL_VERSION,&((structbinder_version*)ubuf)->protocol_version)){
  26. ret=-EINVAL;
  27. gotoerr;
  28. }
  29. break;
  30. ......
  31. }
  32. ret=0;
  33. err:
  34. ......
  35. returnret;
  36. }

很简单,只是将BINDER_CURRENT_PROTOCOL_VERSION写入到传入的参数arg指向的用户缓冲区中去就返回了。BINDER_CURRENT_PROTOCOL_VERSION是一个宏,定义在kernel/common/drivers/staging/android/binder.h文件中:

[cpp] view plain copy print ?
  1. /*Thisisthecurrentprotocolversion.*/
  2. #defineBINDER_CURRENT_PROTOCOL_VERSION7
这里为什么要把ubuf转换成struct binder_version之后,再通过其protocol_version成员变量再来写入呢,转了一圈,最终内容还是写入到ubuf中。我们看一下struct binder_version的定义就会明白,同样是在kernel/common/drivers/staging/android/binder.h文件中:

[cpp] view plain copy print ?
  1. /*UsewithBINDER_VERSION,driverfillsinfields.*/
  2. structbinder_version{
  3. /*driverprotocolversion--incrementwithincompatiblechange*/
  4. signedlongprotocol_version;
  5. };
从注释中可以看出来,这里是考虑到兼容性,因为以后很有可能不是用signed long来表示版本号。

这里有一个重要的地方要注意的是,由于这里是打开设备文件/dev/binder之后,第一次进入到binder_ioctl函数,因此,这里调用binder_get_thread的时候,就会为当前线程创建一个struct binder_thread结构体变量来维护线程上下文信息,具体可以参考浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文。

接着我们再来看一下ioctl文件操作函数执行BINDER_SET_MAX_THREADS命令的过程:

[cpp] view plain copy print ?
  1. result=ioctl(fd,BINDER_SET_MAX_THREADS,&maxThreads);

这个函数调用最终进入到Binder驱动程序的binder_ioctl函数中,我们只关注BINDER_SET_MAX_THREADS相关的部分逻辑:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. ......
  20. caseBINDER_SET_MAX_THREADS:
  21. if(copy_from_user(&proc->max_threads,ubuf,sizeof(proc->max_threads))){
  22. ret=-EINVAL;
  23. gotoerr;
  24. }
  25. break;
  26. ......
  27. }
  28. ret=0;
  29. err:
  30. ......
  31. returnret;
  32. }
这里实现也是非常简单,只是简单地把用户传进来的参数保存在proc->max_threads中就完毕了。注意,这里再调用binder_get_thread函数的时候,就可以在proc->threads中找到当前线程对应的struct binder_thread结构了,因为前面已经创建好并保存在proc->threads红黑树中。

回到ProcessState的构造函数中,这里还通过mmap函数来把设备文件/dev/binder映射到内存中,这个函数在浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文也已经有详细介绍,这里不再重复描述。宏BINDER_VM_SIZE就定义在ProcessState.cpp文件中:

[cpp] view plain copy print ?
  1. #defineBINDER_VM_SIZE((1*1024*1024)-(4096*2))
mmap函数调用完成之后,Binder驱动程序就为当前进程预留了BINDER_VM_SIZE大小的内存空间了。

这样,ProcessState全局唯一变量gProcess就创建完毕了,回到frameworks/base/media/mediaserver/main_mediaserver.cpp文件中的main函数,下一步是调用defaultServiceManager函数来获得Service Manager的远程接口,这个已经在上一篇文章浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路有详细描述,读者可以回过头去参考一下。

再接下来,就进入到MediaPlayerService::instantiate函数把MediaPlayerService添加到Service Manger中去了。这个函数定义在frameworks/base/media/libmediaplayerservice/MediaPlayerService.cpp文件中:

[cpp] view plain copy print ?
  1. voidMediaPlayerService::instantiate(){
  2. defaultServiceManager()->addService(
  3. String16("media.player"),newMediaPlayerService());
  4. }
我们重点看一下IServiceManger::addService的过程,这有助于我们加深对Binder机制的理解。

在上一篇文章浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中说到,defaultServiceManager返回的实际是一个BpServiceManger类实例,因此,我们看一下BpServiceManger::addService的实现,这个函数实现在frameworks/base/libs/binder/IServiceManager.cpp文件中:

[cpp] view plain copy print ?
  1. classBpServiceManager:publicBpInterface<IServiceManager>
  2. {
  3. public:
  4. BpServiceManager(constsp<IBinder>&impl)
  5. :BpInterface<IServiceManager>(impl)
  6. {
  7. }
  8. ......
  9. virtualstatus_taddService(constString16&name,constsp<IBinder>&service)
  10. {
  11. Parceldata,reply;
  12. data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
  13. data.writeString16(name);
  14. data.writeStrongBinder(service);
  15. status_terr=remote()->transact(ADD_SERVICE_TRANSACTION,data,&reply);
  16. returnerr==NO_ERROR?reply.readExceptionCode()
  17. }
  18. ......
  19. };

这里的Parcel类是用来于序列化进程间通信数据用的。

先来看这一句的调用:

[cpp] view plain copy print ?
  1. data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
IServiceManager::getInterfaceDescriptor()返回来的是一个字符串,即"android.os.IServiceManager",具体可以参考IServiceManger的实现。我们看一下Parcel::writeInterfaceToken的实现,位于frameworks/base/libs/binder/Parcel.cpp文件中:

[cpp] view plain copy print ?
  1. //WriteRPCheaders.(previouslyjusttheinterfacetoken)
  2. status_tParcel::writeInterfaceToken(constString16&interface)
  3. {
  4. writeInt32(IPCThreadState::self()->getStrictModePolicy()|
  5. STRICT_MODE_PENALTY_GATHER);
  6. //currentlytheinterfaceidentificationtokenisjustitsnameasastring
  7. returnwriteString16(interface);
  8. }
它的作用是写入一个整数和一个字符串到Parcel中去。

再来看下面的调用:

[cpp] view plain copy print ?
  1. data.writeString16(name);
这里又是写入一个字符串到Parcel中去,这里的name即是上面传进来的“media.player”字符串。

往下看:

[cpp] view plain copy print ?
  1. data.writeStrongBinder(service);
这里定入一个Binder对象到Parcel去。我们重点看一下这个函数的实现,因为它涉及到进程间传输Binder实体的问题,比较复杂,需要重点关注,同时,也是理解Binder机制的一个重点所在。注意,这里的service参数是一个MediaPlayerService对象。

[cpp] view plain copy print ?
  1. status_tParcel::writeStrongBinder(constsp<IBinder>&val)
  2. {
  3. returnflatten_binder(ProcessState::self(),val,this);
  4. }
看到flatten_binder函数,是不是似曾相识的感觉?我们在前面一篇文章 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路中,曾经提到在Binder驱动程序中,使用struct flat_binder_object来表示传输中的一个binder对象,它的定义如下所示:

[cpp] view plain copy print ?
  1. /*
  2. *ThisistheflattenedrepresentationofaBinderobjectfortransfer
  3. *betweenprocesses.The'offsets'suppliedaspartofabindertransaction
  4. *containsoffsetsintothedatawherethesestructuresoccur.TheBinder
  5. *drivertakescareofre-writingthestructuretypeanddataasitmoves
  6. *betweenprocesses.
  7. */
  8. structflat_binder_object{
  9. /*8bytesforlarge_flat_header.*/
  10. unsignedlongtype;
  11. unsignedlongflags;
  12. /*8bytesofdata.*/
  13. union{
  14. void*binder;/*localobject*/
  15. signedlonghandle;/*remoteobject*/
  16. };
  17. /*extradataassociatedwithlocalobject*/
  18. void*cookie;
  19. };
各个成员变量的含义请参考资料 Android Binder设计与实现。

我们进入到flatten_binder函数看看:

[cpp] view plain copy print ?
  1. status_tflatten_binder(constsp<ProcessState>&proc,
  2. constsp<IBinder>&binder,Parcel*out)
  3. {
  4. flat_binder_objectobj;
  5. obj.flags=0x7f|FLAT_BINDER_FLAG_ACCEPTS_FDS;
  6. if(binder!=NULL){
  7. IBinder*local=binder->localBinder();
  8. if(!local){
  9. BpBinder*proxy=binder->remoteBinder();
  10. if(proxy==NULL){
  11. LOGE("nullproxy");
  12. }
  13. constint32_thandle=proxy?proxy->handle():0;
  14. obj.type=BINDER_TYPE_HANDLE;
  15. obj.handle=handle;
  16. obj.cookie=NULL;
  17. }else{
  18. obj.type=BINDER_TYPE_BINDER;
  19. obj.binder=local->getWeakRefs();
  20. obj.cookie=local;
  21. }
  22. }else{
  23. obj.type=BINDER_TYPE_BINDER;
  24. obj.binder=NULL;
  25. obj.cookie=NULL;
  26. }
  27. returnfinish_flatten_binder(binder,obj,out);
  28. }
首先是初始化flat_binder_object的flags域:

[cpp] view plain copy print ?
  1. obj.flags=0x7f|FLAT_BINDER_FLAG_ACCEPTS_FDS;
0x7f表示处理本Binder实体请求数据包的线程的最低优先级,FLAT_BINDER_FLAG_ACCEPTS_FDS表示这个Binder实体可以接受文件描述符,Binder实体在收到文件描述符时,就会在本进程中打开这个文件。

传进来的binder即为MediaPlayerService::instantiate函数中new出来的MediaPlayerService实例,因此,不为空。又由于MediaPlayerService继承自BBinder类,它是一个本地Binder实体,因此binder->localBinder返回一个BBinder指针,而且肯定不为空,于是执行下面语句:

[cpp] view plain copy print ?
  1. obj.type=BINDER_TYPE_BINDER;
  2. obj.binder=local->getWeakRefs();
  3. obj.cookie=local;
设置了flat_binder_obj的其他成员变量,注意,指向这个Binder实体地址的指针local保存在flat_binder_obj的成员变量cookie中。

函数调用finish_flatten_binder来将这个flat_binder_obj写入到Parcel中去:

[cpp] view plain copy print ?
  1. inlinestaticstatus_tfinish_flatten_binder(
  2. constsp<IBinder>&binder,constflat_binder_object&flat,Parcel*out)
  3. {
  4. returnout->writeObject(flat,false);
  5. }
Parcel::writeObject的实现如下:

[cpp] view plain copy print ?
  1. status_tParcel::writeObject(constflat_binder_object&val,boolnullMetaData)
  2. {
  3. constboolenoughData=(mDataPos+sizeof(val))<=mDataCapacity;
  4. constboolenoughObjects=mObjectsSize<mObjectsCapacity;
  5. if(enoughData&&enoughObjects){
  6. restart_write:
  7. *reinterpret_cast<flat_binder_object*>(mData+mDataPos)=val;
  8. //Needtowritemeta-data?
  9. if(nullMetaData||val.binder!=NULL){
  10. mObjects[mObjectsSize]=mDataPos;
  11. acquire_object(ProcessState::self(),val,this);
  12. mObjectsSize++;
  13. }
  14. //rememberifit'safiledescriptor
  15. if(val.type==BINDER_TYPE_FD){
  16. mHasFds=mFdsKnown=true;
  17. }
  18. returnfinishWrite(sizeof(flat_binder_object));
  19. }
  20. if(!enoughData){
  21. conststatus_terr=growData(sizeof(val));
  22. if(err!=NO_ERROR)returnerr;
  23. }
  24. if(!enoughObjects){
  25. size_tnewSize=((mObjectsSize+2)*3)/2;
  26. size_t*objects=(size_t*)realloc(mObjects,newSize*sizeof(size_t));
  27. if(objects==NULL)returnNO_MEMORY;
  28. mObjects=objects;
  29. mObjectsCapacity=newSize;
  30. }
  31. gotorestart_write;
  32. }
这里除了把flat_binder_obj写到Parcel里面之内,还要记录这个flat_binder_obj在Parcel里面的偏移位置:

[cpp] view plain copy print ?
  1. mObjects[mObjectsSize]=mDataPos;
这里因为,如果进程间传输的数据间带有Binder对象的时候,Binder驱动程序需要作进一步的处理,以维护各个Binder实体的一致性,下面我们将会看到Binder驱动程序是怎么处理这些Binder对象的。

再回到BpServiceManager::addService函数中,调用下面语句:

[cpp] view plain copy print ?
  1. status_terr=remote()->transact(ADD_SERVICE_TRANSACTION,data,&reply);
回到 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路一文中的类图中去看一下,这里的remote成员函数来自于BpRefBase类,它返回一个BpBinder指针。因此,我们继续进入到BpBinder::transact函数中去看看:

[cpp] view plain copy print ?
  1. status_tBpBinder::transact(
  2. uint32_tcode,constParcel&data,Parcel*reply,uint32_tflags)
  3. {
  4. //Onceabinderhasdied,itwillnevercomebacktolife.
  5. if(mAlive){
  6. status_tstatus=IPCThreadState::self()->transact(
  7. mHandle,code,data,reply,flags);
  8. if(status==DEAD_OBJECT)mAlive=0;
  9. returnstatus;
  10. }
  11. returnDEAD_OBJECT;
  12. }
这里又调用了IPCThreadState::transact进执行实际的操作。注意,这里的mHandle为0,code为ADD_SERVICE_TRANSACTION。ADD_SERVICE_TRANSACTION是上面以参数形式传进来的,那mHandle为什么是0呢?因为这里表示的是Service Manager远程接口,它的句柄值一定是0,具体请参考 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路一文。
再进入到IPCThreadState::transact函数,看看做了些什么事情:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::transact(int32_thandle,
  2. uint32_tcode,constParcel&data,
  3. Parcel*reply,uint32_tflags)
  4. {
  5. status_terr=data.errorCheck();
  6. flags|=TF_ACCEPT_FDS;
  7. IF_LOG_TRANSACTIONS(){
  8. TextOutput::Bundle_b(alog);
  9. alog<<"BC_TRANSACTIONthr"<<(void*)pthread_self()<<"/hand"
  10. <<handle<<"/code"<<TypeCode(code)<<":"
  11. <<indent<<data<<dedent<<endl;
  12. }
  13. if(err==NO_ERROR){
  14. LOG_ONEWAY(">>>>SENDfrompid%duid%d%s",getpid(),getuid(),
  15. (flags&TF_ONE_WAY)==0?"READREPLY":"ONEWAY");
  16. err=writeTransactionData(BC_TRANSACTION,flags,handle,code,data,NULL);
  17. }
  18. if(err!=NO_ERROR){
  19. if(reply)reply->setError(err);
  20. return(mLastError=err);
  21. }
  22. if((flags&TF_ONE_WAY)==0){
  23. #if0
  24. if(code==4){//relayout
  25. LOGI(">>>>>>CALLINGtransaction4");
  26. }else{
  27. LOGI(">>>>>>CALLINGtransaction%d",code);
  28. }
  29. #endif
  30. if(reply){
  31. err=waitForResponse(reply);
  32. }else{
  33. ParcelfakeReply;
  34. err=waitForResponse(&fakeReply);
  35. }
  36. #if0
  37. if(code==4){//relayout
  38. LOGI("<<<<<<RETURNINGtransaction4");
  39. }else{
  40. LOGI("<<<<<<RETURNINGtransaction%d",code);
  41. }
  42. #endif
  43. IF_LOG_TRANSACTIONS(){
  44. TextOutput::Bundle_b(alog);
  45. alog<<"BR_REPLYthr"<<(void*)pthread_self()<<"/hand"
  46. <<handle<<":";
  47. if(reply)alog<<indent<<*reply<<dedent<<endl;
  48. elsealog<<"(nonerequested)"<<endl;
  49. }
  50. }else{
  51. err=waitForResponse(NULL,NULL);
  52. }
  53. returnerr;
  54. }
IPCThreadState::transact函数的参数flags是一个默认值为0的参数,上面没有传相应的实参进来,因此,这里就为0。

函数首先调用writeTransactionData函数准备好一个structbinder_transaction_data结构体变量,这个是等一下要传输给Binder驱动程序的。structbinder_transaction_data的定义我们在浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文中有详细描述,读者不妨回过去读一下。这里为了方便描述,将structbinder_transaction_data的定义再次列出来:

[cpp] view plain copy print ?
  1. structbinder_transaction_data{
  2. /*ThefirsttwoareonlyusedforbcTRANSACTIONandbrTRANSACTION,
  3. *identifyingthetargetandcontentsofthetransaction.
  4. */
  5. union{
  6. size_thandle;/*targetdescriptorofcommandtransaction*/
  7. void*ptr;/*targetdescriptorofreturntransaction*/
  8. }target;
  9. void*cookie;/*targetobjectcookie*/
  10. unsignedintcode;/*transactioncommand*/
  11. /*Generalinformationaboutthetransaction.*/
  12. unsignedintflags;
  13. pid_tsender_pid;
  14. uid_tsender_euid;
  15. size_tdata_size;/*numberofbytesofdata*/
  16. size_toffsets_size;/*numberofbytesofoffsets*/
  17. /*Ifthistransactionisinline,thedataimmediately
  18. *followshere;otherwise,itendswithapointerto
  19. *thedatabuffer.
  20. */
  21. union{
  22. struct{
  23. /*transactiondata*/
  24. constvoid*buffer;
  25. /*offsetsfrombuffertoflat_binder_objectstructs*/
  26. constvoid*offsets;
  27. }ptr;
  28. uint8_tbuf[8];
  29. }data;
  30. };
writeTransactionData函数的实现如下:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::writeTransactionData(int32_tcmd,uint32_tbinderFlags,
  2. int32_thandle,uint32_tcode,constParcel&data,status_t*statusBuffer)
  3. {
  4. binder_transaction_datatr;
  5. tr.target.handle=handle;
  6. tr.code=code;
  7. tr.flags=binderFlags;
  8. conststatus_terr=data.errorCheck();
  9. if(err==NO_ERROR){
  10. tr.data_size=data.ipcDataSize();
  11. tr.data.ptr.buffer=data.ipcData();
  12. tr.offsets_size=data.ipcObjectsCount()*sizeof(size_t);
  13. tr.data.ptr.offsets=data.ipcObjects();
  14. }elseif(statusBuffer){
  15. tr.flags|=TF_STATUS_CODE;
  16. *statusBuffer=err;
  17. tr.data_size=sizeof(status_t);
  18. tr.data.ptr.buffer=statusBuffer;
  19. tr.offsets_size=0;
  20. tr.data.ptr.offsets=NULL;
  21. }else{
  22. return(mLastError=err);
  23. }
  24. mOut.writeInt32(cmd);
  25. mOut.write(&tr,sizeof(tr));
  26. returnNO_ERROR;
  27. }

注意,这里的cmd为BC_TRANSACTION。这个函数很简单,在这个场景下,就是执行下面语句来初始化本地变量tr:

[cpp] view plain copy print ?
  1. tr.data_size=data.ipcDataSize();
  2. tr.data.ptr.buffer=data.ipcData();
  3. tr.offsets_size=data.ipcObjectsCount()*sizeof(size_t);
  4. tr.data.ptr.offsets=data.ipcObjects();
回忆一下上面的内容,写入到tr.data.ptr.buffer的内容相当于下面的内容:

[cpp] view plain copy print ?
  1. writeInt32(IPCThreadState::self()->getStrictModePolicy()|
  2. STRICT_MODE_PENALTY_GATHER);
  3. writeString16("android.os.IServiceManager");
  4. writeString16("media.player");
  5. writeStrongBinder(newMediaPlayerService());
其中包含了一个Binder实体MediaPlayerService,因此需要设置tr.offsets_size就为1,tr.data.ptr.offsets就指向了这个MediaPlayerService的地址在tr.data.ptr.buffer中的偏移量。最后,将tr的内容保存在IPCThreadState的成员变量mOut中。
回到IPCThreadState::transact函数中,接下去看,(flags & TF_ONE_WAY) == 0为true,并且reply不为空,所以最终进入到waitForResponse(reply)这条路径来。我们看一下waitForResponse函数的实现:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::waitForResponse(Parcel*reply,status_t*acquireResult)
  2. {
  3. int32_tcmd;
  4. int32_terr;
  5. while(1){
  6. if((err=talkWithDriver())<NO_ERROR)break;
  7. err=mIn.errorCheck();
  8. if(err<NO_ERROR)break;
  9. if(mIn.dataAvail()==0)continue;
  10. cmd=mIn.readInt32();
  11. IF_LOG_COMMANDS(){
  12. alog<<"ProcessingwaitForResponseCommand:"
  13. <<getReturnString(cmd)<<endl;
  14. }
  15. switch(cmd){
  16. caseBR_TRANSACTION_COMPLETE:
  17. if(!reply&&!acquireResult)gotofinish;
  18. break;
  19. caseBR_DEAD_REPLY:
  20. err=DEAD_OBJECT;
  21. gotofinish;
  22. caseBR_FAILED_REPLY:
  23. err=FAILED_TRANSACTION;
  24. gotofinish;
  25. caseBR_ACQUIRE_RESULT:
  26. {
  27. LOG_ASSERT(acquireResult!=NULL,"UnexpectedbrACQUIRE_RESULT");
  28. constint32_tresult=mIn.readInt32();
  29. if(!acquireResult)continue;
  30. *acquireResult=result?NO_ERROR:INVALID_OPERATION;
  31. }
  32. gotofinish;
  33. caseBR_REPLY:
  34. {
  35. binder_transaction_datatr;
  36. err=mIn.read(&tr,sizeof(tr));
  37. LOG_ASSERT(err==NO_ERROR,"NotenoughcommanddataforbrREPLY");
  38. if(err!=NO_ERROR)gotofinish;
  39. if(reply){
  40. if((tr.flags&TF_STATUS_CODE)==0){
  41. reply->ipcSetDataReference(
  42. reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),
  43. tr.data_size,
  44. reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),
  45. tr.offsets_size/sizeof(size_t),
  46. freeBuffer,this);
  47. }else{
  48. err=*static_cast<conststatus_t*>(tr.data.ptr.buffer);
  49. freeBuffer(NULL,
  50. reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),
  51. tr.data_size,
  52. reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),
  53. tr.offsets_size/sizeof(size_t),this);
  54. }
  55. }else{
  56. freeBuffer(NULL,
  57. reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),
  58. tr.data_size,
  59. reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),
  60. tr.offsets_size/sizeof(size_t),this);
  61. continue;
  62. }
  63. }
  64. gotofinish;
  65. default:
  66. err=executeCommand(cmd);
  67. if(err!=NO_ERROR)gotofinish;
  68. break;
  69. }
  70. }
  71. finish:
  72. if(err!=NO_ERROR){
  73. if(acquireResult)*acquireResult=err;
  74. if(reply)reply->setError(err);
  75. mLastError=err;
  76. }
  77. returnerr;
  78. }
这个函数虽然很长,但是主要调用了talkWithDriver函数来与Binder驱动程序进行交互:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::talkWithDriver(booldoReceive)
  2. {
  3. LOG_ASSERT(mProcess->mDriverFD>=0,"Binderdriverisnotopened");
  4. binder_write_readbwr;
  5. //Isthereadbufferempty?
  6. constboolneedRead=mIn.dataPosition()>=mIn.dataSize();
  7. //Wedon'twanttowriteanythingifwearestillreading
  8. //fromdataleftintheinputbufferandthecaller
  9. //hasrequestedtoreadthenextdata.
  10. constsize_toutAvail=(!doReceive||needRead)?mOut.dataSize():0;
  11. bwr.write_size=outAvail;
  12. bwr.write_buffer=(longunsignedint)mOut.data();
  13. //Thisiswhatwe'llread.
  14. if(doReceive&&needRead){
  15. bwr.read_size=mIn.dataCapacity();
  16. bwr.read_buffer=(longunsignedint)mIn.data();
  17. }else{
  18. bwr.read_size=0;
  19. }
  20. IF_LOG_COMMANDS(){
  21. TextOutput::Bundle_b(alog);
  22. if(outAvail!=0){
  23. alog<<"Sendingcommandstodriver:"<<indent;
  24. constvoid*cmds=(constvoid*)bwr.write_buffer;
  25. constvoid*end=((constuint8_t*)cmds)+bwr.write_size;
  26. alog<<HexDump(cmds,bwr.write_size)<<endl;
  27. while(cmds<end)cmds=printCommand(alog,cmds);
  28. alog<<dedent;
  29. }
  30. alog<<"Sizeofreceivebuffer:"<<bwr.read_size
  31. <<",needRead:"<<needRead<<",doReceive:"<<doReceive<<endl;
  32. }
  33. //Returnimmediatelyifthereisnothingtodo.
  34. if((bwr.write_size==0)&&(bwr.read_size==0))returnNO_ERROR;
  35. bwr.write_consumed=0;
  36. bwr.read_consumed=0;
  37. status_terr;
  38. do{
  39. IF_LOG_COMMANDS(){
  40. alog<<"Abouttoread/write,writesize="<<mOut.dataSize()<<endl;
  41. }
  42. #ifdefined(HAVE_ANDROID_OS)
  43. if(ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr)>=0)
  44. err=NO_ERROR;
  45. else
  46. err=-errno;
  47. #else
  48. err=INVALID_OPERATION;
  49. #endif
  50. IF_LOG_COMMANDS(){
  51. alog<<"Finishedread/write,writesize="<<mOut.dataSize()<<endl;
  52. }
  53. }while(err==-EINTR);
  54. IF_LOG_COMMANDS(){
  55. alog<<"Ourerr:"<<(void*)err<<",writeconsumed:"
  56. <<bwr.write_consumed<<"(of"<<mOut.dataSize()
  57. <<"),readconsumed:"<<bwr.read_consumed<<endl;
  58. }
  59. if(err>=NO_ERROR){
  60. if(bwr.write_consumed>0){
  61. if(bwr.write_consumed<(ssize_t)mOut.dataSize())
  62. mOut.remove(0,bwr.write_consumed);
  63. else
  64. mOut.setDataSize(0);
  65. }
  66. if(bwr.read_consumed>0){
  67. mIn.setDataSize(bwr.read_consumed);
  68. mIn.setDataPosition(0);
  69. }
  70. IF_LOG_COMMANDS(){
  71. TextOutput::Bundle_b(alog);
  72. alog<<"Remainingdatasize:"<<mOut.dataSize()<<endl;
  73. alog<<"Receivedcommandsfromdriver:"<<indent;
  74. constvoid*cmds=mIn.data();
  75. constvoid*end=mIn.data()+mIn.dataSize();
  76. alog<<HexDump(cmds,mIn.dataSize())<<endl;
  77. while(cmds<end)cmds=printReturnCommand(alog,cmds);
  78. alog<<dedent;
  79. }
  80. returnNO_ERROR;
  81. }
  82. returnerr;
  83. }
这里doReceive和needRead均为1,有兴趣的读者可以自已分析一下。因此,这里告诉Binder驱动程序,先执行write操作,再执行read操作,下面我们将会看到。

最后,通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)进行到Binder驱动程序的binder_ioctl函数,我们只关注cmd为BINDER_WRITE_READ的逻辑:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. caseBINDER_WRITE_READ:{
  20. structbinder_write_readbwr;
  21. if(size!=sizeof(structbinder_write_read)){
  22. ret=-EINVAL;
  23. gotoerr;
  24. }
  25. if(copy_from_user(&bwr,ubuf,sizeof(bwr))){
  26. ret=-EFAULT;
  27. gotoerr;
  28. }
  29. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  30. printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",
  31. proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);
  32. if(bwr.write_size>0){
  33. ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
  34. if(ret<0){
  35. bwr.read_consumed=0;
  36. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  37. ret=-EFAULT;
  38. gotoerr;
  39. }
  40. }
  41. if(bwr.read_size>0){
  42. ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);
  43. if(!list_empty(&proc->todo))
  44. wake_up_interruptible(&proc->wait);
  45. if(ret<0){
  46. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  47. ret=-EFAULT;
  48. gotoerr;
  49. }
  50. }
  51. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  52. printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",
  53. proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);
  54. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  55. ret=-EFAULT;
  56. gotoerr;
  57. }
  58. break;
  59. }
  60. ......
  61. }
  62. ret=0;
  63. err:
  64. ......
  65. returnret;
  66. }
函数首先是将用户传进来的参数拷贝到本地变量struct binder_write_read bwr中去。这里bwr.write_size > 0为true,因此,进入到binder_thread_write函数中,我们只关注BC_TRANSACTION部分的逻辑:

[cpp] view plain copy print ?
  1. binder_thread_write(structbinder_proc*proc,structbinder_thread*thread,
  2. void__user*buffer,intsize,signedlong*consumed)
  3. {
  4. uint32_tcmd;
  5. void__user*ptr=buffer+*consumed;
  6. void__user*end=buffer+size;
  7. while(ptr<end&&thread->return_error==BR_OK){
  8. if(get_user(cmd,(uint32_t__user*)ptr))
  9. return-EFAULT;
  10. ptr+=sizeof(uint32_t);
  11. if(_IOC_NR(cmd)<ARRAY_SIZE(binder_stats.bc)){
  12. binder_stats.bc[_IOC_NR(cmd)]++;
  13. proc->stats.bc[_IOC_NR(cmd)]++;
  14. thread->stats.bc[_IOC_NR(cmd)]++;
  15. }
  16. switch(cmd){
  17. .....
  18. caseBC_TRANSACTION:
  19. caseBC_REPLY:{
  20. structbinder_transaction_datatr;
  21. if(copy_from_user(&tr,ptr,sizeof(tr)))
  22. return-EFAULT;
  23. ptr+=sizeof(tr);
  24. binder_transaction(proc,thread,&tr,cmd==BC_REPLY);
  25. break;
  26. }
  27. ......
  28. }
  29. *consumed=ptr-buffer;
  30. }
  31. return0;
  32. }
首先将用户传进来的transact参数拷贝在本地变量struct binder_transaction_data tr中去,接着调用binder_transaction函数进一步处理,这里我们忽略掉无关代码:

[cpp] view plain copy print ?
  1. staticvoid
  2. binder_transaction(structbinder_proc*proc,structbinder_thread*thread,
  3. structbinder_transaction_data*tr,intreply)
  4. {
  5. structbinder_transaction*t;
  6. structbinder_work*tcomplete;
  7. size_t*offp,*off_end;
  8. structbinder_proc*target_proc;
  9. structbinder_thread*target_thread=NULL;
  10. structbinder_node*target_node=NULL;
  11. structlist_head*target_list;
  12. wait_queue_head_t*target_wait;
  13. structbinder_transaction*in_reply_to=NULL;
  14. structbinder_transaction_log_entry*e;
  15. uint32_treturn_error;
  16. ......
  17. if(reply){
  18. ......
  19. }else{
  20. if(tr->target.handle){
  21. ......
  22. }else{
  23. target_node=binder_context_mgr_node;
  24. if(target_node==NULL){
  25. return_error=BR_DEAD_REPLY;
  26. gotoerr_no_context_mgr_node;
  27. }
  28. }
  29. ......
  30. target_proc=target_node->proc;
  31. if(target_proc==NULL){
  32. return_error=BR_DEAD_REPLY;
  33. gotoerr_dead_binder;
  34. }
  35. ......
  36. }
  37. if(target_thread){
  38. ......
  39. }else{
  40. target_list=&target_proc->todo;
  41. target_wait=&target_proc->wait;
  42. }
  43. ......
  44. /*TODO:reuseincomingtransactionforreply*/
  45. t=kzalloc(sizeof(*t),GFP_KERNEL);
  46. if(t==NULL){
  47. return_error=BR_FAILED_REPLY;
  48. gotoerr_alloc_t_failed;
  49. }
  50. ......
  51. tcomplete=kzalloc(sizeof(*tcomplete),GFP_KERNEL);
  52. if(tcomplete==NULL){
  53. return_error=BR_FAILED_REPLY;
  54. gotoerr_alloc_tcomplete_failed;
  55. }
  56. ......
  57. if(!reply&&!(tr->flags&TF_ONE_WAY))
  58. t->from=thread;
  59. else
  60. t->from=NULL;
  61. t->sender_euid=proc->tsk->cred->euid;
  62. t->to_proc=target_proc;
  63. t->to_thread=target_thread;
  64. t->code=tr->code;
  65. t->flags=tr->flags;
  66. t->priority=task_nice(current);
  67. t->buffer=binder_alloc_buf(target_proc,tr->data_size,
  68. tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY));
  69. if(t->buffer==NULL){
  70. return_error=BR_FAILED_REPLY;
  71. gotoerr_binder_alloc_buf_failed;
  72. }
  73. t->buffer->allow_user_free=0;
  74. t->buffer->debug_id=t->debug_id;
  75. t->buffer->transaction=t;
  76. t->buffer->target_node=target_node;
  77. if(target_node)
  78. binder_inc_node(target_node,1,0,NULL);
  79. offp=(size_t*)(t->buffer->data+ALIGN(tr->data_size,sizeof(void*)));
  80. if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){
  81. ......
  82. return_error=BR_FAILED_REPLY;
  83. gotoerr_copy_data_failed;
  84. }
  85. if(copy_from_user(offp,tr->data.ptr.offsets,tr->offsets_size)){
  86. ......
  87. return_error=BR_FAILED_REPLY;
  88. gotoerr_copy_data_failed;
  89. }
  90. ......
  91. off_end=(void*)offp+tr->offsets_size;
  92. for(;offp<off_end;offp++){
  93. structflat_binder_object*fp;
  94. ......
  95. fp=(structflat_binder_object*)(t->buffer->data+*offp);
  96. switch(fp->type){
  97. caseBINDER_TYPE_BINDER:
  98. caseBINDER_TYPE_WEAK_BINDER:{
  99. structbinder_ref*ref;
  100. structbinder_node*node=binder_get_node(proc,fp->binder);
  101. if(node==NULL){
  102. node=binder_new_node(proc,fp->binder,fp->cookie);
  103. if(node==NULL){
  104. return_error=BR_FAILED_REPLY;
  105. gotoerr_binder_new_node_failed;
  106. }
  107. node->min_priority=fp->flags&FLAT_BINDER_FLAG_PRIORITY_MASK;
  108. node->accept_fds=!!(fp->flags&FLAT_BINDER_FLAG_ACCEPTS_FDS);
  109. }
  110. if(fp->cookie!=node->cookie){
  111. ......
  112. gotoerr_binder_get_ref_for_node_failed;
  113. }
  114. ref=binder_get_ref_for_node(target_proc,node);
  115. if(ref==NULL){
  116. return_error=BR_FAILED_REPLY;
  117. gotoerr_binder_get_ref_for_node_failed;
  118. }
  119. if(fp->type==BINDER_TYPE_BINDER)
  120. fp->type=BINDER_TYPE_HANDLE;
  121. else
  122. fp->type=BINDER_TYPE_WEAK_HANDLE;
  123. fp->handle=ref->desc;
  124. binder_inc_ref(ref,fp->type==BINDER_TYPE_HANDLE,&thread->todo);
  125. ......
  126. }break;
  127. ......
  128. }
  129. }
  130. if(reply){
  131. ......
  132. }elseif(!(t->flags&TF_ONE_WAY)){
  133. BUG_ON(t->buffer->async_transaction!=0);
  134. t->need_reply=1;
  135. t->from_parent=thread->transaction_stack;
  136. thread->transaction_stack=t;
  137. }else{
  138. ......
  139. }
  140. t->work.type=BINDER_WORK_TRANSACTION;
  141. list_add_tail(&t->work.entry,target_list);
  142. tcomplete->type=BINDER_WORK_TRANSACTION_COMPLETE;
  143. list_add_tail(&tcomplete->entry,&thread->todo);
  144. if(target_wait)
  145. wake_up_interruptible(target_wait);
  146. return;
  147. ......
  148. }
注意,这里传进来的参数reply为0,tr->target.handle也为0。因此,target_proc、target_thread、target_node、target_list和target_wait的值分别为:

[cpp] view plain copy print ?
  1. target_node=binder_context_mgr_node;
  2. target_proc=target_node->proc;
  3. target_list=&target_proc->todo;
  4. target_wait=&target_proc->wait;
接着,分配了一个待处理事务t和一个待完成工作项tcomplete,并执行初始化工作:

[cpp] view plain copy print ?
  1. /*TODO:reuseincomingtransactionforreply*/
  2. t=kzalloc(sizeof(*t),GFP_KERNEL);
  3. if(t==NULL){
  4. return_error=BR_FAILED_REPLY;
  5. gotoerr_alloc_t_failed;
  6. }
  7. ......
  8. tcomplete=kzalloc(sizeof(*tcomplete),GFP_KERNEL);
  9. if(tcomplete==NULL){
  10. return_error=BR_FAILED_REPLY;
  11. gotoerr_alloc_tcomplete_failed;
  12. }
  13. ......
  14. if(!reply&&!(tr->flags&TF_ONE_WAY))
  15. t->from=thread;
  16. else
  17. t->from=NULL;
  18. t->sender_euid=proc->tsk->cred->euid;
  19. t->to_proc=target_proc;
  20. t->to_thread=target_thread;
  21. t->code=tr->code;
  22. t->flags=tr->flags;
  23. t->priority=task_nice(current);
  24. t->buffer=binder_alloc_buf(target_proc,tr->data_size,
  25. tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY));
  26. if(t->buffer==NULL){
  27. return_error=BR_FAILED_REPLY;
  28. gotoerr_binder_alloc_buf_failed;
  29. }
  30. t->buffer->allow_user_free=0;
  31. t->buffer->debug_id=t->debug_id;
  32. t->buffer->transaction=t;
  33. t->buffer->target_node=target_node;
  34. if(target_node)
  35. binder_inc_node(target_node,1,0,NULL);
  36. offp=(size_t*)(t->buffer->data+ALIGN(tr->data_size,sizeof(void*)));
  37. if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){
  38. ......
  39. return_error=BR_FAILED_REPLY;
  40. gotoerr_copy_data_failed;
  41. }
  42. if(copy_from_user(offp,tr->data.ptr.offsets,tr->offsets_size)){
  43. ......
  44. return_error=BR_FAILED_REPLY;
  45. gotoerr_copy_data_failed;
  46. }
注意,这里的事务t是要交给target_proc处理的,在这个场景之下,就是Service Manager了。因此,下面的语句:

[cpp] view plain copy print ?
  1. t->buffer=binder_alloc_buf(target_proc,tr->data_size,
  2. tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY));
就是在Service Manager的进程空间中分配一块内存来保存用户传进入的参数了:

[cpp] view plain copy print ?
  1. if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){
  2. ......
  3. return_error=BR_FAILED_REPLY;
  4. gotoerr_copy_data_failed;
  5. }
  6. if(copy_from_user(offp,tr->data.ptr.offsets,tr->offsets_size)){
  7. ......
  8. return_error=BR_FAILED_REPLY;
  9. gotoerr_copy_data_failed;
  10. }
由于现在target_node要被使用了,增加它的引用计数:

[cpp] view plain copy print ?
  1. if(target_node)
  2. binder_inc_node(target_node,1,0,NULL);
接下去的for循环,就是用来处理传输数据中的Binder对象了。在我们的场景中,有一个类型为BINDER_TYPE_BINDER的Binder实体MediaPlayerService:

[cpp] view plain copy print ?
  1. switch(fp->type){
  2. caseBINDER_TYPE_BINDER:
  3. caseBINDER_TYPE_WEAK_BINDER:{
  4. structbinder_ref*ref;
  5. structbinder_node*node=binder_get_node(proc,fp->binder);
  6. if(node==NULL){
  7. node=binder_new_node(proc,fp->binder,fp->cookie);
  8. if(node==NULL){
  9. return_error=BR_FAILED_REPLY;
  10. gotoerr_binder_new_node_failed;
  11. }
  12. node->min_priority=fp->flags&FLAT_BINDER_FLAG_PRIORITY_MASK;
  13. node->accept_fds=!!(fp->flags&FLAT_BINDER_FLAG_ACCEPTS_FDS);
  14. }
  15. if(fp->cookie!=node->cookie){
  16. ......
  17. gotoerr_binder_get_ref_for_node_failed;
  18. }
  19. ref=binder_get_ref_for_node(target_proc,node);
  20. if(ref==NULL){
  21. return_error=BR_FAILED_REPLY;
  22. gotoerr_binder_get_ref_for_node_failed;
  23. }
  24. if(fp->type==BINDER_TYPE_BINDER)
  25. fp->type=BINDER_TYPE_HANDLE;
  26. else
  27. fp->type=BINDER_TYPE_WEAK_HANDLE;
  28. fp->handle=ref->desc;
  29. binder_inc_ref(ref,fp->type==BINDER_TYPE_HANDLE,&thread->todo);
  30. ......
  31. }break;
由于是第一次在Binder驱动程序中传输这个MediaPlayerService,调用binder_get_node函数查询这个Binder实体时,会返回空,于是binder_new_node在proc中新建一个,下次就可以直接使用了。

现在,由于要把这个Binder实体MediaPlayerService交给target_proc,也就是Service Manager来管理,也就是说Service Manager要引用这个MediaPlayerService了,于是通过binder_get_ref_for_node为MediaPlayerService创建一个引用,并且通过binder_inc_ref来增加这个引用计数,防止这个引用还在使用过程当中就被销毁。注意,到了这里的时候,t->buffer中的flat_binder_obj的type已经改为BINDER_TYPE_HANDLE,handle已经改为ref->desc,跟原来不一样了,因为这个flat_binder_obj是最终是要传给Service Manager的,而Service Manager只能够通过句柄值来引用这个Binder实体。

最后,把待处理事务加入到target_list列表中去:

[cpp] view plain copy print ?
  1. list_add_tail(&t->work.entry,target_list);
并且把待完成工作项加入到本线程的todo等待执行列表中去:

[cpp] view plain copy print ?
  1. list_add_tail(&tcomplete->entry,&thread->todo);
现在目标进程有事情可做了,于是唤醒它:

[cpp] view plain copy print ?
  1. if(target_wait)
  2. wake_up_interruptible(target_wait);
这里就是要唤醒Service Manager进程了。回忆一下前面 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路这篇文章,此时, Service Manager正在binder_thread_read函数中调用wait_event_interruptible进入休眠状态。

这里我们先忽略一下Service Manager被唤醒之后的场景,继续MedaPlayerService的启动过程,然后再回来。

回到binder_ioctl函数,bwr.read_size > 0为true,于是进入binder_thread_read函数:

[cpp] view plain copy print ?
  1. staticint
  2. binder_thread_read(structbinder_proc*proc,structbinder_thread*thread,
  3. void__user*buffer,intsize,signedlong*consumed,intnon_block)
  4. {
  5. void__user*ptr=buffer+*consumed;
  6. void__user*end=buffer+size;
  7. intret=0;
  8. intwait_for_proc_work;
  9. if(*consumed==0){
  10. if(put_user(BR_NOOP,(uint32_t__user*)ptr))
  11. return-EFAULT;
  12. ptr+=sizeof(uint32_t);
  13. }
  14. retry:
  15. wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);
  16. .......
  17. if(wait_for_proc_work){
  18. .......
  19. }else{
  20. if(non_block){
  21. if(!binder_has_thread_work(thread))
  22. ret=-EAGAIN;
  23. }else
  24. ret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));
  25. }
  26. ......
  27. while(1){
  28. uint32_tcmd;
  29. structbinder_transaction_datatr;
  30. structbinder_work*w;
  31. structbinder_transaction*t=NULL;
  32. if(!list_empty(&thread->todo))
  33. w=list_first_entry(&thread->todo,structbinder_work,entry);
  34. elseif(!list_empty(&proc->todo)&&wait_for_proc_work)
  35. w=list_first_entry(&proc->todo,structbinder_work,entry);
  36. else{
  37. if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/*nodataadded*/
  38. gotoretry;
  39. break;
  40. }
  41. if(end-ptr<sizeof(tr)+4)
  42. break;
  43. switch(w->type){
  44. ......
  45. caseBINDER_WORK_TRANSACTION_COMPLETE:{
  46. cmd=BR_TRANSACTION_COMPLETE;
  47. if(put_user(cmd,(uint32_t__user*)ptr))
  48. return-EFAULT;
  49. ptr+=sizeof(uint32_t);
  50. binder_stat_br(proc,thread,cmd);
  51. if(binder_debug_mask&BINDER_DEBUG_TRANSACTION_COMPLETE)
  52. printk(KERN_INFO"binder:%d:%dBR_TRANSACTION_COMPLETE\n",
  53. proc->pid,thread->pid);
  54. list_del(&w->entry);
  55. kfree(w);
  56. binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++;
  57. }break;
  58. ......
  59. }
  60. if(!t)
  61. continue;
  62. ......
  63. }
  64. done:
  65. ......
  66. return0;
  67. }

这里,thread->transaction_stack和thread->todo均不为空,于是wait_for_proc_work为false,由于binder_has_thread_work的时候,返回true,这里因为thread->todo不为空,因此,线程虽然调用了wait_event_interruptible,但是不会睡眠,于是继续往下执行。

由于thread->todo不为空,执行下列语句:

[cpp] view plain copy print ?
  1. if(!list_empty(&thread->todo))
  2. w=list_first_entry(&thread->todo,structbinder_work,entry);
w->type为BINDER_WORK_TRANSACTION_COMPLETE,这是在上面的binder_transaction函数设置的,于是执行:

[cpp] view plain copy print ?
  1. switch(w->type){
  2. ......
  3. caseBINDER_WORK_TRANSACTION_COMPLETE:{
  4. cmd=BR_TRANSACTION_COMPLETE;
  5. if(put_user(cmd,(uint32_t__user*)ptr))
  6. return-EFAULT;
  7. ptr+=sizeof(uint32_t);
  8. ......
  9. list_del(&w->entry);
  10. kfree(w);
  11. }break;
  12. ......
  13. }
这里就将w从thread->todo删除了。由于这里t为空,重新执行while循环,这时由于已经没有事情可做了,最后就返回到binder_ioctl函数中。注间,这里一共往用户传进来的缓冲区buffer写入了两个整数,分别是BR_NOOP和BR_TRANSACTION_COMPLETE。

binder_ioctl函数返回到用户空间之前,把数据消耗情况拷贝回用户空间中:

[cpp] view plain copy print ?
  1. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  2. ret=-EFAULT;
  3. gotoerr;
  4. }
最后返回到IPCThreadState::talkWithDriver函数中,执行下面语句:

[cpp] view plain copy print ?
  1. if(err>=NO_ERROR){
  2. if(bwr.write_consumed>0){
  3. if(bwr.write_consumed<(ssize_t)mOut.dataSize())
  4. mOut.remove(0,bwr.write_consumed);
  5. else
  6. mOut.setDataSize(0);
  7. }
  8. if(bwr.read_consumed>0){
  9. <PREclass=cppname="code">mIn.setDataSize(bwr.read_consumed);
  10. mIn.setDataPosition(0);</PRE>}......returnNO_ERROR;}

Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

分类: Android 8106人阅读 评论(13) 收藏 举报

在上一篇文章中,我们分析了Android系统进程间通信机制Binder中的Server在启动过程使用Service Manager的addService接口把自己添加到Service Manager守护过程中接受管理。在这一篇文章中,我们将深入到Binder驱动程序源代码去分析Client是如何通过Service Manager的getService接口中来获得Server远程接口的。Client只有获得了Server的远程接口之后,才能进一步调用Server提供的服务。

这里,我们仍然是通过Android系统中自带的多媒体播放器为例子来说明Client是如何通过IServiceManager::getService接口来获得MediaPlayerService这个Server的远程接口的。假设计读者已经阅读过前面三篇文章浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路、浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路和Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析,即假设Service Manager和MediaPlayerService已经启动完毕,Service Manager现在等待Client的请求。

这里,我们要举例子说明的Client便是MediaPlayer了,它声明和实现在frameworks/base/include/media/mediaplayer.h和frameworks/base/media/libmedia/mediaplayer.cpp文件中。MediaPlayer继承于IMediaDeathNotifier类,这个类声明和实现在frameworks/base/include/media/IMediaDeathNotifier.h和frameworks/base/media/libmedia//IMediaDeathNotifier.cpp文件中,里面有一个静态成员函数getMeidaPlayerService,它通过IServiceManager::getService接口来获得MediaPlayerService的远程接口。

在介绍IMediaDeathNotifier::getMeidaPlayerService函数之前,我们先了解一下这个函数的目标。看来前面浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路这篇文章的读者知道,我们在获取Service Manager远程接口时,最终是获得了一个BpServiceManager对象的IServiceManager接口。类似地,我们要获得MediaPlayerService的远程接口,实际上就是要获得一个称为BpMediaPlayerService对象的IMediaPlayerService接口。现在,我们就先来看一下BpMediaPlayerService的类图:

Android进程间通信IPC机制Binder_第5张图片

从这个类图可以看到,BpMediaPlayerService继承于BpInterface<IMediaPlayerService>类,即BpMediaPlayerService继承了IMediaPlayerService类和BpRefBase类,这两个类又分别继续了RefBase类。BpRefBase类有一个成员变量mRemote,它的类型为IBinder,实际是一个BpBinder对象。BpBinder类使用了IPCThreadState类来与Binder驱动程序进行交互,而IPCThreadState类有一个成员变量mProcess,它的类型为ProcessState,IPCThreadState类借助ProcessState类来打开Binder设备文件/dev/binder,因此,它可以和Binder驱动程序进行交互。

BpMediaPlayerService的构造函数有一个参数impl,它的类型为const sp<IBinder>&,从上面的描述中,这个实际上就是一个BpBinder对象。这样,要创建一个BpMediaPlayerService对象,首先就要有一个BpBinder对象。再来看BpBinder类的构造函数,它有一个参数handle,类型为int32_t,这个参数的意义就是请求MediaPlayerService这个远程接口的进程对MediaPlayerService这个Binder实体的引用了。因此,获取MediaPlayerService这个远程接口的本质问题就变为从Service Manager中获得MediaPlayerService的一个句柄了。

现在,我们就来看一下IMediaDeathNotifier::getMeidaPlayerService的实现:

[cpp] view plain copy print ?
  1. //establishbinderinterfacetoMediaPlayerService
  2. /*static*/constsp<IMediaPlayerService>&
  3. IMediaDeathNotifier::getMediaPlayerService()
  4. {
  5. LOGV("getMediaPlayerService");
  6. Mutex::Autolock_l(sServiceLock);
  7. if(sMediaPlayerService.get()==0){
  8. sp<IServiceManager>sm=defaultServiceManager();
  9. sp<IBinder>binder;
  10. do{
  11. binder=sm->getService(String16("media.player"));
  12. if(binder!=0){
  13. break;
  14. }
  15. LOGW("Mediaplayerservicenotpublished,waiting...");
  16. usleep(500000);//0.5s
  17. }while(true);
  18. if(sDeathNotifier==NULL){
  19. sDeathNotifier=newDeathNotifier();
  20. }
  21. binder->linkToDeath(sDeathNotifier);
  22. sMediaPlayerService=interface_cast<IMediaPlayerService>(binder);
  23. }
  24. LOGE_IF(sMediaPlayerService==0,"nomediaplayerservice!?");
  25. returnsMediaPlayerService;
  26. }
函数首先通过defaultServiceManager函数来获得Service Manager的远程接口,实际上就是获得BpServiceManager的IServiceManager接口,具体可以参考 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路一文。总的来说,这里的语句:

[cpp] view plain copy print ?
  1. sp<IServiceManager>sm=defaultServiceManager();
相当于是:

[cpp] view plain copy print ?
  1. sp<IServiceManager>sm=newBpServiceManager(newBpBinder(0));
这里的0表示Service Manager的远程接口的句柄值是0。

接下去的while循环是通过sm->getService接口来不断尝试获得名称为“media.player”的Service,即MediaPlayerService。为什么要通过这无穷循环来得MediaPlayerService呢?因为这时候MediaPlayerService可能还没有启动起来,所以这里如果发现取回来的binder接口为NULL,就睡眠0.5秒,然后再尝试获取,这是获取Service接口的标准做法。
我们来看一下BpServiceManager::getService的实现:

[cpp] view plain copy print ?
  1. classBpServiceManager:publicBpInterface<IServiceManager>
  2. {
  3. ......
  4. virtualsp<IBinder>getService(constString16&name)const
  5. {
  6. unsignedn;
  7. for(n=0;n<5;n++){
  8. sp<IBinder>svc=checkService(name);
  9. if(svc!=NULL)returnsvc;
  10. LOGI("Waitingforservice%s...\n",String8(name).string());
  11. sleep(1);
  12. }
  13. returnNULL;
  14. }
  15. virtualsp<IBinder>checkService(constString16&name)const
  16. {
  17. Parceldata,reply;
  18. data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
  19. data.writeString16(name);
  20. remote()->transact(CHECK_SERVICE_TRANSACTION,data,&reply);
  21. returnreply.readStrongBinder();
  22. }
  23. ......
  24. };
BpServiceManager::getService通过BpServiceManager::checkService执行操作。

在BpServiceManager::checkService中,首先是通过Parcel::writeInterfaceToken往data写入一个RPC头,这个我们在Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文已经介绍过了,就是写往data里面写入了一个整数和一个字符串“android.os.IServiceManager”, Service Manager来处理CHECK_SERVICE_TRANSACTION请求之前,会先验证一下这个RPC头,看看是否正确。接着再往data写入一个字符串name,这里就是“media.player”了。回忆一下Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析这篇文章,那里已经往Service Manager中注册了一个名字为“media.player”的MediaPlayerService。

这里的remote()返回的是一个BpBinder,具体可以参考浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路一文,于是,就进行到BpBinder::transact函数了:

[cpp] view plain copy print ?
  1. status_tBpBinder::transact(
  2. uint32_tcode,constParcel&data,Parcel*reply,uint32_tflags)
  3. {
  4. //Onceabinderhasdied,itwillnevercomebacktolife.
  5. if(mAlive){
  6. status_tstatus=IPCThreadState::self()->transact(
  7. mHandle,code,data,reply,flags);
  8. if(status==DEAD_OBJECT)mAlive=0;
  9. returnstatus;
  10. }
  11. returnDEAD_OBJECT;
  12. }

这里的mHandle = 0,code =CHECK_SERVICE_TRANSACTION,flags = 0。

这里再进入到IPCThread::transact函数中:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::transact(int32_thandle,
  2. uint32_tcode,constParcel&data,
  3. Parcel*reply,uint32_tflags)
  4. {
  5. status_terr=data.errorCheck();
  6. flags|=TF_ACCEPT_FDS;
  7. IF_LOG_TRANSACTIONS(){
  8. TextOutput::Bundle_b(alog);
  9. alog<<"BC_TRANSACTIONthr"<<(void*)pthread_self()<<"/hand"
  10. <<handle<<"/code"<<TypeCode(code)<<":"
  11. <<indent<<data<<dedent<<endl;
  12. }
  13. if(err==NO_ERROR){
  14. LOG_ONEWAY(">>>>SENDfrompid%duid%d%s",getpid(),getuid(),
  15. (flags&TF_ONE_WAY)==0?"READREPLY":"ONEWAY");
  16. err=writeTransactionData(BC_TRANSACTION,flags,handle,code,data,NULL);
  17. }
  18. if(err!=NO_ERROR){
  19. if(reply)reply->setError(err);
  20. return(mLastError=err);
  21. }
  22. if((flags&TF_ONE_WAY)==0){
  23. #if0
  24. if(code==4){//relayout
  25. LOGI(">>>>>>CALLINGtransaction4");
  26. }else{
  27. LOGI(">>>>>>CALLINGtransaction%d",code);
  28. }
  29. #endif
  30. if(reply){
  31. err=waitForResponse(reply);
  32. }else{
  33. ParcelfakeReply;
  34. err=waitForResponse(&fakeReply);
  35. }
  36. #if0
  37. if(code==4){//relayout
  38. LOGI("<<<<<<RETURNINGtransaction4");
  39. }else{
  40. LOGI("<<<<<<RETURNINGtransaction%d",code);
  41. }
  42. #endif
  43. IF_LOG_TRANSACTIONS(){
  44. TextOutput::Bundle_b(alog);
  45. alog<<"BR_REPLYthr"<<(void*)pthread_self()<<"/hand"
  46. <<handle<<":";
  47. if(reply)alog<<indent<<*reply<<dedent<<endl;
  48. elsealog<<"(nonerequested)"<<endl;
  49. }
  50. }else{
  51. err=waitForResponse(NULL,NULL);
  52. }
  53. returnerr;
  54. }
首先是调用函数writeTransactionData写入将要传输的数据到IPCThreadState的成员变量mOut中去:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::writeTransactionData(int32_tcmd,uint32_tbinderFlags,
  2. int32_thandle,uint32_tcode,constParcel&data,status_t*statusBuffer)
  3. {
  4. binder_transaction_datatr;
  5. tr.target.handle=handle;
  6. tr.code=code;
  7. tr.flags=binderFlags;
  8. conststatus_terr=data.errorCheck();
  9. if(err==NO_ERROR){
  10. tr.data_size=data.ipcDataSize();
  11. tr.data.ptr.buffer=data.ipcData();
  12. tr.offsets_size=data.ipcObjectsCount()*sizeof(size_t);
  13. tr.data.ptr.offsets=data.ipcObjects();
  14. }elseif(statusBuffer){
  15. tr.flags|=TF_STATUS_CODE;
  16. *statusBuffer=err;
  17. tr.data_size=sizeof(status_t);
  18. tr.data.ptr.buffer=statusBuffer;
  19. tr.offsets_size=0;
  20. tr.data.ptr.offsets=NULL;
  21. }else{
  22. return(mLastError=err);
  23. }
  24. mOut.writeInt32(cmd);
  25. mOut.write(&tr,sizeof(tr));
  26. returnNO_ERROR;
  27. }
结构体binder_transaction_data在上一篇文章 Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析已经介绍过,这里不再累述,这个结构体是用来描述要传输的参数的内容的。这里着重描述一下将要传输的参数tr里面的内容,handle = 0,code =CHECK_SERVICE_TRANSACTION,cmd =BC_TRANSACTION,data里面的数据分别为:

[cpp] view plain copy print ?
  1. writeInt32(IPCThreadState::self()->getStrictModePolicy()|STRICT_MODE_PENALTY_GATHER);
  2. writeString16("android.os.IServiceManager");
  3. writeString16("media.player");
这是在BpServiceManager::checkService函数里面写进去的,其中前两个是RPC头,Service Manager在收到这个请求时会验证这两个参数是否正确,这点前面也提到了。IPCThread->getStrictModePolicy默认返回0,STRICT_MODE_PENALTY_GATHER定义为:

[cpp] view plain copy print ?
  1. //Note:mustbekeptinsyncwithandroid/os/StrictMode.java'sPENALTY_GATHER
  2. #defineSTRICT_MODE_PENALTY_GATHER0x100
我们不关心这个参数的含义,这不会影响我们分析下面的源代码,有兴趣的读者可以研究一下。这里要注意的是,要传输的参数不包含有Binder对象,因此tr.offsets_size = 0。要传输的参数最后写入到IPCThreadState的成员变量mOut中,包括cmd和tr两个数据。

回到IPCThread::transact函数中,由于(flags & TF_ONE_WAY) == 0为true,即这是一个同步请求,并且reply != NULL,最终调用:

[cpp] view plain copy print ?
  1. err=waitForResponse(reply);
进入到waitForResponse函数中:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::waitForResponse(Parcel*reply,status_t*acquireResult)
  2. {
  3. int32_tcmd;
  4. int32_terr;
  5. while(1){
  6. if((err=talkWithDriver())<NO_ERROR)break;
  7. err=mIn.errorCheck();
  8. if(err<NO_ERROR)break;
  9. if(mIn.dataAvail()==0)continue;
  10. cmd=mIn.readInt32();
  11. IF_LOG_COMMANDS(){
  12. alog<<"ProcessingwaitForResponseCommand:"
  13. <<getReturnString(cmd)<<endl;
  14. }
  15. switch(cmd){
  16. caseBR_TRANSACTION_COMPLETE:
  17. if(!reply&&!acquireResult)gotofinish;
  18. break;
  19. caseBR_DEAD_REPLY:
  20. err=DEAD_OBJECT;
  21. gotofinish;
  22. caseBR_FAILED_REPLY:
  23. err=FAILED_TRANSACTION;
  24. gotofinish;
  25. caseBR_ACQUIRE_RESULT:
  26. {
  27. LOG_ASSERT(acquireResult!=NULL,"UnexpectedbrACQUIRE_RESULT");
  28. constint32_tresult=mIn.readInt32();
  29. if(!acquireResult)continue;
  30. *acquireResult=result?NO_ERROR:INVALID_OPERATION;
  31. }
  32. gotofinish;
  33. caseBR_REPLY:
  34. {
  35. binder_transaction_datatr;
  36. err=mIn.read(&tr,sizeof(tr));
  37. LOG_ASSERT(err==NO_ERROR,"NotenoughcommanddataforbrREPLY");
  38. if(err!=NO_ERROR)gotofinish;
  39. if(reply){
  40. if((tr.flags&TF_STATUS_CODE)==0){
  41. reply->ipcSetDataReference(
  42. reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),
  43. tr.data_size,
  44. reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),
  45. tr.offsets_size/sizeof(size_t),
  46. freeBuffer,this);
  47. }else{
  48. err=*static_cast<conststatus_t*>(tr.data.ptr.buffer);
  49. freeBuffer(NULL,
  50. reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),
  51. tr.data_size,
  52. reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),
  53. tr.offsets_size/sizeof(size_t),this);
  54. }
  55. }else{
  56. freeBuffer(NULL,
  57. reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),
  58. tr.data_size,
  59. reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),
  60. tr.offsets_size/sizeof(size_t),this);
  61. continue;
  62. }
  63. }
  64. gotofinish;
  65. default:
  66. err=executeCommand(cmd);
  67. if(err!=NO_ERROR)gotofinish;
  68. break;
  69. }
  70. }
  71. finish:
  72. if(err!=NO_ERROR){
  73. if(acquireResult)*acquireResult=err;
  74. if(reply)reply->setError(err);
  75. mLastError=err;
  76. }
  77. returnerr;
  78. }
这个函数通过IPCThreadState::talkWithDriver与驱动程序进行交互:

[cpp] view plain copy print ?
  1. status_tIPCThreadState::talkWithDriver(booldoReceive)
  2. {
  3. LOG_ASSERT(mProcess->mDriverFD>=0,"Binderdriverisnotopened");
  4. binder_write_readbwr;
  5. //Isthereadbufferempty?
  6. constboolneedRead=mIn.dataPosition()>=mIn.dataSize();
  7. //Wedon'twanttowriteanythingifwearestillreading
  8. //fromdataleftintheinputbufferandthecaller
  9. //hasrequestedtoreadthenextdata.
  10. constsize_toutAvail=(!doReceive||needRead)?mOut.dataSize():0;
  11. bwr.write_size=outAvail;
  12. bwr.write_buffer=(longunsignedint)mOut.data();
  13. //Thisiswhatwe'llread.
  14. if(doReceive&&needRead){
  15. bwr.read_size=mIn.dataCapacity();
  16. bwr.read_buffer=(longunsignedint)mIn.data();
  17. }else{
  18. bwr.read_size=0;
  19. }
  20. ......
  21. //Returnimmediatelyifthereisnothingtodo.
  22. if((bwr.write_size==0)&&(bwr.read_size==0))returnNO_ERROR;
  23. bwr.write_consumed=0;
  24. bwr.read_consumed=0;
  25. status_terr;
  26. do{
  27. ......
  28. #ifdefined(HAVE_ANDROID_OS)
  29. if(ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr)>=0)
  30. err=NO_ERROR;
  31. else
  32. err=-errno;
  33. #else
  34. err=INVALID_OPERATION;
  35. #endif
  36. ......
  37. }while(err==-EINTR);
  38. ......
  39. if(err>=NO_ERROR){
  40. if(bwr.write_consumed>0){
  41. if(bwr.write_consumed<(ssize_t)mOut.dataSize())
  42. mOut.remove(0,bwr.write_consumed);
  43. else
  44. mOut.setDataSize(0);
  45. }
  46. if(bwr.read_consumed>0){
  47. mIn.setDataSize(bwr.read_consumed);
  48. mIn.setDataPosition(0);
  49. }
  50. ......
  51. returnNO_ERROR;
  52. }
  53. returnerr;
  54. }
这里的needRead为true,因此,bwr.read_size大于0;outAvail也大于0,因此,bwr.write_size也大于0。函数最后通过:

[cpp] view plain copy print ?
  1. ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr)
进入到Binder驱动程序的binder_ioctl函数中。注意,这里的mProcess->mDriverFD是在我们前面调用defaultServiceManager函数获得Service Manager远程接口时,打开的设备文件/dev/binder的文件描述符,mProcess是IPCSThreadState的成员变量。

Binder驱动程序的binder_ioctl函数中,我们只关注BINDER_WRITE_READ命令相关的逻辑:

[cpp] view plain copy print ?
  1. staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg)
  2. {
  3. intret;
  4. structbinder_proc*proc=filp->private_data;
  5. structbinder_thread*thread;
  6. unsignedintsize=_IOC_SIZE(cmd);
  7. void__user*ubuf=(void__user*)arg;
  8. /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/
  9. ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2);
  10. if(ret)
  11. returnret;
  12. mutex_lock(&binder_lock);
  13. thread=binder_get_thread(proc);
  14. if(thread==NULL){
  15. ret=-ENOMEM;
  16. gotoerr;
  17. }
  18. switch(cmd){
  19. caseBINDER_WRITE_READ:{
  20. structbinder_write_readbwr;
  21. if(size!=sizeof(structbinder_write_read)){
  22. ret=-EINVAL;
  23. gotoerr;
  24. }
  25. if(copy_from_user(&bwr,ubuf,sizeof(bwr))){
  26. ret=-EFAULT;
  27. gotoerr;
  28. }
  29. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  30. printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n",
  31. proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer);
  32. if(bwr.write_size>0){
  33. ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
  34. if(ret<0){
  35. bwr.read_consumed=0;
  36. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  37. ret=-EFAULT;
  38. gotoerr;
  39. }
  40. }
  41. if(bwr.read_size>0){
  42. ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK);
  43. if(!list_empty(&proc->todo))
  44. wake_up_interruptible(&proc->wait);
  45. if(ret<0){
  46. if(copy_to_user(ubuf,&bwr,sizeof(bwr)))
  47. ret=-EFAULT;
  48. gotoerr;
  49. }
  50. }
  51. if(binder_debug_mask&BINDER_DEBUG_READ_WRITE)
  52. printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n",
  53. proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size);
  54. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  55. ret=-EFAULT;
  56. gotoerr;
  57. }
  58. break;
  59. }
  60. ......
  61. default:
  62. ret=-EINVAL;
  63. gotoerr;
  64. }
  65. ret=0;
  66. err:
  67. ......
  68. returnret;
  69. }
这里的filp->private_data的值是在defaultServiceManager函数创建ProcessState对象时,在ProcessState构造函数通过open文件操作函数打开设备文件/dev/binder时设置好的,它表示的是调用open函数打开设备文件/dev/binder的进程上下文信息,这里将它取出来保存在proc本地变量中。

这里的thread本地变量表示当前线程上下文信息,通过binder_get_thread函数获得。在前面执行ProcessState构造函数时,也会通过ioctl文件操作函数进入到这个函数,那是第一次进入到binder_ioctl这里,因此,调用binder_get_thread时,表示当前进程上下文信息的proc变量还没有关于当前线程的上下文信息,因此,会为proc创建一个表示当前线程上下文信息的thread,会保存在proc->threads表示的红黑树结构中。这里调用binder_get_thread就可以直接从proc找到并返回了。

进入到BINDER_WRITE_READ相关的逻辑。先看看BINDER_WRITE_READ的定义:

[cpp] view plain copy print ?
  1. #defineBINDER_WRITE_READ_IOWR('b',1,structbinder_write_read)
这里可以看出,BINDER_WRITE_READ命令的参数类型为struct binder_write_read:

[cpp] view plain copy print ?
  1. structbinder_write_read{
  2. signedlongwrite_size;/*bytestowrite*/
  3. signedlongwrite_consumed;/*bytesconsumedbydriver*/
  4. unsignedlongwrite_buffer;
  5. signedlongread_size;/*bytestoread*/
  6. signedlongread_consumed;/*bytesconsumedbydriver*/
  7. unsignedlongread_buffer;
  8. };
这个结构体的含义可以参考 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文。这里首先是通过copy_from_user函数把用户传进来的参数的内容拷贝到本地变量bwr中。
从上面的调用过程,我们知道,这里bwr.write_size是大于0的,因此进入到binder_thread_write函数中,我们只关注BC_TRANSACTION相关的逻辑:

[cpp] view plain copy print ?
  1. int
  2. binder_thread_write(structbinder_proc*proc,structbinder_thread*thread,
  3. void__user*buffer,intsize,signedlong*consumed)
  4. {
  5. uint32_tcmd;
  6. void__user*ptr=buffer+*consumed;
  7. void__user*end=buffer+size;
  8. while(ptr<end&&thread->return_error==BR_OK){
  9. if(get_user(cmd,(uint32_t__user*)ptr))
  10. return-EFAULT;
  11. ptr+=sizeof(uint32_t);
  12. if(_IOC_NR(cmd)<ARRAY_SIZE(binder_stats.bc)){
  13. binder_stats.bc[_IOC_NR(cmd)]++;
  14. proc->stats.bc[_IOC_NR(cmd)]++;
  15. thread->stats.bc[_IOC_NR(cmd)]++;
  16. }
  17. switch(cmd){
  18. ......
  19. caseBC_TRANSACTION:
  20. caseBC_REPLY:{
  21. structbinder_transaction_datatr;
  22. if(copy_from_user(&tr,ptr,sizeof(tr)))
  23. return-EFAULT;
  24. ptr+=sizeof(tr);
  25. binder_transaction(proc,thread,&tr,cmd==BC_REPLY);
  26. break;
  27. }
  28. ......
  29. default:
  30. printk(KERN_ERR"binder:%d:%dunknowncommand%d\n",proc->pid,thread->pid,cmd);
  31. return-EINVAL;
  32. }
  33. *consumed=ptr-buffer;
  34. }
  35. return0;
  36. }
这里再次把用户传出来的参数拷贝到本地变量tr中,tr的类型为struct binder_transaction_data,这个就是前面我们在IPCThreadState::writeTransactionData写入的内容了。

接着进入到binder_transaction函数中,不相关的代码我们忽略掉:

[cpp] view plain copy print ?
  1. staticvoid
  2. binder_transaction(structbinder_proc*proc,structbinder_thread*thread,
  3. structbinder_transaction_data*tr,intreply)
  4. {
  5. structbinder_transaction*t;
  6. structbinder_work*tcomplete;
  7. size_t*offp,*off_end;
  8. structbinder_proc*target_proc;
  9. structbinder_thread*target_thread=NULL;
  10. structbinder_node*target_node=NULL;
  11. structlist_head*target_list;
  12. wait_queue_head_t*target_wait;
  13. structbinder_transaction*in_reply_to=NULL;
  14. structbinder_transaction_log_entry*e;
  15. uint32_treturn_error;
  16. .......
  17. if(reply){
  18. ......
  19. }else{
  20. if(tr->target.handle){
  21. ......
  22. }else{
  23. target_node=binder_context_mgr_node;
  24. if(target_node==NULL){
  25. return_error=BR_DEAD_REPLY;
  26. gotoerr_no_context_mgr_node;
  27. }
  28. }
  29. ......
  30. target_proc=target_node->proc;
  31. if(target_proc==NULL){
  32. return_error=BR_DEAD_REPLY;
  33. gotoerr_dead_binder;
  34. }
  35. if(!(tr->flags&TF_ONE_WAY)&&thread->transaction_stack){
  36. ......
  37. }
  38. }
  39. if(target_thread){
  40. ......
  41. }else{
  42. target_list=&target_proc->todo;
  43. target_wait=&target_proc->wait;
  44. }
  45. ......
  46. /*TODO:reuseincomingtransactionforreply*/
  47. t=kzalloc(sizeof(*t),GFP_KERNEL);
  48. if(t==NULL){
  49. return_error=BR_FAILED_REPLY;
  50. gotoerr_alloc_t_failed;
  51. }
  52. binder_stats.obj_created[BINDER_STAT_TRANSACTION]++;
  53. tcomplete=kzalloc(sizeof(*tcomplete),GFP_KERNEL);
  54. if(tcomplete==NULL){
  55. return_error=BR_FAILED_REPLY;
  56. gotoerr_alloc_tcomplete_failed;
  57. }
  58. binder_stats.obj_created[BINDER_STAT_TRANSACTION_COMPLETE]++;
  59. t->debug_id=++binder_last_id;
  60. ......
  61. if(!reply&&!(tr->flags&TF_ONE_WAY))
  62. t->from=thread;
  63. else
  64. t->from=NULL;
  65. t->sender_euid=proc->tsk->cred->euid;
  66. t->to_proc=target_proc;
  67. t->to_thread=target_thread;
  68. t->code=tr->code;
  69. t->flags=tr->flags;
  70. t->priority=task_nice(current);
  71. t->buffer=binder_alloc_buf(target_proc,tr->data_size,
  72. tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY));
  73. if(t->buffer==NULL){
  74. return_error=BR_FAILED_REPLY;
  75. gotoerr_binder_alloc_buf_failed;
  76. }
  77. t->buffer->allow_user_free=0;
  78. t->buffer->debug_id=t->debug_id;
  79. t->buffer->transaction=t;
  80. t->buffer->target_node=target_node;
  81. if(target_node)
  82. binder_inc_node(target_node,1,0,NULL);
  83. offp=(size_t*)(t->buffer->data+ALIGN(tr->data_size,sizeof(void*)));
  84. if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){
  85. ......
  86. return_error=BR_FAILED_REPLY;
  87. gotoerr_copy_data_failed;
  88. }
  89. ......
  90. if(reply){
  91. ......
  92. }elseif(!(t->flags&TF_ONE_WAY)){
  93. BUG_ON(t->buffer->async_transaction!=0);
  94. t->need_reply=1;
  95. t->from_parent=thread->transaction_stack;
  96. thread->transaction_stack=t;
  97. }else{
  98. ......
  99. }
  100. t->work.type=BINDER_WORK_TRANSACTION;
  101. list_add_tail(&t->work.entry,target_list);
  102. tcomplete->type=BINDER_WORK_TRANSACTION_COMPLETE;
  103. list_add_tail(&tcomplete->entry,&thread->todo);
  104. if(target_wait)
  105. wake_up_interruptible(target_wait);
  106. return;
  107. ......
  108. }
注意,这里的参数reply = 0,表示这是一个BC_TRANSACTION命令。
前面我们提到,传给驱动程序的handle值为0,即这里的tr->target.handle = 0,表示请求的目标Binder对象是Service Manager,因此有:

[cpp] view plain copy print ?
  1. target_node=binder_context_mgr_node;
  2. target_proc=target_node->proc;
  3. target_list=&target_proc->todo;
  4. target_wait=&target_proc->wait;

其中binder_context_mgr_node是在Service Manager通知Binder驱动程序它是守护过程时创建的。

接着创建一个待完成事项tcomplete,它的类型为struct binder_work,这是等一会要保存在当前线程的todo队列去的,表示当前线程有一个待完成的事务。紧跟着创建一个待处理事务t,它的类型为struct binder_transaction,这是等一会要存在到Service Manager的todo队列去的,表示Service Manager当前有一个事务需要处理。同时,这个待处理事务t也要存放在当前线程的待完成事务transaction_stack列表中去:

[cpp] view plain copy print ?
  1. t->from_parent=thread->transaction_stack;
  2. thread->transaction_stack=t;
这样表明当前线程还有事务要处理。

继续往下看,就是分别把tcomplete和t放在当前线程thread和Service Manager进程的todo队列去了:

[cpp] view plain copy print ?
  1. t->work.type=BINDER_WORK_TRANSACTION;
  2. list_add_tail(&t->work.entry,target_list);
  3. tcomplete->type=BINDER_WORK_TRANSACTION_COMPLETE;
  4. list_add_tail(&tcomplete->entry,&thread->todo);
最后,Service Manager有事情可做了,就要唤醒它了:

[cpp] view plain copy print ?
  1. wake_up_interruptible(target_wait);
前面我们提到,此时Service Manager正在等待Client的请求,也就是Service Manager此时正在进入到Binder驱动程序的binder_thread_read函数中,并且休眠在target->wait上,具体参考 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文。
这里,我们暂时忽略Service Manager被唤醒之后的情景,继续看当前线程的执行。
函数binder_transaction执行完成之后,就一路返回到binder_ioctl函数里去了。函数binder_ioctl从binder_thread_write函数调用处返回后,发现bwr.read_size大于0,于是就进入到binder_thread_read函数去了:

[cpp] view plain copy print ?
  1. staticint
  2. binder_thread_read(structbinder_proc*proc,structbinder_thread*thread,
  3. void__user*buffer,intsize,signedlong*consumed,intnon_block)
  4. {
  5. void__user*ptr=buffer+*consumed;
  6. void__user*end=buffer+size;
  7. intret=0;
  8. intwait_for_proc_work;
  9. if(*consumed==0){
  10. if(put_user(BR_NOOP,(uint32_t__user*)ptr))
  11. return-EFAULT;
  12. ptr+=sizeof(uint32_t);
  13. }
  14. retry:
  15. wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);
  16. ......
  17. if(wait_for_proc_work){
  18. ......
  19. }else{
  20. if(non_block){
  21. if(!binder_has_thread_work(thread))
  22. ret=-EAGAIN;
  23. }else
  24. ret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));
  25. }
  26. ......
  27. while(1){
  28. uint32_tcmd;
  29. structbinder_transaction_datatr;
  30. structbinder_work*w;
  31. structbinder_transaction*t=NULL;
  32. if(!list_empty(&thread->todo))
  33. w=list_first_entry(&thread->todo,structbinder_work,entry);
  34. elseif(!list_empty(&proc->todo)&&wait_for_proc_work)
  35. w=list_first_entry(&proc->todo,structbinder_work,entry);
  36. else{
  37. if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/*nodataadded*/
  38. gotoretry;
  39. break;
  40. }
  41. if(end-ptr<sizeof(tr)+4)
  42. break;
  43. switch(w->type){
  44. ......
  45. caseBINDER_WORK_TRANSACTION_COMPLETE:{
  46. cmd=BR_TRANSACTION_COMPLETE;
  47. if(put_user(cmd,(uint32_t__user*)ptr))
  48. return-EFAULT;
  49. ptr+=sizeof(uint32_t);
  50. binder_stat_br(proc,thread,cmd);
  51. if(binder_debug_mask&BINDER_DEBUG_TRANSACTION_COMPLETE)
  52. printk(KERN_INFO"binder:%d:%dBR_TRANSACTION_COMPLETE\n",
  53. proc->pid,thread->pid);
  54. list_del(&w->entry);
  55. kfree(w);
  56. binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++;
  57. }break;
  58. ......
  59. }
  60. if(!t)
  61. continue;
  62. ......
  63. }
  64. done:
  65. ......
  66. return0;
  67. }
函数首先是写入一个操作码BR_NOOP到用户传进来的缓冲区中去。

回忆一下上面的binder_transaction函数,这里的thread->transaction_stack != NULL,并且thread->todo也不为空,所以线程不会进入休眠状态。

进入while循环中,首先是从thread->todo队列中取回待处理事项w,w的类型为BINDER_WORK_TRANSACTION_COMPLETE,这也是在binder_transaction函数里面设置的。对BINDER_WORK_TRANSACTION_COMPLETE的处理也很简单,只是把一个操作码BR_TRANSACTION_COMPLETE写回到用户传进来的缓冲区中去。这时候,用户传进来的缓冲区就包含两个操作码了,分别是BR_NOOP和BINDER_WORK_TRANSACTION_COMPLETE。

binder_thread_read执行完之后,返回到binder_ioctl函数中,将操作结果写回到用户空间中去:

[cpp] view plain copy print ?
  1. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  2. ret=-EFAULT;
  3. gotoerr;
  4. }
最后就返回到IPCThreadState::talkWithDriver函数中了。

IPCThreadState::talkWithDriver函数从下面语句:

[cpp] view plain copy print ?
  1. ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr)
返回后,首先是清空之前写入Binder驱动程序的内容:

[cpp] view plain copy print ?
  1. if(bwr.write_consumed>0){
  2. if(bwr.write_consumed<(ssize_t)mOut.dataSize())
  3. mOut.remove(0,bwr.write_consumed);
  4. else
  5. mOut.setDataSize(0);
  6. }
接着是设置从Binder驱动程序读取的内容:

[cpp] view plain copy print ?
  1. if(bwr.read_consumed>0){
  2. mIn.setDataSize(bwr.read_consumed);
  3. mIn.setDataPosition(0);
  4. }
然后就返回到IPCThreadState::waitForResponse去了。IPCThreadState::waitForResponse函数的处理也很简单,就是处理刚才从Binder驱动程序读入内容了。从前面的分析中,我们知道,从Binder驱动程序读入的内容就是两个整数了,分别是BR_NOOP和BR_TRANSACTION_COMPLETE。对BR_NOOP的处理很简单,正如它的名字所示,什么也不做;而对BR_TRANSACTION_COMPLETE的处理,就分情况了,如果这个请求是异步的,那个整个BC_TRANSACTION操作就完成了,如果这个请求是同步的,即要等待回复的,也就是reply不为空,那么还要继续通过IPCThreadState::talkWithDriver进入到Binder驱动程序中去等待BC_TRANSACTION操作的处理结果。

这里属于后一种情况,于是再次通过IPCThreadState::talkWithDriver进入到Binder驱动程序的binder_ioctl函数中。不过这一次在binder_ioctl函数中,bwr.write_size等于0,而bwr.read_size大于0,于是再次进入到binder_thread_read函数中。这时候thread->transaction_stack仍然不为NULL,不过thread->todo队列已经为空了,因为前面我们已经处理过thread->todo队列的内容了,于是就通过下面语句:

[cpp] view plain copy print ?
  1. ret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));
进入休眠状态了,等待Service Manager的唤醒。

现在,我们终于可以回到Service Manager被唤醒之后的过程了。前面我们说过,Service Manager此时正在binder_thread_read函数中休眠中:

[cpp] view plain copy print ?
  1. staticint
  2. binder_thread_read(structbinder_proc*proc,structbinder_thread*thread,
  3. void__user*buffer,intsize,signedlong*consumed,intnon_block)
  4. {
  5. void__user*ptr=buffer+*consumed;
  6. void__user*end=buffer+size;
  7. intret=0;
  8. intwait_for_proc_work;
  9. if(*consumed==0){
  10. if(put_user(BR_NOOP,(uint32_t__user*)ptr))
  11. return-EFAULT;
  12. ptr+=sizeof(uint32_t);
  13. }
  14. retry:
  15. wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);
  16. ......
  17. if(wait_for_proc_work){
  18. ......
  19. if(non_block){
  20. if(!binder_has_proc_work(proc,thread))
  21. ret=-EAGAIN;
  22. }else
  23. ret=wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc,thread));
  24. }else{
  25. ......
  26. }
  27. ......
  28. while(1){
  29. uint32_tcmd;
  30. structbinder_transaction_datatr;
  31. structbinder_work*w;
  32. structbinder_transaction*t=NULL;
  33. if(!list_empty(&thread->todo))
  34. w=list_first_entry(&thread->todo,structbinder_work,entry);
  35. elseif(!list_empty(&proc->todo)&&wait_for_proc_work)
  36. w=list_first_entry(&proc->todo,structbinder_work,entry);
  37. else{
  38. if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/*nodataadded*/
  39. gotoretry;
  40. break;
  41. }
  42. if(end-ptr<sizeof(tr)+4)
  43. break;
  44. switch(w->type){
  45. caseBINDER_WORK_TRANSACTION:{
  46. t=container_of(w,structbinder_transaction,work);
  47. }break;
  48. ......
  49. }
  50. if(!t)
  51. continue;
  52. BUG_ON(t->buffer==NULL);
  53. if(t->buffer->target_node){
  54. structbinder_node*target_node=t->buffer->target_node;
  55. tr.target.ptr=target_node->ptr;
  56. tr.cookie=target_node->cookie;
  57. t->saved_priority=task_nice(current);
  58. if(t->priority<target_node->min_priority&&
  59. !(t->flags&TF_ONE_WAY))
  60. binder_set_nice(t->priority);
  61. elseif(!(t->flags&TF_ONE_WAY)||
  62. t->saved_priority>target_node->min_priority)
  63. binder_set_nice(target_node->min_priority);
  64. cmd=BR_TRANSACTION;
  65. }else{
  66. ......
  67. }
  68. tr.code=t->code;
  69. tr.flags=t->flags;
  70. tr.sender_euid=t->sender_euid;
  71. if(t->from){
  72. structtask_struct*sender=t->from->proc->tsk;
  73. tr.sender_pid=task_tgid_nr_ns(sender,current->nsproxy->pid_ns);
  74. }else{
  75. ......
  76. }
  77. tr.data_size=t->buffer->data_size;
  78. tr.offsets_size=t->buffer->offsets_size;
  79. tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset;
  80. tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*));
  81. if(put_user(cmd,(uint32_t__user*)ptr))
  82. return-EFAULT;
  83. ptr+=sizeof(uint32_t);
  84. if(copy_to_user(ptr,&tr,sizeof(tr)))
  85. return-EFAULT;
  86. ptr+=sizeof(tr);
  87. ......
  88. list_del(&t->work.entry);
  89. t->buffer->allow_user_free=1;
  90. if(cmd==BR_TRANSACTION&&!(t->flags&TF_ONE_WAY)){
  91. t->to_parent=thread->transaction_stack;
  92. t->to_thread=thread;
  93. thread->transaction_stack=t;
  94. }else{
  95. ......
  96. }
  97. break;
  98. }
  99. done:
  100. *consumed=ptr-buffer;
  101. ......
  102. return0;
  103. }
这里就是从语句中唤醒了:

[cpp] view plain copy print ?
  1. ret=wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc,thread));
Service Manager唤醒过来看,继续往下执行,进入到while循环中。首先是从proc->todo中取回待处理事项w。这个事项w的类型是BINDER_WORK_TRANSACTION,这是上面调用binder_transaction的时候设置的,于是通过w得到待处理事务t:

[cpp] view plain copy print ?
  1. t=container_of(w,structbinder_transaction,work);
接下来的内容,就把cmd和t->buffer的内容拷贝到用户传进来的缓冲区去了,这里就是Service Manager从用户空间传进来的缓冲区了:

[cpp] view plain copy print ?
  1. if(put_user(cmd,(uint32_t__user*)ptr))
  2. return-EFAULT;
  3. ptr+=sizeof(uint32_t);
  4. if(copy_to_user(ptr,&tr,sizeof(tr)))
  5. return-EFAULT;
  6. ptr+=sizeof(tr);
注意,这里先是把t->buffer的内容拷贝到本地变量tr中,再拷贝到用户空间缓冲区去。关于t->buffer内容的拷贝,请参考 Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文,它的一个关键地方是Binder驱动程序和Service Manager守护进程共享了同一个物理内存的内容,拷贝的只是这个物理内存在用户空间的虚拟地址回去:

[cpp] view plain copy print ?
  1. tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset;
  2. tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*));
对于Binder驱动程序这次操作来说,这个事项就算是处理完了,就要从todo队列中删除了:

[cpp] view plain copy print ?
  1. list_del(&t->work.entry);
紧接着,还不放删除这个事务,因为它还要等待Service Manager处理完成后,再进一步处理,因此,放在thread->transaction_stack队列中:

[cpp] view plain copy print ?
  1. t->to_parent=thread->transaction_stack;
  2. t->to_thread=thread;
  3. thread->transaction_stack=t;
还要注意的一个地方是,上面写入的cmd =BR_TRANSACTION,告诉Service Manager守护进程,它要做什么事情,后面我们会看到相应的分析。

这样,binder_thread_read函数就处理完了,回到binder_ioctl函数中,同样是操作结果写回到用户空间的缓冲区中去:

[cpp] view plain copy print ?
  1. if(copy_to_user(ubuf,&bwr,sizeof(bwr))){
  2. ret=-EFAULT;
  3. gotoerr;
  4. }
最后,就返回到frameworks/base/cmds/servicemanager/binder.c文件中的binder_loop函数去了:

更多相关文章

  1. Android应用中通过AIDL机制实现进程间的通讯实例
  2. Android studio 下的aidl编程实现Android的夸进程间通信
  3. Android多线程系统概述(sundy深入浅出)之进程和线程
  4. Android 驱动之旅: 第二章 -- 在Android 系统中增加C 可执行程序
  5. android进程间通讯(3)--使用socket
  6. Android进程说明
  7. Android(IPC)进程间通讯1:详解Binder由来?
  8. Android性能:内存篇之进程内存管理
  9. FirefoxOS 系统进程初步分析 底层系统继承自 android

随机推荐

  1. Android(安卓)天气预报(使用okHttp、Async
  2. Android(安卓)Notification 显示后消失
  3. Android(安卓)ContentProvider和getConte
  4. Android(安卓)多点触控初步学习
  5. Android(安卓)修改开机画面
  6. 单独编译Android(安卓)app模块
  7. Could not resolve all files for config
  8. android中设置Animation 动画效果
  9. Android(安卓)Phone 类的详细 分析 各个
  10. Android(安卓)Studio阶段性学习总结_1