AIDL回调机制原理
主aidl接口
// IRemote.aidl
package allan.com.test;
import allan.com.test.ICallback;
interface IRemote {
void regist(ICallback cb);
void unregist(ICallback cb);
}
回调aidl接口
// IRemote.aidl
package allan.com.test;
interface ICallback {
void dataCalback(String s);
}
前情回顾,我们一般的binder(aidl)client某个主动调用服务器的方法func()执行,是通过XXXProxy(BnXXX)的方法transact()传递到服务端。然后服务端对应的func()真实地执行。
@Override public void regist(allan.com.test.ICallback cb) throws android.os.RemoteException
{ //client proxy
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null))); //将cb当做参数写入Parcel
mRemote.transact(Stub.TRANSACTION_regist, _data, _reply, 0);//再通过transact驱动传入
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
//server Stub
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) {
case TRANSACTION_regist:
{
data.enforceInterface(DESCRIPTOR);
allan.com.test.ICallback _arg0;
_arg0 = allan.com.test.ICallback.Stub.asInterface(data.readStrongBinder());
this.regist(_arg0); //服务端真实执行的代码
reply.writeNoException();
return true;
}
相反,注册回调的该如何处理呢?
实际上,RemoteCallbackList,内部主要是维护了一个List用于存储所有的client注册的ICallback IBinder对象。内部又有一个object[] mActiveBroadcast用于中转。基本可以忽略它的存在。又或者只有一个client则直接保存ICallback对象即可。
首先注册过程就是一个client主动调用的流程。上面已经分析过,将ICallback(IBinder)保存下来。
在注册的时候,
//regist(allan.com.test.ICallback cb)
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null))); //writeStrongBinder
mRemote.transact(Stub.TRANSACTION_regist, _data, _reply, 0); //transact()
_reply.readException();
类似再谈Binder中的附录1-2可以分析到,writeStrongBinder最后onTransact接收端(为什么我换个词呢)拿到的cb,拿到的BinderProxy/BpBinder对象。
如何回调?
//client中的代码,实现Stub
static class MyCallback extends ICallback.Stub {
WeakReference activity;
MyCallback(MainActivity activity) {
this.activity = new WeakReference(activity);
}
@Override
public void dataCalback(String s) {
//to do something by `s`
}
};
//XXXService.java
//远程回调队列
private final RemoteCallbackList mCallbacks = new RemoteCallbackList();
@Override
public IBinder onBind(Intent intent) {
return mStub;
}
private IRemote.Stub mStub = new IRemote.Stub() {
@Override
public void regist(ICallback cb) throws RemoteException {
if (cb != null) mCallbacks.register(cb); //绑定
}
@Override
public void unregist(ICallback cb) throws RemoteException {
if (cb != null) mCallbacks.unregister(cb);//解除
}
};
//XXXService.java
protected void callback2Client(String info) {
if (mCallbacks == null || mCallbacks.getRegisteredCallbackCount() <= 0) {return;}
synchronized (mCallbacks) {
mCallbacks.beginBroadcast(); //开始回调
int N = mCallbacks.getRegisteredCallbackCount();
for (int i = 0; i < N; i++) {
try {
if (mCallbacks.getBroadcastItem(i) == null) {
continue;
}
mCallbacks.getBroadcastItem(i).dataCalback(info); //get出来以后调用dataCalback到客户端去
} catch (DeadObjectException e) {
if (mCallbacks.getBroadcastItem(i) != null)
mCallbacks.unregister(mCallbacks.getBroadcastItem(i));
} catch (RemoteException e) {
e.printStackTrace();
}
}
mCallbacks.finishBroadcast(); //结束回调
}
}
server端某个事情发生后,队列则调用mCallbacks.getBroadcastItem(i).dataCalback(info);
或者只有一个使用mCallback.dataCallback(info)
。刚才说过server端持有的这个Callback是BinderProxy/BpBinder对象,因此这里调用的时候会使用transact()
最后回到到原来的客户端onTransact()
为何没有分析C++层的Binder回调?事实上是一样的,在前面分析中我已经提到了,BnXX,BpXX,BpBinder等其实跟java层是一一对应的。在后续的研究中会有涉及。这里略过。
client主动流程图
title Authentication Sequence
client->client:func()
client-->binder:transact()
binder-->server:onTransact()
server->server:func()
title Authentication Sequence
client->client:regist(cb)
client-->binder:transact()
binder-->server:onTransact()
server->server:regist(cb)
server->server:cb(BinderProxy/BpBinder)
server->server:cb.dataCallback()
server-->binder:transact()
binder-->client:dataCallback()
client->client:dosomething()