aidl 调用过程
从上一篇文章中可以知道,客户端绑定服务后,会在 onServiceConnected() 拿到 IBinder,然后通过调用 IAvengerAidlInterface.Stub.asInterface(service) 将 IBinder 转换成IAvengerAidlInterface。然后通过它来调用 addAvenger 等方法。这个过程都是在编译 aidl 文件后生成的 java 文件中完成的。
生成的 java 文件的结构
上图为 java 文件的结构,里面有一个 Stub 类,Stub 中还有一个 Proxy 的内部类。我们通过 IAvengerAidlInterface.Stub.asInterface(service) 得到的实际是这个 Proxy 类的实例。通过它调用接口的方法时会调用 transact 方法,该方法会调用到服务器的 onTransact 方法,此时客户端的线程会被挂起,直到服务器端返回。所以如果服务器端是耗时操作,客户端需要在线程中执行方法的调用。而服务器端的 onTransact 方法是运行在 Binder 线程池中,所以不管方法耗不耗时都应该采用同步的方法实现。Stub 类中的 onTransact(int code, .Parcel data, Parcel reply, int flags) 方法是真正执行相关 aidl 接口的方法。执行完成后将结果装入一个 reply 的 Parcel 中返回给客户端。
详解该 java 文件的具体实现
public interface IAvengerAidlInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements IAvengerAidlInterface {
private static final String DESCRIPTOR = "com.example.aidlserver.IAvengerAidlInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 将 IBinder 转换成我们所创建的进程间通信的接口,或者创建一个 Proxy
* @param obj
* @return
*/
public static IAvengerAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//如果客户端和服务器端在同一个进程,则直接返回服务器端的Stub对象(即Service中onBind()中返回的IBinder
if (((iin != null) && (iin instanceof IAvengerAidlInterface))) {
return ((IAvengerAidlInterface) iin);
}
//如果不在同一进程,则返回系统封装后的Stub.Proxy,它是一个代理类,用它来实现跨进程通信
return new Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 客户端调用服务器端的通信接口的具体实现
* @param code 这个 code 对应服务器端所有执行的方法,譬如我们写了一个 getAvengers() 方法,那么就会对应生成一个 code 如 TRANSACTION_getAvengers 用于 switch-case。
* @param data 方法里面的参数
* @param reply 方法的返回值
* @param flags false 代表客户端请求失败
* @return
* @throws android.os.RemoteException
*/
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getAvengers: {
data.enforceInterface(DESCRIPTOR);
//调用服务器端 getAvengers() 方法,然后写到 reply 中返回给客户端
java.util.List<com.example.aidlserver.aidlmodel.Avenger> _result = this.getAvengers();
reply.writeNoException();
//数据的传递都是通过 Parcelable 实现的。这样你就知道为什么自定义的数据结构都要实现 parcelable 了吧
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addAvengerIn: {
data.enforceInterface(DESCRIPTOR);
com.example.aidlserver.aidlmodel.Avenger _arg0;
if ((0 != data.readInt())) {
//调用 Avenger.CREATOR.createFromParcel 用于创建一个 Avenger 对象,并将参数传进去
_arg0 = com.example.aidlserver.aidlmodel.Avenger.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//通过 data 构造完方法所需要的参数后,开始调用服务器端的方法
this.addAvengerIn(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_addAvengerInout: { // inout 相当于结合了 in 和 out
data.enforceInterface(DESCRIPTOR);
com.example.aidlserver.aidlmodel.Avenger _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.aidlserver.aidlmodel.Avenger.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addAvengerInout(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addAvengerOut: {
data.enforceInterface(DESCRIPTOR);
com.example.aidlserver.aidlmodel.Avenger _arg0;
//out 直接 new 一个空对象,参数直接不要然后传给服务器。相当于没用传一个容器给服务器
_arg0 = new com.example.aidlserver.aidlmodel.Avenger();
this.addAvengerOut(_arg0); // 服务器端可以往这个“容器”填充内容
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
//再将该(修改过的)“容器”的内容写到 reply ,它后面会被写回到客户端传进来的那个对象,如果它被服务器端修改
//那么客户端的该对象就会被同步修改。This is the trick that the out tag playes.
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements IAvengerAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<com.example.aidlserver.aidlmodel.Avenger> getAvengers() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.aidlserver.aidlmodel.Avenger> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getAvengers, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.aidlserver.aidlmodel.Avenger.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//in 为定向 tag 的话,服务端将会接收到该对象的完整数据,但是客户端的那个对象不会因为服务端对该参数的修改而发生变动
@Override
public void addAvengerIn(com.example.aidlserver.aidlmodel.Avenger avenger) throws android.os.RemoteException {
//创建两个 Parcel,一个用于存放参数,一个用于存放返回值
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
//将客户端传过来的 avenger 对象中的参数都写到 data 中
if ((avenger != null)) {
_data.writeInt(1);
avenger.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//调用 transact 后,该远程请求会经过系统底层封装后调用到服务器端的 onTransact,客户端的该线程会被挂起,
//那么如果该方法很耗时就要开线程调用了。而 onTransact 方法本身就是在服务器端的 binder 线程池中执行的,所以
//Binder方法不管耗不耗时都应该采用同步的方法实现。
//我们可以看到 transact 方法传的不是 Avenger ,而是该对象的 Parcel,这就解释了后面调用的 onTransact
//方法为什么要直接 New 或者采用 Parcelable 的 Create 来创建一个新 Avenger 了。
mRemote.transact(Stub.TRANSACTION_addAvengerIn, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
//inout 为定向 tag 时,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。
@Override
public void addAvengerInout(com.example.aidlserver.aidlmodel.Avenger avenger) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((avenger != null)) {
//先写个1进去代表 dada 中有值,这就解释了上面的 onTransact 方法中判断 data.getInt() != 0 才去创建 Avenger
_data.writeInt(1);
avenger.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addAvengerInout, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
avenger.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
//out 的话,服务端将会接收到一个参数为空的对象,但服务端该“空”对象修改之后客户端会同步变动
@Override
public void addAvengerOut(com.example.aidlserver.aidlmodel.Avenger avenger) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
//从上面可知会调用到 onTransact 方法,由于参数的 tag 为 out。 那么这个
//_reply 就已经被服务器端赋值了
mRemote.transact(Stub.TRANSACTION_addAvengerOut, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
//将 _reply 的内容拷贝给 avenger,这样服务器如果对客户端传过去的 avenger
//修改了的话,客户端也会同步改变
avenger.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getAvengers = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addAvengerIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_addAvengerInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_addAvengerOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List<com.example.aidlserver.aidlmodel.Avenger> getAvengers() throws android.os.RemoteException;
public void addAvengerIn(com.example.aidlserver.aidlmodel.Avenger avenger) throws android.os.RemoteException;
public void addAvengerInout(com.example.aidlserver.aidlmodel.Avenger avenger) throws android.os.RemoteException;
public void addAvengerOut(com.example.aidlserver.aidlmodel.Avenger avenger) throws android.os.RemoteException;
}
下面我们看下 Binder 工作机制图
结合上面的解释很好懂。