Binder是Android的一种安全且高效的进程间通信机制,安全是因为其发起通信时会写入PID/UID信息,高效是因为传输过程只需要一次内存拷贝
Binder机制
总结
Binder通信模型包含四个角色Client,Service,ServiceManager和Binder驱动,通信过程为:
- Server进程需要先向ServiceManager进程注册服务,该过程本身是跨进程的,首先获得ServiceManager服务,然后调用注册方法
- Client进程使用服务时需要向ServiceManager获得对应Service
- 调用服务中提供的方法
整个过程类似于从电话本上查到对应名字的电话并拨打过去……
基础知识
进程是CPU上运行的单个任务,Linux系统是多进程的,使用虚拟内存实现了进程的隔离,进程都认为独占了整个系统,进程之间数据不共享,需要借助某种机制进行进程间通信
Linux将内存划分为内核空间和用户空间,内核空间不允许应用程序随便访问,应用程序可以通过系统调用进入内核态访问内核空间
一个进程的用户空间如果想要访问别的进程的用户空间,需要借助进程间通信机制,如Linux的Socket,管道,共享内存等,Android则使用了Binder机制,通过Binder驱动实现
Binder跨进程通信原理
Android系统使用代理模式完成Binder通信,Client进程持有Server端的代理,代理对象协助驱动完成了跨进程通信
Java层数据结构
- IBinder 代表跨进程传输能力的接口,驱动会识别IBinder类型的数据,完成本地对象和代理对象的转换
- IInterface 代表远程服务能力的接口
- Binder 代表Binder本地对象,BinderProxy是Binder的内部类,是Binder的本地代理,它们都实现了IBinder,Binder驱动会完成这两种对象的转换
- Stub 使用AIDL的时候会自动生成Stub类,它继承了Binder,实现了IInterface,是一个抽象类,需要被具体实现
AIDL生成的代码可以看到这几个结构,Android的很多服务基本都是这个样子,比如ActivityManagerService
IActivityManager
是具有Activity管理能力的远程接口,ActivityManagerNative
实现了该接口,它是一个Binder本地对象,它的内部类ActivityManagerProxy
是Binder代理对象,ActivityManagerService
继承了ActivityManagerNative
,是服务的具体实现类
以ActivityManagerService为例的原理分析
以startActivity()
为例
Instrumentation.java
1 | ActivityManagerNative.getDefault().startActivity() |
首先获得ActivityManager服务,然后调用startActivity()
ActivityManagerNative.java
1 | IBinder b = ServiceManager.getService("activity"); |
通过ServiceManager
获得名为activity
的服务,它是一个IBinder
通过asInterface()
方法转化成IActivityManager
接口,这个对象具有Activity管理能力,显然在应用进程里它应该是一个Binder代理对象
ActivityManagerNative.java
1 | static public IActivityManager asInterface(IBinder obj) { |
通过queryLocalInterface()
获取本地接口,如果获取不到则用此Binder创建一个代理对象
Binder.java
1 | public IInterface queryLocalInterface(String descriptor) { |
这个方法在Binder
和BinderProxy
中都有实现,Binder
中返回了本地对象,而BinderProxy
中返回了null
,所以在服务端和客户端拿到的IBinder不同
获得IActivityManager
之后就可以调用startActivity()
方法
1 | public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException { |
按顺序填入参数,然后调用mRemote
的transact()
方法,这个mRemote
就是一个IBinder
,最后等待返回值
服务端在onTransact()
里面收到客户端发来的命令
1 |
|
根据命令号走对应的条件分支,取出参数,调用服务端中实际的startActivity()
方法,最后写回返回值
ServiceManager
ServiceManager
是整个Binder机制的守护进程,来管理各种Server,并像Client提供查询Server远程接口的功能
ServiceManager
做了三件事:
1.打开Binder设备文件并建立内存映射
2.告诉Binder驱动自己是上下文管理者即守护进程
3.进入无限循环,等待Client的请求
ServiceManager也是一个Server,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过ServiceManager远程接口提供的getService
接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于ServiceManager这个Server来说,Client如果想要获得ServiceManager远程接口,却不必通过进程间通信机制来获得,因为ServiceManager远程接口是一个特殊的Binder引用,它的引用句柄一定是0