Android之AIDL使用binder进程间通信原理

上回书说到,如何使用AIDL进行线程进通信
这次我们来研究一下AIDL线程间通信原理。

Binder机制

首先我们需要知道一下什么是Binder机制,具体什么是Binder机制推荐多查一查其他博客,由于太过于偏向底层,稍微做一些了解即可。

代码分析

还是先上代码,首先看一下我们自己定义的AIDL接口
注意,一下代码均是在Android-29(Android 10.0)版本上的

interface IMyAidlInterface {
    void sendMessage(in String msg);
    String getMessage();
}

定义完成接口之后编辑器会自动为我们生成IMyAidlInterface.java这个类

我们使用时会在客户端绑定服务进程,在onServiceConnected中获得到IMyAidlInterface的实例对象,下面我们一起来看看代码。有关于如何绑定service以及如何拿到的实例对象请参考我的另一篇文章。
Android AMS源码分析之结合AIDL分析bindService

先看下部分关键代码及注释内容

//定义一个这个东西
private IMyAidlInterface myAidl;
        public void onServiceConnected(ComponentName name, IBinder service) {
         	//在这里拿到它的实例
         	/**
         	*在这里我们记住传入的参数“service” 是一个Ibinder对象
         	*/
            myAidl = IMyAidlInterface.Stub.asInterface(service);
        }

然后在IMyAidlInterface中初始化
最终return的是

return new com.tiancong.myaidl1.IMyAidlInterface.Stub.Proxy(obj);

在这里我们先看一下他们的层级关系
Android之AIDL使用binder进程间通信原理_第1张图片
在Proxy只有这一个构造方法,所以记住这个mRemote就是我们传入的参数

    private static class Proxy implements com.tiancong.myaidl1.IMyAidlInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      ......
    }

我们可以看到 Proxy 也是实现了IMyAidlInterface接口的,所以我们客户端调用的接口中的方法的最终实现就在在这里实现的。
我们可以清楚的看到 例如sendmessage

      @Override public void sendMessage(java.lang.String msg) 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.writeString(msg);
          boolean _status = mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().sendMessage(msg);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }

在这里我们会发现我们sendmessage方法的参数msg被一个_data的成员打包进去了,然后使用了
mRemote.transact(…)的方法,我们上文提到mRemote是就是我们的Ibinder,IBinder又是一个接口,所以我们就要去找实现IBinder接口的Binder类里面去看transact方法的具体实现,接下来的跳转就很简单了,通过Binder的transact调用data.setDataPosition()方法,最终到nativeSetDataPosition(mNativePtr, pos)方法。我们知道native方法是本地方法,都是C、C++来实现的,在这里我们不做深入了解,最终的结果就是把数据发送了出去
补充transact下面代码

    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

记住boolean r = onTransact(code, data, reply, flags);这行代码,待会要考。

接下来我们来看服务端代码,看看服务的是怎么完成接受数据并返回的
绑定服务的代码就不看了,我们先看下在服务端是如何绑定的

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return iBinder;
    }

    private IBinder iBinder = new IMyAidlInterface.Stub() {
        @Override
        public void sendMessage(String msg) throws RemoteException {
            message = "  "+msg +"  " + "被service处理了";
            Log.d(TAG, "sendMessage: "+msg);
        }

        @Override
        public String getMessage() throws RemoteException {
            Log.d(TAG, "getMessage: "+message);
            return message;
        }
    };

我们在在服务开启执行onBind的时候返回了iBinder,我们可以清楚的看到这个iBinder就是我们IMyAidlInterface.stub()的一个实例对象。我们看下这个东西。

public static abstract class Stub extends android.os.Binder implements com.tiancong.myaidl1.IMyAidlInterface

我们看到,这个stub继承Binder类,在里面又重写了上面的提到的onTransact方法,再加上一些底层不了描述的逻辑,完了了最终在客户端通过Transact发送,在服务的onTransact中接受,例如我们sendmesseg方法最终会在服务的执行。关于这里面的具体细节我们可以参考一下下面这张图片,只是作为了解一下就可以了

        case TRANSACTION_sendMessage:
        {
          data.enforceInterface(descriptor);
          java.lang.String _arg0;
          _arg0 = data.readString();
          this.sendMessage(_arg0);
          reply.writeNoException();
          return true;
        }

Android之AIDL使用binder进程间通信原理_第2张图片

可以看到this.sendMessage(_arg0);我们在stub类里面没有找到sendmessage的实现,所以我们的最终调用的sendmessage就是我们在服务中重新的sendmessage方法。这样就完成了一次完整的进程间通信操作。

如果对Android进程间通信还有什么疑问,欢迎关注我的微信公众号,我们来一起进行讨论。
Android之AIDL使用binder进程间通信原理_第3张图片

你可能感兴趣的:(java,Android,java,android,多进程)