本篇文章是参照老罗的Blog整理而来。
Android应用程序是由Activity、Service、Broadcast Receiver和Content Provider四种类型的组件构成的,它们有可能运行在同一进程中,也有可能运行在不同的进程中。Android系统开发了一套新的进程间通信机制——Binder,方便那些运行在不同进程中的应用程序组件和系统组件进行通信。
Binder进程间通信机制采用了CS通信方式,其中,提供服务的进程称为Server进程,而访问服务的进程称为Client进程。Binder进程间通信机制主要涉及了Client、Service、Service Manager和Binder驱动程序四个角色。
从上图中,可以得到如下信息:
1、Client、Server、Service Manager实现在用户空间,Binder驱动程序实现在内核空间中。
2、Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server。
3、Binder驱动程序提供设备文件 /dev/binder与用户空间交互,Client、Server和Service Manager通过系统调用open、mmap和ioctl来访问设备文件 /dev/binder。
4、Client和Server之间的进程间通信通过Binder驱动程序间接实现。
5、Service Manager是一个守护进程,用来管理server、并向Client提供查询Server接口的功能。
为了加深对Binder进程间通信机制的理解,分析了Binder进程间通信机制的四个使用场景,分别是:
1、Service Manager的启动过程。
2、Service Manager代理对象的获取过程。
3、Service组件的启动过程。
4、Service代理对象的获取过程。
Service Manager的启动过程
Service Manager是Binder进程间通信机制的核心组件之一,它扮演者Binder进程间通信机制上下文管理者的角色,同时负责管理系统中的Service组件,并且向Client组件提供获取Service代理对象的服务。
Service Manager是由init进程负责启动的,而init进程是在系统启动时启动的,因此,Service Manager也是在系统启动时启动的。
----Service Manager源代码目录结构
----Service_manager.c (frameworks\native\cmds\servicemanager)
----Binder.h (frameworks\native\cmds\servicemanager)
----Binder.c (frameworks\native\cmds\servicemanager)
从Service_manager.c的入口函数main(*)开启,Service Manager的启动过程主要分三个步骤:
1、调用函数binder_open打开设备文件 /dev/binder,以及将它映射到本进程的地址空间。
bs = binder_open(128*1024);
2、调用函数binder_become_context_manager将自己注册为Binder进程间通信机制的上下文管理者。
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
3、调用函数binder_loop来循环等待和处理Client进程的通信请求。
binder_loop(bs, svcmgr_handler);
1、打开和映射Binder设备文件
--> Binder.c # binder_open(*)
具体过程如下:
1、调用函数open打开设备文件 /dev/binder;
bs->fd = open("/dev/binder", O_RDWR);
2、调用函数mmap将设备文件 /dev/binder映射到进程的地址空间,它请求的地址空间大小正是binder_open接收的参数;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
2、注册为Binder上下文管理者
--> Binder.c # binder_become_context_manager(*)
Service Manager要成为Binder进程间通信机制的上下文管理者,就必须要通过IO控制命令BINDER_SET_CONTEXT_MGR将自己注册到Binder驱动程序,这是通过调用函数binder_become_context_manager来实现的,该函数具体如下:
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
3、 循环等待Client进程请求
--> Binder.c # binder_loop(*)
由于Service Manager需要在系统运行期间为Service组件和Client组件提供服务,因此,它就需要通过一个无限循环来等待和处理Service组件和Client组件的进程间通信请求。
具体过程如下:
1、注册为Binder线程,以便Binder驱动程序即可将进程间通信请求分发给它处理。
readbuf[0] = BC_ENTER_LOOPER; /* Service Manager主线程是主动成为Binder线程 */
binder_write(bs, readbuf, sizeof(uint32_t));
2、通过IO控制命令BINDER_WRITE_READ来检查Binder驱动程序是否有新的进程间通信请求。
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
3、若有请求需要它处理,交给函数binder_parse来处理;否则,当前线程就会在Binder驱动程序中休眠等待。
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
Service Manager代理对象的获取过程
Service组件在启动时,需要将自己注册到Service Manager中;而Client组件在使用Service组件提供的服务之前,也需要通过Service Manager来获得Service组件的代理对象。由于Service Manager本身是一个Service组件,因此,其他的Service组件和Client组件在使用它提供的服务之前,也需要先获得他的代理对象。
Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。获取Service Manager远程接口的函数是defaultServiceManager。该函数声明在IServiceManager.h文件,实现在IServiceManager.cpp文件中。
——相关代码文件
——IServiceManager.h (frameworks\native\include\binder)
——IServiceManager.cpp (frameworks\native\libs\binder)
——Static.cpp (frameworks\native\libs\binder)
——ProcessState.cpp (frameworks\native\libs\binder)
——IInterface.h (frameworks\native\include\binder)
在Android系统的Binder机制中,Server和Client拿到的远程接口是指是BpServiceManager,包含了一个句柄值为0的Binder引用。
对于Server来说,就是调用IServiceManager::addService这个接口来和Binder驱动程序交互。而Client则调用IServiceManager::getService这个接口与Binder驱动程序交互。
Service组件的启动过程
Service组件是在Server进程中运行的。Server进程在启动时,会首先将它里面的Service组件注册到Service Manager中,接着再启动一个Binder线程池来等待和处理Client进程的通信请求。
Client进程和Service进程的一次进程间通信过程:
1、Client进程将进程间通信数据封装成一个Parcel对象,以便可以将进程间通信数据传递给Binder驱动程序。
2、Client进程向Binder驱动程序发送一个BC_TRANSACTION命令协议。Binder驱动程序根据协议内容找到目标Server进程之后,就会向Client进程发一个BR_TRANSACTION_COMPLETE返回协议,表示它的进程间通信请求已经被接收。Client进程接收到Binder驱动程序发送给它的BR_TRANSACTION_COMPLETE返回协议,并且对它进行处理,就会再次进入到Binder驱动程序中去等待目标Server进程返回进程间通信结果。
3、Binder驱动程序在向Client进程发送BR_TRANSACTION_COMPLETE返回协议的同时,也会向目标Server进程发送一个BR_TRANSACTION返回协议,请求目标Server进程处理该进程间通信请求。
4、Server进程接收到Binder驱动程序发来的BR_TRANSACTION返回协议,并且对它进行处理之后,就会向Binder驱动程序发送一个BC_REPLY命令协议。Binder驱动程序根据协议内容找到目标Client进程之后,就会向Server进程发送一个BR_TRANSACTION_COMPLETE返回协议,表示它返回的进程间通信结果已经收到了。Server进程接收到Binder驱动程序发给它的BR_TRANSACTION_COMPLETE返回协议,并且对它进行处理之后,以及进程间通信过程就此结束了。接着它会再次进入到Binder驱动程序中去等待下一次进程间通信请求。
5、Binder驱动程序向Server进程发送BR_TRANSACTION_COMPLETE返回协议的同时,也会向目标Client进程发送一个BR_REPLY返回协议,表示Server进程已经处理完成他的进程间通信请求了,并且将进程间通信结果返回给它。
Service代理对象的获取过程
Service组件将自己注册到Service Manager中之后,它就在Server进程中等待Client进程将进程间通信请求发送过来。Client进程为了和运行在Server进程中的Service组件通信,首先要获得它的一个代理对象,这是通过Service Manager提供的Service组件查询服务来实现的。