Android OS的核心设计思想是component,而支持component的基石则是Inter-component-communication/Inter-process-communication,而不同抽象层次的ICC/IPC都是由Binder来实现的。
从概念上来说,Binder采用C/S通信Model。传送的数据存放于Transaction中,为了能把不同结构的数据放入Transaction,传输前后必须进行序列化和反序列化。通过Death Notification能够知道Binder是否还活着。为了让C能找到S,有两种方式:注册service和匿名service,注册service架构类似于Mediator design pattern, 匿名service则是通过Intent。Binder的Security 通过携带双方的PID,UID完成。
从实现上来说,Binder采用分层模型。从上到下分别为:Java app层主要是通过AIDL在client侧生成访问service的proxy,在service侧生成带有remote method实现的stub;Java API层除了封装底层Binder middleware以外,引入了Intent的相关facilities;C++ middleware主要负责管理request working的进程/线程,marshalling/unmarshalling data,与binder driver 交互;Binder driver负责安全可靠的在process之间转发message。
Android 4种Component 的hierarchical class diagram如下:
Activity代表App的一个UI,主要负责显示和接受user输入。由于可能被另一个位于前端的Activity置于睡眠状态,一般不存放persistent data。
Service主要服务于需要长期存在的目的。由于service只有在system 的memory耗尽需要kill app来释放内存时才会被强制停止,所有后台处理的工作都应该放置于此。
ContentProvider一般用于管理persistent data。它提供访问persistent data 的interface,这个接口类似于file/network stream 以及SQL DB。
BroadcastReceiver用于接受系统发送的message。
虽然通信的形式有Intent、ContentProvider、Messager,但基石都是Binder。
1.2.1 Component通信举例
既然Component各有分工,他们之间就需要通信来相互合作。如下图所示,Activity通过Intent来start,同时通过Intent将另一个Activity带到前台;Service能够通过Intent被start/stop/bind,同时也是通过Intent来return; ContentProvider 能够通过CRUD被访问;BroadcastReceiver能够接受订阅的Intent。
1.2.2 Component通信的形式
从上节知道,通信的形式有Intent、ContentProvider,其实他们都是对Binder的high-level抽象:
Intent是component之间的一种异步通信方式:
Intent支持点对点(Explicit Intent)或者订阅-发布(Implicit Intent)的模式;
Intent可以包含标识具体component的URI,operation 的描述ACTION以及相应的data;
ContentProvider和ContentResolver之间是一种同步的并通过CRUD API联系的通信方式。
Messenger作为对Handler的reference通过Intent发送给remote process,当remote process处理messenger时候会callback回local process。
Binder最重要的作用是提供类似RPC 的调用。这种调用能提供One-way或者Two-way的方式。借助AIDL,可以只暴露service的接口而隐藏实现。
Link-to-death notification能够通知Binder进程的结束。
Binder都具有唯一标识,所以能作为能在multiple process 之间shared的token。
通过Binder能获取到Caller’s PID/UID。
如下图所示,Process A 作为client端持proxy object来实现与Binder driver的通信,driver则负责将message转发到目标object; Process B作为server端会根据进来的request不断spawn新的thread来处理,一直到最大thread数limitation。
每次在process之间传递的data叫做transaction data,它的结构如下图。
Target:指向目标binder节点;
Cookie:存放内部使用信息;
Sender ID:包含安全相关信息;
Data field:包含一组序列化的data array,array中每个entry包含 command和相应的argument;
任何一个需要在process间传递的object都必须实现Parcelable接口:在发送端实现序列化该对象,在接受端实现恢复对象。所有对象内的信息都必须转化为原子类型: int、float、boolean、String。
这个序列化的过程叫做marshaling或者flattening。重构对象的过程叫做unmarshaling或者unflattening。
这是一种oberser pattern:本地Binder object如果希望知道远端Binder object的生命周期结束,就会将其加入一个oberser队列。如果远端Binder宿主process terminaton事件发生,就会通知本地Binder object并作出相应。
这是一种Mediator pattern:Context Manager是一个Binder 号为0的特殊Binder,它为其他Binder提供名字-Binder mapping的服务。
每个作为service来发布的binder,都需要将其name和binder token提交给Context Manager。
Client如果需访问某个service,只需知道service name,然后通过访问Context Manager就可获得需要访问service的Binder token。
Intent 位于Java API 层并通过Binder 发送,它是一种对需要执行操作的抽象,即操作的实际执行者并不一定需要在Intent内定义。
Intent通常包含action和data两部分。
常见的Intent分为两类:explicit intent会指向特定的目标component;implicit intent指向的目标component由Android系统决定,如果有多个component目标,系统将选择最合适那个来执行。
Binder保证为通信的两个process提供secure channel,同时通过PID/UID 来识别两端的partners。
Intent filter:是service或者application的声明,标识该service/application能够接受什么样的intent。另外,intent filter会被explicit intent bypass,所以其并不能保证对所有intent都安全。
类IInterface为所有的server端的共同基类,它的子类,比如IServiceManager、IMediaPlayerService等等提供了该服务端所具备的所有功能(一些列API)。
类IBinder是Binder通信协议的接口,为client和server端通信的基础。
类BBinder和类BpBinder均为IBinder的子类:BBinder用于server端,BpBinder用于client端。
类BBinder继承自IBinder,用于server端。各个服务端的service(比如ServiceManager、MediaPlayerService等等)需要创建一个继承BBinder并实现onTransact()函数的class,比如BnXXXService。BBinder通过transact()接收处理client端发过来的请求命令,并调用onTransact()这个虚函数,即调用BnXXXService的onTransact()函数。
类BpRefBase 的作用:client 端通过查询ServiceManager 获取到所需的的 BpBinder 后, BpRefBase 负责管理当前获得的 BpBinder 实例,并保存至成员变量IBinder* const mRemote;
类BpBinder继承自IBinder,负责将client端的请求发送至服务端的BBinder,为服务端在client端所提供的服务代理。客户端必须通过服务代理BpBinder才可以享用服务端所提供的具体服务。
模板类BnInterface(template class BnInterface : public INTERFACE, public BBinder)继承自传入的类INTERFACE和BBinder;
模板类BpInterface(template class BpInterface : public INTERFACE, public BpRefBase)继承自传入的类INTERFACE和BpRefBase。
ProcessState 是以单例模式设计的。每个进程在使用binder 机制通信时,均需要维护一个ProcessState 实例来描述当前进程在binder 通信时的binder 状态。
ProcessState 有如下2 个主要功能:
1. 创建一个thread, 该线程负责与内核中的binder 模块进行通信,称该线程为Pool thread ;
2. 为指定的handle 创建一个BpBinder 对象,并管理该进程中所有的BpBinder 对象。
5.2.1 Pool thread
在Binder IPC 中,所有进程均会启动一个thread 来负责与BD 来直接通信,也就是不停的读写BD ,这个线程的实现主体是一个IPCThreadState 对象,下面会介绍这个类型。
下面是Pool thread 的启动方式:
ProcessState::self()->startThreadPool();
5.2.2 BpBinder
获取BpBinder 主要功能是负责client 向BD 发送调用请求的数据。它是client 端binder 通信的核心对象,通过调用transact 函数向BD 发送调用请求的数据,它的构造函数如下:
BpBinder(int32_t handle);
通过BpBinder 的构造函数发现,BpBinder 会将当前通信中server 的handle 记录下来,当有数据发送时,会通知BD 数据的发送目标。
ProcessState 通过如下方式来获取BpBinder 对象:
ProcessState::self()->getContextObject(handle);
在这个过程中,ProcessState 会维护一个BpBinder 的vector mHandleToObject ,每当ProcessState 创建一个BpBinder 的实例时,回去查询mHandleToObject ,如果对应的handle 已经有binder 指针,那么不再创建,否则创建binder 并插入到mHandleToObject 中。
ProcessState 创建的BpBinder 实例,一般情况下会作为参数构建一个client 端的代理接口,这个代理接口的形式为BpINTERFACE , 例如在与SM 通信时,client 会创建一个代理接口BpServiceManager .
IPCThreadState 也是以单例模式设计的。由于每个进程只维护了一个ProcessState 实例,同时ProcessState 只启动一个Pool thread ,也就是说每一个进程只会启动一个Pool thread ,因此每个进程则只需要一个IPCThreadState 即可。
Pool thread 的实际内容则为:
IPCThreadState::self()->joinThreadPool();
ProcessState 中有2 个Parcel 成员,mIn 和mOut ,Pool thread 会不停的查询BD 中是否有数据可读,如果有将其读出并保存到mIn ,同时不停的检查mOut 是否有数据需要向BD 发送,如果有,则将其内容写入到BD 中,总而言之,从BD 中读出的数据保存到mIn ,待写入到BD 中的数据保存在了mOut 。
ProcessState 中生成的BpBinder 实例通过调用IPCThreadState 的transact 函数来向mOut 中写入数据,这样的话这个binder IPC 过程的client 端的调用请求的发送过程就明了了 。
IPCThreadState 有两个重要的函数,talkWithDriver 函数负责从BD 读写数据,executeCommand 函数负责解析并执行mIn 中的数据。