AIDL分析(Binder跨进程通信分析)
文件格式
package com.ckkj.router.aidl;
interface IRouterInterface {
void stepIn(int steps);
void stepOut(int steps);
}
可以看到,aidl的内容书写格式和正常的接口一模一样,只是文件后缀为aidl,而且具有包名和import语句
需要注意的是:由于不是普通的java文件,在aidl引用关系中,即使是位于同一个package下的文件,也需要通过import将引用的类导入到aidl中
文件描述
创建完aidl文件后,rebuild该项目,会在gen目录下生成aidl文件对应的java文件,上图中的aidl文件对应生成的java文件如下:
<!--对应接口的标识符-->
private static final java.lang.String DESCRIPTOR = "com.github.lotty.IMyAidlInterface";
<!--对应接口中的方法标识符-->
static final int TRANSACTION_stepIn =(android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_stepOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
<!--对应接口中的stepIn方法-->
public void stepIn(int steps) throws android.os.RemoteException;
<!--对应接口中的stepOut方法-->
public void stepOut(int steps) throws android.os.RemoteException;
- TRANSACTION 方法标识符,有限定范围,必须介于
FIRST_CALL_TRANSACTION
和LAST_CALL_TRANSACTION
之间
/**
* The first transaction code available for user commands.
*/
int FIRST_CALL_TRANSACTION = 0x00000001;
/**
* The last transaction code available for user commands.
*/
int LAST_CALL_TRANSACTION = 0x00ffffff;
- DESCRIPTOR Biner标识符,确认是有哪个客户端发起的请求,一般是类的全路径名称
- 类关系说明
/**创建的aidl文件对应的java接口文件
*/
interface IRouterInterface extends android.os.IInterface
/**本地客户端stub,处理通信,可能是进程内,也可能是进程间,当引起进程间通信时,会交给代理类Proxy
*/
abstract class Stub extends android.os.Binder implements com.ckkj.router.aidl.IRouterInterface
/**处理进程间通信的代理类
*/
class Proxy implements com.ckkj.router.aidl.IRouterInterface
方法分析
- onTransact
/**该方法会由服务端执行,运行在服务端的binder线程池中,主要是将结果写到返回结果对象中
* 需要注意该方法的最好是同步的,因为已经是在线程池中
*/
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_stepIn: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
this.stepIn(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_stepOut: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
this.stepOut(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
2. stepIn接口方法
/**该方法会由服务端在代理类Proxy中执行,主要是将参数写到请求参数对象中,并调用服务端的transact方法
*/
public void stepIn(int steps) 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.writeInt(steps);
mRemote.transact(Stub.TRANSACTION_stepIn, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
总体流程
- 客户端发起调用,通过asInterface获取远端Binder在本地的对象(或者代理)
- 查询本地是否已有服务对象
queryLocalInterface
(本地调用) - 出发跨进程调用时,通过Stub.Proxy对象将调用交给服务端
- 在Proxy中对应的方法调用会调用
Binder.transact
方法,并将参数序列化写入到data中,调用对象为服务端的Binder对象,此时调用进入服务端 - transact的方法会调用自身的onTransact方法,进行真实的调用,同时将返回数据序列化写入到reply中
- 本地从reply中获取数据,流程结束