一、原理
首先 binder 在最底层有 kernel 的驱动支持。/dev/binder 是 binder 的设备文件。然后 android 通过这个驱动在 native 层整了一套 C/S 架构的框架出来,最后在 java 对应也封装了一层(可以理解为 native 的马甲)。这些东西后面再慢慢分析。
二、应用
基于 binder android 弄了很多 manager services,不过小编觉得倒是因为需要存在这些 maanger services 才需要 binder 进程间通信。这里说说为什么需要这些 manager services。因为设备的上的有些硬件(例如相机、传感器)一般一次只能一个访问,有些需要把一些数据混合在一起输出(SurfaceFlinger、AudioFlinger),这就需要一些管理,但是应用是不同的程序,它们并不知道其它人的情况,所以就需要一个 manager,而且这个 manager 是要能接受不同进程的。这就引出了 android binder 的最经典的场景—— android 那一票 services。
同时由于有这一票 services 的 存在,那么又要有人来管它们,所以就有一个东西叫: ServiceManager 。这个东西本身也是基于 binder 通信的。
三、框架设计——native
binder 主要的实现在 native 层。先来张图,整体对框架有个概括:
这里先啰嗦下 binder native 层的代码位置(这个是个模块,相关的都里面,没几个文件,自己找吧):
图中分为2个部分:一个是实现部分(BBinder、BpBinder 那部分),一个是接口部分(IInterface 那部分)。先来看下实体部分:
前面说了 binder 是 C/S 架构的,那当然得有 server 和 client。BBinder 代表 server,BpBinder 代表 client,然后在这个基础上抽象出 IBinder 这个基类。IBinder 中比较重要的抽象方法有4个:
然后在基类有默认实现的是3个:
基类的实现还真全是马甲,但是这样也有个好出,就是子类可以只覆盖自己感兴趣的方法就可以了(否则子类就必须全部实现,不然编译会报错的)。
先来看看 localBinder 和 remoteBinder 这2个,这2个看定义就十分明显了,一个是返回 BBinder 的指针(服务器的),一个是返回 BpBinder 的指针(客户端的),而且在 BBinder 和 BpBinder 分别只实现了一个:
然后是 queryLocalInterface 这个,这个返回的是 IInterface 的指针。BBinder 和 BpBinder 都没有实现,这个放到后面暴露的接口去实现了。
最后来看下: transact,这个看名字,和参数就知道这个就是通信用的方法。这个在基类中也没实现,但是在 BBinder 和 BpBinder 有实现,并且不一样(当然得不一样,服务器能和客户端一样么)。BBinder 的:
那个PING_TRANSACTION估计是测试用的,先不理它,它主要就是调用了 onTransact 这个回调。这个回调是在 BBinder 中定义的,是个虚函数,主要留给它的子类来实现。可以想象得到服务器端在等待客户端的请求,当有请求来的时候,就会出发 onTransact 然后由具体的服务(子类)来实现这个回调,处理不同的逻辑。
而在 BpBinder 中是这样的:
又是马甲,这个IPCThreadState 是线程剧本变量,就是一个线程存一个,不同线程不一样,binder 的 C/S 架构采用了多线程来处理请求,这个也是后面再分析,先来看看实现再说:
这个函数中关键点是 writeTransactionData 和 waitForResponse,这2个函数分别是对 binder 驱动写请求(数据已经通过 Parcel 打包好,这个也是后面再分析),然后等待 binder 驱动的返回的数据结果(服务器那端写的)。驱动相关的也是后面再说,先在继续往下走。这里可以看得出客户端是将请求写入驱动,发送给服务器,然后等待服务器返回的结果。
然后就是接口了,接口基类是 IInterface,这个基类很简单,就定义2个有用的函数:
其实它留给子类的就 onAsBinder 这个回调,用来获取 IBinder 的指针。IInterface 的子类是 BnInterface 和 BpInterface 分别对应 BBinder(服务器) 和 BpBinder(客户端)的接口。在这之前得先看看 INTERFACE 这个东西,android 在这里弄了一个模版类,BnXx 和 BpXx 都是。
在 IInterface.h 中有这2个宏:
如果在 .h 中的 class 定义中调用DECLARE_META_INTERFACE("Xx")在 .cpp 中的实现中调用IMPLEMENT_META_INTERFACE("Xx", "Xx")那么就相当于声明和实现了:
1、默认构造函数
2、析构函数
3、定义了并以 Xx 初始化 String16 descriptor 这个变量
4、asInterface: 返回 IXx 的指针
5、getInterfaceDescriptor: 返回 descriptor 字符串
实际上,后面的具体的 native 的 service 的接口就是这么写的(后面会有具体的实例分析)。
接下来就看真正的接口基类: BnInterface:
哎呦咧,C++ 的多重继承,分别继续了 BBinder(binder 的服务器) 和 INTERFACE 这个其实就是上面的 IInterface,在具体的 services 中会通过 IInterface 中的那2个宏弄一个 IXx 出来,然后 BnInterface 这里的 INTERFACE 就是 IXx(这个后面到了实例分析,就会很清楚了)。这里实现上面 BBinder 那没实现的几个接口:
queryLocalInterface 这个是只有 BBinder 才有的(对比 IBinder 的接口),然后根据在这个函数的实现:对比 descriptor 是不是自己定义的(通过DECLARE_META_INTERFACE这个宏定义的),然后是否返回自己,可以猜得到:1、这个函数是用来判断请求是不是处于本进程内,如果是的话,应该就不需要跨进程调用,直接可以调用本进程的方法。这样对于上层应用来说,暴露的是 IBinder 接口,上层应用不需要关心调用是本地的还是远程的。2:descriptor 这个是用来区别 binder 的服务器的,binder 通过这个来判断请求是不是发给自己的,如果 descriptor 不匹配,则拒绝处理。
然后是 BpInterface 了:
比 Bn 相比,没了判断是不是本地的接口了,客户端当然不需要有啦。然后应该是继续 BpBinder 的,变成了 BpRefBase 。
上面这个东西,其它的不看,就看一个函数 remote() 返回 mRemote 这个 IBinder 指针。然后来看下 BpInterface 的构造函数:
BpInterface 的 sp 参数的构造函数,把 sp 传给 BpRefBase 了,这个 IBinder 其实就是 BpBinder (通过后面的分析可以看得出的)。结合上面 Bn 的 onAsBinder 是返回 this 自己(BBinder),Bp 的是返回 BpBinder 。
再下面,就是具体业务相关的了,IXx 继承自 IInterface,主要是使用 IInterface 提供的那个DECLARE_META_INTERFACE(Xx)这个宏声明一些接口(上面有分析的),Xx 就是接口的名字了,例如 ServerManager、SurfaceComposer 之类的(这个后面会有具体的实例分析的)。然后这个 IXx 还得定义这个 service 对外(客户端)提供的接口,例如 CaptureScreen 之类的,这个就和具体的 service 相关了。
BnXx 继承 BnInterface(同时继承 IXx),使用 IInterface 提供的IMPLEMENT_META_INTERFACE(Xx, Xx)来实现上面说的那些接口。注意这里的 Xx 要和DECLARE_META_INTERFACE那里的一样,例如都叫 SurfaceComposer, 然后后面那个是标示(descriptor),例如 “android.ui.ISurfaceComposer”(用包名来标示一般不会重复)。
然后剩下的主要是实现 onTransact 就是响应客户端的请求。其实通过后面的分析 BnXx 中也并不是真正实现请求的地方,这个只是一个中转站而已,真正的实现在 service 模块里面,一个一个业务函数实现的,这里的 onTransact 只是区分客户端发过来的请求命令,然后去调用 service 里面的函数,实现这些的文件都叫 I
Xx.h, IXx.cpp 看上去也不像实现的样子。然后真正的 service 就要继承 BnXx 去实现 onTransact。但是你也发现了,onTransact 已经在 BnXx 里实现了,所以你在 services 看到的 onTransact 都是马甲,基本上都是调用: super.onTransact 的 。
BpXx 继承 BpInterface。 BpInterface 并没强制要求 BpXx 实现啥东西,但是作用客户端(Java 层那一堆 XxManager 给其它 apk 调用的),暴露给第三方引用使用的,必须要实现服务器提供的方法对应的接口:例如说 service 那边有一个方法是: captureScreen 用来实现截屏用的,那么客户端也必须有响应的方法: captureScreen,然后客户端调用 remote()(IBinder) 的 transact 发送请求到服务器。当然其实函数名字也可以不一一对应,你只要在服务器 onTransact 里调用正确就行了。但是后面你会发现如果这些东西一一对应的话,代码是很机械的,后面 android 就搞了个代码自动生成的工具出来(aidl)。