android机制系列之六 Binder/AIDL回调callback机制原理

AIDL回调机制原理

1. 接口定义

主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);
} 

2. client主动流程原理

前情回顾,我们一般的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;
}

这里写图片描述

3. server回调流程原理

相反,注册回调的该如何处理呢?

实际上,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<MainActivity> activity;

    MyCallback(MainActivity activity) {
        this.activity = new WeakReference<MainActivity>(activity);
    }

    @Override
    public void dataCalback(String s) {
        //to do something by `s`
    }
};

//XXXService.java
//远程回调队列
private final RemoteCallbackList<ICallback> mCallbacks = new RemoteCallbackList<ICallback>();

@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()

最后执行。
这里写图片描述

总结

  1. client会申请callback接口Stub/BnXXX;
  2. 注册的时候,其实就让server端持有client端的一个IBinder对象(因为跨进程server端保存的是BinderProxy/BpBinder);
  3. 回调的时候,我们常说的server端此刻作为“client”,回调到原来的client端,它此刻作为了”server“。

为何没有分析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()

猜你喜欢

转载自blog.csdn.net/jzlhll123/article/details/80865999