-
服务端:即服务提供者,比如android就提供了很多的系统服务,比如Alarm、WIFI、INPUT、LAYOUT_INFLATER、ACTIVITY等;当然开发者也可以实现自己的服务,然后把服务开放给其他应用使用,在代码上服务接口必须继承 IInterface,服务具体实现类必须继承 Binder;
-
Binder驱动:实际上他是一个遵从Linux设备驱动模型的虚拟驱动,设备节点为/dev/binder;他主要用来实现客户端和服务端请求的中转,其相关源码位于./frameworks/native/libs/binder/目录;
具体驱动的打开、监听是通过守护进程servicemana
ger完成,在./init.rc中定义,相关源码位于./frameworks/base/cmds/servicemanager/;
- 客户端:即服务消费者,要想调用其他进程中的功能,必须在本地有一个对远程对象的引用,且客户端和服务端必须遵从相同的接口和数据交换协议;而这两点就是实现IPC通信需要解决的最核心的两个问题;
为了简化服务提供者和消费者之间的开发和沟通成本,android系统提供了AIDL(Android Interface Definition Language)的工具支持,该工具可以把一个用于接口声明的aidl文件转换成一个Java文件,转换的过程就是要让该服务在代码层面自动符合Binder框架的设计规范,并自动解决好上面提到的2个核心问题中的第二点,生成好的Java文件其实包括了3个类:
服务接口类IXXX extends android.os.IInterface;
本地存根类IXXX.Stub extends android.os.Binder implements IXXX;
远程代理类 IXXX.Stub.Proxy implements IXXX;
经历过EJB时代的同学们一定对上面的代码形式相当熟悉吧,哈哈!
以上文件生成好之后,服务提供者就可以专注于写具体的逻辑代码了,直接extends IXXX.Stub 实现具体的方法即可;
那是否可以不用aidl工具来生成代码呢?当然可以,如果你愿意的话完全可以自己来写相关的代码,只要符合Binder代码规范即可;
服务提供者使用的本地存根类IXXX.Stub中的核心方法
-
public final boolean transact(int code, Parcel data, Parcel reply, int flags);实际上是父类Binder中的方法,因为是final的,所以子类是不能重载的,这也是Binder框架设计的一部分,因为他不允许开发者随意改变调用机制,该方法用于接受服务调用请求,但他自己并不直接处理这些请求,而是转交给onTransact方法(可由子类重载)来处理,这是android系统中非常重要的一种设计思想,被广泛用于各种场景,以后你看见onXXXX相关的方法一般都是相关的功能回调或子类重载点;
-
protected boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags);
根据参数code判断该执行IXXX接口中的哪个具体业务方法,并且从data中按序取出数据作为具体业务方法的输入参数;
注意:从Parcel取出数据的顺序必须和存入数据(具体间后面IXXX.Stub.Proxy中业务方法的描述)的顺序一致,否则数据就乱套了,而这就是AIDL工具自动生成代码要解决的核心问题;
- public static IXXX asInterface(android.os.IBinder obj);将远程对象的引用转换成具体的业务接口,这里自动屏蔽了本地和远程调用的细节,因为服务提供方不仅可以被其他进程调用,还可以被自身进程内其他功能块调用;
服务消费者使用的远程代理类 IXXX.Stub.Proxy中的核心方法
身进程内其他功能块调用;
服务消费者使用的远程代理类 IXXX.Stub.Proxy中的核心方法