一、IPC消息机制
1、AIDL
1)AIDL实现远程Service调用步骤:
- 服务器端创建aidl文件,aidl文件有两种
// 表示提供方法的接口
interface BookController {
// oneway代表这个Binder接口是异步调用
oneway void addBook(Book book);
}
// 表示自定义传输数据类
parcelable Book;
- 创建service,声明一个BookController.Stub类型的对象(代表该服务的binder实体),在onbind方法里返回该binder实体,binder实体中实现aidl中定义的接口
- 客户端通过bindService方法绑定服务器中的服务,在onServiceConnected中将IBinder service参数转换成aidl接口类型
BookController service = BookController.Stub.asInterface(service);
- 拿到服务端的binder,可以直接调用接口
2)AIDL调用过程:
3)IBinder/IInterface/Binder/BinderProxy/Stub解析:
- IBinder是一个接口,它代表了一种跨进程传输的能力;只要实现了这个接口,就能将这个对象进行跨进程传递;这是驱动底层支持的;在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。
- IBinder负责数据传输,那么client与server端的调用契约(这里不用接口避免混淆)呢?这里的IInterface代表的就是远程server对象具有的接口能力。具体来说,就是aidl里面的接口。
- Java层的Binder类,代表的其实就是Binder本地对象。BinderProxy类是Binder类的一个内部类,它代表远程进程的Binder对象的本地代理;这两个类都继承自IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。
- 在使用AIDL的时候,编译工具会给我们生成一个Stub的静态内部类;这个类继承了Binder, 说明它是一个Binder本地对象,它实现了IInterface接口,表明它具有远程Server承诺给Client的能力;Stub是一个抽象类,具体的IInterface的相关实现需要我们手动完成,这里使用了策略模式。
4)Proxy和Stub的关系:
Proxy与Stub不一样,虽然他们都既是Binder又是IInterface,不同的是Stub采用的是继承(is 关系),Proxy采用的是组合(has 关系)。他们均实现了所有的IInterface函数,不同的是,Stub使用策略模式调用的是虚函数(待子类实现),而Proxy则使用组合模式。
5)oneway
- oneway关键字表示被修饰接口为异步调用,服务端阻塞时不会阻塞客户端;仅作用于远程调用,对本地调用无作用
- oneway可以用来修饰在interface之前,这样会造成interface内所有的方法都隐式地带上oneway;
- oneway也可以修饰在interface里的各个方法之前。
- 被oneway修饰了的方法不可以有返回值,也不可以有带out或inout的参数。
6)in/out/inout
所有的非基本参数都需要一个定向tag来指出数据流通的方式,不管是 in , out , 还是 inout 。基本参数的定向tag默认是并且只能是 in 。
- in 为定向 tag 的话表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动;
- out 的话表现为服务端将会接收到那个对象的的空对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动(理解为传入指针参数作为返回值);
- inout 为定向 tag 的情况下,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。
2、Messenger
1)Messenger实现远程Service调用步骤:
- 服务端创建Handler用于处理客户端的消息,同时可以向客户端回复消息
private Handler serverHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case WHAT_TO_SERVER:
Messenger client = msg.replyTo;
client.send(toClient);
break;
}
}
});
通过客户端发送过来的消息Message msg,调用msg.replyto获得客户端的信使Messenger client ,通过client.send(toClient)向客户端回复消息。
- 服务端新建信使Messenger,上一步创建的Handler实例作为参数。
private Messenger serverMessenger = new Messenger(serverHandler);
- 服务端返回Messenger的Binder
@Override
public IBinder onBind(Intent intent) {
// 返回Messenger的IBinder
return serverMessenger.getBinder();
}
- 客户端创建Handler用来处理服务端发送的消息
- 客户端创建信使Messenger clientMessager,传递给服务端用来发送回复消息
- 连接远程服务MessengerService,新建Messenger serverMessenger,用来向服务端发送消息。
private Messenger serverMessenger;
private ServiceConnection messagerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serverMessenger = new Messenger(service);
}
};
这里IBinder service是服务端onBind返回的Binder,用此Binder创建Messenger就可以像服务端发送消息了。
- 向服务端发送消息
Message toServer = Message.obtain(null, WHAT_TO_SERVER);
toServer.arg1 = 100;
toServer.replyTo = clientMessager;
serverMessenger.send(toServer);
2)Messenger实现原理
在AIDL 的基础上,进一步封装服务端暴露的接口,将服务端收到Message通过Handlder发送到目标线程。
系统定义了IMessenger AIDL接口,其中只有send方法。
oneway interface IMessenger {
void send(in Message msg);
}
在Handler.java中实现了该接口:
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg