AIDL是Android接口定义语言,底层实现是通过Binder实现进程间的通信。
支持数据类型
- 八种基本数据类型
- String,Charsequence
- List
- Map
- parcelable
- Bundle(设置classloader)
多线程处理
- 线程安全:AIDL的接口实现必须是线程安全的,因为不同进程的多线程可能同时访问AIDL接口,需要加锁进行操作。
- 不要阻塞主线程:不要在AIDL接口中执行耗时操作,因为可能会阻塞调用方的主线程。如果需要执行耗时操作,应该在另一个线程中执行,通过回调发送给调用方。
- 处理DeadObjectException:当远程进程死亡时,任何对该进程的AIDL调用都会抛出异常,需要捕获异常重新绑定服务。
自定义类型传递
定义Message类,并且实现parcelable序列化,创建Message.aidl文件,在使用的aidl文件中需要手动导入。客户端和服务端相同文件并且路径要一致。
定向Tag以及oneway
in:数据只能从客户端流向服务端,服务端修改数据不会同步客户端
out:数据只能从服务端流向客户端,客户端传到服务端是空对象,服务端修改这个对象,会同步给客户端
inout:数据双向流动,客户端给服务端是完整对象,服务端改变这个对象也会同步客户端
oneway:主要有两个特性:异步调用和串行化处理。异步调用是指应用向 binder 驱动发送数据后不需要挂起线程等待 binder 驱动的回复,而是直接结束。像一些系统服务调用应用进程的时候就会使用 oneway,比如 AMS 调用应用进程启动 Activity,这样就算应用进程中做了耗时的任务,也不会阻塞系统服务的运行。 串行化处理是指对于一个服务端的 AIDL 接口而言,所有的 oneway 方法不会同时执行,binder 驱动会将他们串行化处理,排队一个一个调用。
RemoteCallbackList
beginBroadcast 开始遍历
getBroadcastItem 获取listener
finishBroadcast 结束遍历
register 注册listener
unregister 解除注册listener
帮我们处理Binder的linkToDeath和unlinkToDeath方法,传入DeathRecipient对象。这样可以帮我们避免了两个进程调用过程发生意外crash,致使 回调 失败或者进程crash的问题。
注册和解除注册的时候传递的listener不是一个对象,因为是进程间传输,服务端把客户端传递过来的对象重新转换为新的对象。ArrayMap<IBinder, Callback> 但是listener对应的Binder对象是相同。
Proxy客户端调用
//客户端获取proxy
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder)
public static com.hugl.testaidlproject.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//判断同一进程
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.hugl.testaidlproject.IMyAidlInterface))) {
return ((com.hugl.testaidlproject.IMyAidlInterface)iin);
}
//返回proxy
return new com.hugl.testaidlproject.IMyAidlInterface.Stub.Proxy(obj);
}
@Override public java.util.List<com.hugl.testaidlproject.Messages> getMessagesList() throws android.os.RemoteException
{
//客户端传递数据的parcel
android.os.Parcel _data = android.os.Parcel.obtain();
//服务端返回的数据parcel
android.os.Parcel _reply = android.os.Parcel.obtain();
//服务端返回的数据
java.util.List<com.hugl.testaidlproject.Messages> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//调用Binder,然后stub的ontransact方法数据写入_reply中
boolean _status = mRemote.transact(Stub.TRANSACTION_getMessagesList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.hugl.testaidlproject.Messages.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
整体流程
Client端:MainActivity;
Server端:Service;
Service的对外aidl接口如上面的案例所示,
MainActivity已经通过BindService拿到了Service的IBinder对象。
aidl通信的基本步骤如下:
- Client通过ServiceConnection获取到Server的Binder,并且封装成一个Proxy。
- 通过Proxy来同步调用IPC方法(testFunction),同时通过Parcel将参数传给Binder,最终触发Binder的transact方法。
- Binder的transact方法最终会触发到Server上Stub的onTransact方法。
- Server上Stub的onTransact方法中,会先从Parcel中解析中参数,然后将参数带入真正的方法中执行,然后将结果写入Parcel后传回。
- 请注意:Client的Ipc方法中,执行Binder的transact时,是阻塞等待的,一直到Server逻辑执行结束后才会继续执行。当然,如果IPC方法是oneWay的方式,那么就是非阻塞的等待。
- 当Server返回结果后,Client从Parcel中取出返回值,于是实现了一次IPC调用。