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()
AIDL (Android Interface Definition Language) 是一种跨进程通信机制,它可以让不同进程间的组件进行通信。其中,callback 机制AIDL 的重要特性之一,它允许客户端向服务端注册回调,服务端可以在需要的时候调用客户端提供的回调方法。 下面是一个简单的 AIDL 回调机制的代码示例: 定义 AIDL 接口: ``` // IMyService.aidl interface IMyService { void registerCallback(IMyCallback cb); void unregisterCallback(IMyCallback cb); } interface IMyCallback { void onResult(int result); } ``` 服务端实现 AIDL 接口: ``` // MyService.java public class MyService extends Service { private List<IMyCallback> callbacks = new ArrayList<>(); private final IMyService.Stub binder = new IMyService.Stub() { @Override public void registerCallback(IMyCallback cb) throws RemoteException { callbacks.add(cb); } @Override public void unregisterCallback(IMyCallback cb) throws RemoteException { callbacks.remove(cb); } }; // 在需要的时候调用客户端提供的回调方法 private void notifyCallbacks(int result) { for (IMyCallback cb : callbacks) { cb.onResult(result); } } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } } ``` 客户端调用 AIDL 接口并注册回调: ``` // MyActivity.java public class MyActivity extends Activity { private IMyService myService; private IMyCallback myCallback = new IMyCallback.Stub() { @Override public void onResult(int result) throws RemoteException { // 处理服务端传回来的结果 } }; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { myService = IMyService.Stub.asInterface(service); try { myService.registerCallback(myCallback); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { myService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); // 绑定服务 Intent intent = new Intent(this, MyService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); // 解除回调注册 if (myService != null) { try { myService.unregisterCallback(myCallback); } catch (RemoteException e) { e.printStackTrace(); } } // 解绑服务 unbindService(connection); } } ``` 在客户端的代码中,我们首先绑定服务,并在连接成功后注册回调。当服务端需要通知客户端时,它会遍历回调列表并调用客户端提供的回调方法。在客户端的回调方法中,我们可以处理服务端传回来的结果。最后,在客户端销毁时,我们需要解除回调注册并解绑服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值