先给大家看一下我的AIDL文件,只有两个方法:
interface IRemoteService {
void setPause(String pause);
void setPlay(String play);
}
以下具体分析的是Make build生成的IRemoteService.java文件。
对比下图理解更有助于理解源码:
Binder的工作机制.png
- 在文件开头就有注释,该文件是自动生成的,不要修改。所以如果要为跨进程通信添加新的方法,只需要在IRemoteService.aidl文件中添加再build即可。
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.wanda.musicplayer;
// Declare any non-default types here with import statements
- IInterface:IRemoteService继承自IInterface,所有Binder通信的接口必须继承IInterface接口
public interface IRemoteService extends android.os.IInterface {
/**
* Default implementation for IRemoteService.
*/
public static class Default implements com.wanda.musicplayer.IRemoteService {
@Override
public void setPause(java.lang.String pause) throws android.os.RemoteException {
}
@Override
public void setPlay(java.lang.String play) throws android.os.RemoteException {
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
... ...
- Stub继承了Binder类并实现了IRemoteService。而学过activity与service通信的都知道,在Service中的onBind方法会返回一个Binder对象,而Stub继承了Binder,又是一个抽象类,所以Stub可以作为我们跨进程通信时,服务端自定义Binder的父类。
public static abstract class Stub extends android.os.Binder implements com.wanda.musicplayer.IRemoteService {
- DESCRIPTOR:Binder的唯一标识,通常是包名+接口名组成的字符串
private static final java.lang.String DESCRIPTOR = "com.wanda.musicplayer.IRemoteService";
- asInterface:asInterface将服务端Binder转换为客户端所需的AIDL接口类型对象。在方法中首先会调用queryLocalInterface(DESCRIPTOR),参数是binder的唯一标识,用来查询本地接口。如果能查询到本地接口IRemoteService(客户端和服务端处于同一进程),就返回本地接口,不跨进程通信。如果查询不到本地接口,就构造Proxy代理对象并返回,通过代理对象可以跨进程通信。**
public static com.wanda.musicplayer.IRemoteService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
// 5.1\. 如果能查询到本地接口IRemoteService,就返回本地接口,不跨进程通信。
if (((iin != null) && (iin instanceof com.wanda.musicplayer.IRemoteService))) {
return ((com.wanda.musicplayer.IRemoteService) iin);
}
// 5.2\. 如果查询不到本地接口,就返回代理对象,通过代理对象可以跨进程通信。
return new com.wanda.musicplayer.IRemoteService.Stub.Proxy(obj);
}
- asBinder():用于返回当前Binder对象
//6. asBinder()用于返回当前Binder对象
@Override
public android.os.IBinder asBinder() {
return this;
}
- Proxy代理类:构造Proxy时,把服务端的Binder对象赋值给mRemote,Proxy中实现了自定义方法:setPause和setPlay ,通过调用mRemote的transact方法,最后走到Stub的onTransact,完成对服务端Binder的调用。
- onTransact与transact
(1)每个AIDL中定义的方法都有一个int code来标识:
static final int TRANSACTION_setPause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setPlay = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
(2)Proxy中实现了setPause和setPlay,其中分别调用了mRemote.transact()方法,transact的第一个参数code是每个方法的唯一标识。客户端远程请求Binder并写入参数,通过transact传入服务端。
private static class Proxy implements com.wanda.musicplayer.IRemoteService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void setPause(java.lang.String pause) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(pause);
boolean _status = mRemote.transact(Stub.TRANSACTION_setPause, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().setPause(pause);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void setPlay(java.lang.String play) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(play);
boolean _status = mRemote.transact(Stub.TRANSACTION_setPlay, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().setPlay(play);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public static com.wanda.musicplayer.IRemoteService sDefaultImpl;
}
(3)onTransact运行在服务端的Binder线程池中,当客户端发起跨进程请求时,请求会通过底层封装后,交由onTransact处理,服务端通过code来判断客户端请求的方法是什么,接着从data取出目标方法需要的参数(如果目标方法有参数的话),然后执行目标方法,执行完之后就向reply中写入返回值(如果目标方法有返回值的话),这就是这个方法的执行过程,如果此方法返回false,那么客户端请求失败。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_setPause: {
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
this.setPause(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_setPlay: {
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
this.setPlay(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
所以,aidl通信体现着代理模式的设计思想,RemoteService具体实现了Stub,Proxy是Stub在本地的Client代理对象,Proxy与Stub依靠transact和onTransact通信,Proxy与Stub的封装设计最终很方便地完成了客户端与服务端的跨进程通信