Android IPC之AIDL源码探索(三)源码探索

1,504 阅读18分钟

一、简介

这将是一个围绕AIDL的系列文章,内容含AIDL简单使用、进阶使用、AIDL源码探索,希望从简单开始再到复杂,在这个过程中使大家既能掌握AIDL的使用方法和需要注意的细节,同时也能通过对AIDL源码的探索,使各位理解AIDL的处理原理。这篇文章为第三篇,会在前两篇的基础上,根据例子中的AIDL接口,深入源码探索AIDL的实现原理。

二、AIDL文件结构

先回顾一下,前两篇文章中定义的AIDL文件。

interface MyAIDLInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void commonMethod();

    void setStringText(String text);

    void setObjectMethodIn(in MethodObject o);
    void setObjectMethodOut(out MethodObject o);
    void setObjectMethodInout(inout MethodObject o);

    MethodObject getObjectMethod();

    void register(CallBackAIDLInterface aidl);
    void unregister(CallBackAIDLInterface aidl);
}

为了全面了解AIDL对不同类型函数的处理逻辑,这里定义了8个函数,register()和unregister()情况一样,所以总体有7种不同类型。现在去看AIDL类,真正的幕后黑手,类内容有些长,你可能会反感,但相信我你需要耐心的浏览一下。

public interface MyAIDLInterface extends android.os.IInterface
{
  /** Default implementation for MyAIDLInterface. */
  public static class Default implements com.zhukai.aidlservice.MyAIDLInterface
  {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public void commonMethod() throws android.os.RemoteException
    {
    }
    @Override public void setStringText(java.lang.String text) throws android.os.RemoteException
    {
    }
    @Override public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
    {
    }
    @Override public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
    {
    }
    @Override public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
    {
    }
    @Override public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException
    {
      return null;
    }
    @Override public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException
    {
    }
    @Override public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.zhukai.aidlservice.MyAIDLInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.zhukai.aidlservice.MyAIDLInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.zhukai.aidlservice.MyAIDLInterface interface,
     * generating a proxy if needed.
     */
    public static com.zhukai.aidlservice.MyAIDLInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.zhukai.aidlservice.MyAIDLInterface))) {
        return ((com.zhukai.aidlservice.MyAIDLInterface)iin);
      }
      return new com.zhukai.aidlservice.MyAIDLInterface.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_commonMethod:
        {
          data.enforceInterface(descriptor);
          this.commonMethod();
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_setStringText:
        {
          data.enforceInterface(descriptor);
          java.lang.String _arg0;
          _arg0 = data.readString();
          this.setStringText(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_setObjectMethodIn:
        {
          data.enforceInterface(descriptor);
          com.zhukai.aidlservice.MethodObject _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.setObjectMethodIn(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_setObjectMethodOut:
        {
          data.enforceInterface(descriptor);
          com.zhukai.aidlservice.MethodObject _arg0;
          _arg0 = new com.zhukai.aidlservice.MethodObject();
          this.setObjectMethodOut(_arg0);
          reply.writeNoException();
          if ((_arg0!=null)) {
            reply.writeInt(1);
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        case TRANSACTION_setObjectMethodInout:
        {
          data.enforceInterface(descriptor);
          com.zhukai.aidlservice.MethodObject _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.setObjectMethodInout(_arg0);
          reply.writeNoException();
          if ((_arg0!=null)) {
            reply.writeInt(1);
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        case TRANSACTION_getObjectMethod:
        {
          data.enforceInterface(descriptor);
          com.zhukai.aidlservice.MethodObject _result = this.getObjectMethod();
          reply.writeNoException();
          if ((_result!=null)) {
            reply.writeInt(1);
            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        case TRANSACTION_register:
        {
          data.enforceInterface(descriptor);
          com.zhukai.aidlservice.CallBackAIDLInterface _arg0;
          _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder());
          this.register(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_unregister:
        {
          data.enforceInterface(descriptor);
          com.zhukai.aidlservice.CallBackAIDLInterface _arg0;
          _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder());
          this.unregister(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.zhukai.aidlservice.MyAIDLInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
      @Override public void commonMethod() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_commonMethod, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().commonMethod();
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public void setStringText(java.lang.String text) 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(text);
          boolean _status = mRemote.transact(Stub.TRANSACTION_setStringText, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setStringText(text);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((o!=null)) {
            _data.writeInt(1);
            o.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodIn, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setObjectMethodIn(o);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodOut, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setObjectMethodOut(o);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            o.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((o!=null)) {
            _data.writeInt(1);
            o.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodInout, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().setObjectMethodInout(o);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            o.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        com.zhukai.aidlservice.MethodObject _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getObjectMethod, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getObjectMethod();
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            _result = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(_reply);
          }
          else {
            _result = null;
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) 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.writeStrongBinder((((aidl!=null))?(aidl.asBinder()):(null)));
          boolean _status = mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().register(aidl);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) 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.writeStrongBinder((((aidl!=null))?(aidl.asBinder()):(null)));
          boolean _status = mRemote.transact(Stub.TRANSACTION_unregister, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().unregister(aidl);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.zhukai.aidlservice.MyAIDLInterface sDefaultImpl;
    }
    static final int TRANSACTION_commonMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_setStringText = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_setObjectMethodIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    static final int TRANSACTION_setObjectMethodOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
    static final int TRANSACTION_setObjectMethodInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
    static final int TRANSACTION_getObjectMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
    static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
    static final int TRANSACTION_unregister = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
    public static boolean setDefaultImpl(com.zhukai.aidlservice.MyAIDLInterface impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.zhukai.aidlservice.MyAIDLInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public void commonMethod() throws android.os.RemoteException;
  public void setStringText(java.lang.String text) throws android.os.RemoteException;
  public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException;
  public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException;
  public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException;
  public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException;
  public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException;
  public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException;
}

看到这里,我深怕劝退了很多小伙伴,这个类也太长了,但是我相信看到这里的你还是对这个类有了一点印象,现在只需要我们整理一下思路,先弄清楚类的结构,然后再以实际使用作为入口去追踪,一切都会云开雾散!下面我会把代码极简化,让大家看清类的整体结构。

public interface MyAIDLInterface extends android.os.IInterface
{
  //默认的实现类
  public static class Default implements com.zhukai.aidlservice.MyAIDLInterface
  {
    ... //省略了继承实现的函数
  }
  //服务端的Binder对象
  public static abstract class Stub extends android.os.Binder implements com.zhukai.aidlservice.MyAIDLInterface
  {
     ...  //省略了内容
    //客户端代理对象
    private static class Proxy implements com.zhukai.aidlservice.MyAIDLInterface
    {
    }
     ...  //省略了内容
  }
  //AIDL文件中定义的所有函数
  public void commonMethod() throws android.os.RemoteException;
  public void setStringText(java.lang.String text) throws android.os.RemoteException;
  public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException;
  public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException;
  public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException;
  public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException;
  public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException;
  public void unregister(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException;
}

现在这个类结构就简单清晰多了,AS根据我们定义的AIDL文件,构建了最外层MyAIDLInterface类,包含了所有AIDL文件中定义的函数。再在内部构建了3个实现类Default、Stub、Proxy(Stub内部类),Default就很好理解了,一个默认实现类;Stub、Proxy(Stub内部类)可以说是整个AIDL类中最重要的两个类,Stub是服务端的,所以它同时还继承了Binder类(Binder类实现了IBinde接口),Proxy是客户端的。弄清楚了结构,现在就可以回到使用,通过使用的流程来追踪内部实现逻辑。

三、源码追踪

1.服务端创建Binder对象

应该还记得在服务端Service中,onBind方法返回了Stub对象。

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return stub;
}

MyAIDLInterface.Stub stub = new MyAIDLInterface.Stub() {...}

这里需要看一下Stub对象创建时做了什么。

private static final java.lang.String DESCRIPTOR = "com.zhukai.aidlservice.MyAIDLInterface";
/** Construct the stub at attach it to the interface. */

private IInterface mOwner;
private String mDescriptor;

public Stub()
{
  this.attachInterface(this, DESCRIPTOR);//调用了Binder的函数
}

public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;//Stub对象
    mDescriptor = descriptor;//描述符
}

通过调用父类Binder的attachInterface()函数,把自己和一段描述符绑定在了Binder对象中。这样在onBind()函数中返回的Binder对象就携带了Stub对象和一段描述符,这个描述符就是自己完整的类名。

这个Binder对象最终被返回到哪儿去了呢?会不会是绑定Service的地方,那就去看客户端。

2.客户端获取操作对象

private void bind() {
    Intent intent = new Intent();
    intent.setAction("com.zhukai.aidlservice.startService");
    intent.setComponent(new ComponentName("com.zhukai.aidlservice","com.zhukai.aidlservice.MyService"));
    bindService(intent, new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAIDLInterface = MyAIDLInterface.Stub.asInterface(service);//核心方法
            ...
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAIDLInterface = null;
        }
    }, Service.BIND_AUTO_CREATE);
}

在客户端绑定方法中,ServiceConnection接口的onServiceConnected回调方法返回了一个IBinder对象,这个IBinder对象,就是刚刚服务端Service中返回的Binder对象。这里需要注意,根据Binder机制特性,如果我们绑定的服务没有另起进程,那这个Binder对象和服务端是同一个;另起进程了,这个Binder对象就只是服务端返回Binder对象的一个BinderProxy代理对象。现在Binder已经从服务端传递到了客户端,再看客户端后续操作。

接着调用MyAIDLInterface.Stub.asInterface(service)函数传入Binder对象,这是一个专门获取客户端操作对象的函数。


//描述符就是AIDL类的完整类名
private static final java.lang.String DESCRIPTOR = "com.zhukai.aidlservice.MyAIDLInterface";

/**
 * Cast an IBinder object into an com.zhukai.aidlservice.MyAIDLInterface interface,
 * generating a proxy if needed.
 */
public static com.zhukai.aidlservice.MyAIDLInterface asInterface(android.os.IBinder obj)
{
  if ((obj==null)) {//判空
    return null;
  }
  android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//核心
  if (((iin!=null)&&(iin instanceof com.zhukai.aidlservice.MyAIDLInterface))) {
    return ((com.zhukai.aidlservice.MyAIDLInterface)iin);
  }
  return new com.zhukai.aidlservice.MyAIDLInterface.Stub.Proxy(obj);
}

在函数内,先判断了Binder是否为null,紧接着调用Binder对象的queryLocalInterface()函数,传入了客户端的描述符DESCRIPTOR。

public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    if (mDescriptor != null && mDescriptor.equals(descriptor)) {//和Binder缓存的描述符做比较
        return mOwner;
    }
    return null;
}

因为Binder对象的不同,在这个函数中就会出现两种情况,如果这个Binder对象和服务端是同一个,在服务端是有绑定了描述符(mDescriptor)和Stub对象(mOwner)的,再同传入的客户端的描述符比较相等,那就会返回绑定的服务端Stub对象。如果这个Binder对像是代理对象,那这个mDescriptor肯定是null,那就直接返回null。

执行跳出这个方法回到asInterface()函数中。

public static com.zhukai.aidlservice.MyAIDLInterface asInterface(android.os.IBinder obj)
{
  if ((obj==null)) {
    return null;
  }
  android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  if (((iin!=null)&&(iin instanceof com.zhukai.aidlservice.MyAIDLInterface))) {//不为null且类型匹配
    return ((com.zhukai.aidlservice.MyAIDLInterface)iin);//把Stub对象转换成实现的AIDL类 类型
  }
  //否则返回代理对象,传入了Binder代理对象。
  return new com.zhukai.aidlservice.MyAIDLInterface.Stub.Proxy(obj);
}

如果iin对象是服务端Stub对象,就直接转换成AIDL类类型返回,为null,就会传入Binder代理对象创建Proxy代理对象返回。反正,最终客户端会拿到一个AIDL类对象,是受Binder对象的不同,返回对象有差异。本篇文章重点是围绕Service另起进程的情况,也就是Binder为代理对象,那么此方法将执行到最后一步,返回Proxy代理对象。因为服务端Service是在同一进程的情况下,客户端拿到的是服务端Stub对象,就不存在IPC了,也就没有往后分析的必要。

3.各类型函数内部实现分析

客户端拿到Proxy代理对象,就可以调用所有函数与服务端进行通信。

if (null != myAIDLInterface){
    myAIDLInterface.commonMethod();
    myAIDLInterface.setStringText("test");
    myAIDLInterface.setObjectMethodIn(new MethodObject());
    myAIDLInterface.setObjectMethodInout(new MethodObject());
    myAIDLInterface.setObjectMethodInout(new MethodObject());
    myAIDLInterface.getObjectMethod();
    myAIDLInterface.register(callBackAIDLInterface);
    myAIDLInterface.unregister(callBackAIDLInterface);
}

CallBackAIDLInterface callBackAIDLInterface = new CallBackAIDLInterface.Stub() {
    @Override
    public void callBack() throws RemoteException {

    }
};

commonMethod()

点击进入commonMethod()函数,确是MyAIDLInterface接口的commonMethod()函数,但是因为myAIDLInterface对象实际是Proxy类对象,所以实际上是Proxy类中的实现方法,看下具体实现。

@Override public void commonMethod() throws android.os.RemoteException
    {
  //序列化操作对象Parcel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入描述符
    boolean _status = mRemote.transact(Stub.TRANSACTION_commonMethod, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态。
    if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      getDefaultImpl().commonMethod();//调用默认实现
      return;
    }
    _reply.readException();//读取服务端执行是否有异常
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
}

因为是IPC的过程,所以传输数据都需要进行序列化,所以开始创建了两个序列化操作对象(_data,_reply)。 然后写入了一段描述符,接着就直接调用了mRemote的transact()函数,传入了一个标识(Stub.TRANSACTION_commonMethod)和两个序列化对象(_data,_reply)以及一个int(flags)值。这个标识就是用于区分函数的,称它为函数标识吧。

static final int TRANSACTION_commonMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setStringText = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_setObjectMethodIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_setObjectMethodOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_setObjectMethodInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_getObjectMethod = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
static final int TRANSACTION_unregister = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);

mRemote就是初始化Proxy对象时传入的Binder对象;忘记了可以回顾一下前面asInterface()函数的分析。执行到mRemote.transact()这一步其实就堵塞了,Binder机制会通知服务端Stub对象中的onTransact()函数(mRemote.transact()->服务端Binder.onTransact()->Stub类中重写的onTransact()),现在我们去Stub类中onTransact()函数看下做了什么。

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
  java.lang.String descriptor = DESCRIPTOR;
  switch (code)
  {
    case INTERFACE_TRANSACTION:
    {
      reply.writeString(descriptor);
      return true;
    }
    case TRANSACTION_commonMethod:
    {
      data.enforceInterface(descriptor);
      this.commonMethod();
      reply.writeNoException();
      return true;
    }
    case TRANSACTION_setStringText:
    {
      data.enforceInterface(descriptor);
      java.lang.String _arg0;
      _arg0 = data.readString();
      this.setStringText(_arg0);
      reply.writeNoException();
      return true;
    }
    case TRANSACTION_setObjectMethodIn:
    {
      data.enforceInterface(descriptor);
      com.zhukai.aidlservice.MethodObject _arg0;
      if ((0!=data.readInt())) {
        _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);
      }
      else {
        _arg0 = null;
      }
      this.setObjectMethodIn(_arg0);
      reply.writeNoException();
      return true;
    }
    case TRANSACTION_setObjectMethodOut:
    {
      data.enforceInterface(descriptor);
      com.zhukai.aidlservice.MethodObject _arg0;
      _arg0 = new com.zhukai.aidlservice.MethodObject();
      this.setObjectMethodOut(_arg0);
      reply.writeNoException();
      if ((_arg0!=null)) {
        reply.writeInt(1);
        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
      }
      else {
        reply.writeInt(0);
      }
      return true;
    }
    case TRANSACTION_setObjectMethodInout:
    {
      data.enforceInterface(descriptor);
      com.zhukai.aidlservice.MethodObject _arg0;
      if ((0!=data.readInt())) {
        _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);
      }
      else {
        _arg0 = null;
      }
      this.setObjectMethodInout(_arg0);
      reply.writeNoException();
      if ((_arg0!=null)) {
        reply.writeInt(1);
        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
      }
      else {
        reply.writeInt(0);
      }
      return true;
    }
    case TRANSACTION_getObjectMethod:
    {
      data.enforceInterface(descriptor);
      com.zhukai.aidlservice.MethodObject _result = this.getObjectMethod();
      reply.writeNoException();
      if ((_result!=null)) {
        reply.writeInt(1);
        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
      }
      else {
        reply.writeInt(0);
      }
      return true;
    }
    case TRANSACTION_register:
    {
      data.enforceInterface(descriptor);
      com.zhukai.aidlservice.CallBackAIDLInterface _arg0;
      _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder());
      this.register(_arg0);
      reply.writeNoException();
      return true;
    }
    case TRANSACTION_unregister:
    {
      data.enforceInterface(descriptor);
      com.zhukai.aidlservice.CallBackAIDLInterface _arg0;
      _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder());
      this.unregister(_arg0);
      reply.writeNoException();
      return true;
    }
    default:
    {
      return super.onTransact(code, data, reply, flags);
    }
  }
}

整体看下来,是通过不同的函数标识做了不同的逻辑处理。分析commonMethod()函数,根据函数标识判断是TRANSACTION_commonMethod分支。

case TRANSACTION_commonMethod:
{
  data.enforceInterface(descriptor);//对描述符进行了校验
  this.commonMethod();//调用了自己的commonMethod()函数,也就是服务端Stub对象的commonMethod()函数。
  reply.writeNoException();//写入无异常
  return true;
}

首先对描述符进行了校验,再调用了this.commonMethod()函数。这个this就是Stub对象,既调用了服务端Stub对象的commonMethod()函数。后面再写入无异常,返回true代表执行成功。服务端执行完毕,客户端阻塞恢复运行继续执行下面代码。

if (!_status && getDefaultImpl() != null) {
  getDefaultImpl().commonMethod();
  return;
}
_reply.readException();

失败了一般也是不会有设置默认实现,所以后续就是执行读取服务端写入的异常,进行异常检测,如果服务端写入了异常,那客户端将抛出异常。感兴趣可以点入源码查看一下。这样一次完整的通信就完成了。

注:分析完commonMethod()函数,我们对AIDL基本的通讯逻辑已经清楚了,后续不同类型函数实现只是在处理细节上有所差异,差异都是存在客户端Proxy实现函数和服务端Stub类onTransact()函数中。故后续只分析这两个函数即可,并且直接把客服端和服务端两个函数放在一起,便于直观。

setStringText(String text)

//客户端Proxy类
@Override public void setStringText(java.lang.String text) throws android.os.RemoteException
{
  //序列化操作对象Parcel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入描述符
    _data.writeString(text);//写入传入的数据
    boolean _status = mRemote.transact(Stub.TRANSACTION_setStringText, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态。
    if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      getDefaultImpl().setStringText(text);//调用默认实现
      return;
    }
    _reply.readException();//读取服务端执行是否有异常
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
}

//服务端Stub类
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR; 
    switch (code) {
        case TRANSACTION_setStringText:
        {
          data.enforceInterface(descriptor);//对描述符进行了校验
          java.lang.String _arg0;
          _arg0 = data.readString();//读取客户端写入的数据
          this.setStringText(_arg0);//调用自己的函数,并传入读取的数据
          reply.writeNoException();//写入无异常
          return true;
        }
    }
}

差异主要是客户端多了一步写入数据,服务端相应的就多了一步读取数据。

void setObjectMethodIn(in MethodObject o)

//客户端Proxy类
@Override public void setObjectMethodIn(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
{
  //序列化操作对象Parcel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入描述符
    if ((o!=null)) {//数据对象不为null
      _data.writeInt(1);//写入1,表示序列化对象不为null
      o.writeToParcel(_data, 0);//写入序列化对象
    }
    else {
      _data.writeInt(0);//写入0,表示序列化数据对象为null
    }
    boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodIn, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态。
     if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      getDefaultImpl().setObjectMethodIn(o);//调用默认实现
      return;
    }
    _reply.readException();//读取服务端执行是否有异常
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
}

//服务端Stub类
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR; 
    switch (code) {
        case TRANSACTION_setObjectMethodIn:
        {
          data.enforceInterface(descriptor);//对描述符进行了校验
          com.zhukai.aidlservice.MethodObject _arg0;
          if ((0!=data.readInt())) {//客户端有写入0或1,非0代表序列化对象不为null
            _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);//进行反序列化
          }
          else {
            _arg0 = null;
          }
         this.setObjectMethodIn(_arg0);//调用自己的函数,传入数据对象。
         reply.writeNoException();//写入无异常
         return true;
        }
    }
}

setObjectMethodIn()函数参数是一个对象类型,并在AIDL文件中进行了in修饰前缀修饰,参数的数据对象只能从客户端传入服务端,所以在逻辑上只在客户端进行了序列化,在服务端进行反序列化,服务端的修改并不能影响到客户端。

setObjectMethodOut(out MethodObject o)

//客户端Proxy类
@Override public void setObjectMethodOut(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
{
  //序列化操作对象Parcel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入描述符
    boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodOut, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态。
    if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      getDefaultImpl().setObjectMethodOut(o);//调用默认实现
      return;
    }
    _reply.readException();//读取服务端执行是否有异常
    if ((0!=_reply.readInt())) {//服务端有写入0或1,非0代表序列化对象不为null
      o.readFromParcel(_reply);//反序列化修改参数中数据对象o的数据
    }
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
}

//服务端Stub类
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR; 
    switch (code) {
        case TRANSACTION_setObjectMethodOut:
        {
          data.enforceInterface(descriptor);//对描述符进行了校验
          com.zhukai.aidlservice.MethodObject _arg0;
          _arg0 = new com.zhukai.aidlservice.MethodObject();//创建一个数据对象
          this.setObjectMethodOut(_arg0);//调用自己的函数,传入刚刚创建的对象。
          reply.writeNoException();//写入无异常
          if ((_arg0!=null)) {//数据对象不为null
            reply.writeInt(1);//写入1,表示序列化数据对象不为null
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//写入序列化对象
          }
          else {
            reply.writeInt(0);//写入0,表示序列化数据对象为null
          }
          return true;
        }
    }
}

setObjectMethodOut()函数参数也是一个对象类型,并在AIDL文件中进行了out修饰前缀修饰,客户端参数数据对象无法传输到服务端,所以在客户端调用mRemote.transact()函数之前,并没有进行序列化写入操作;但是因为服务端的修改是可以影响到客户端的,所以在服务端的处理上直接创建了一个数据对象,并调用函数时传入,使服务端进行操作,在方法执行完后,又进行了序列化写入操作。当服务端无异常执行完成后,客户端阻塞停止,反而客户端通过反序列化对原本传入的数据对象进行了数据修改。

setObjectMethodInout(inout MethodObject o)

客户端Proxy类
@Override public void setObjectMethodInout(com.zhukai.aidlservice.MethodObject o) throws android.os.RemoteException
{
  //序列化操作类对象Pracel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入描述符
    if ((o!=null)) {//数据对象不为null
      _data.writeInt(1);//写入1,表示序列化数据对象不为null
      o.writeToParcel(_data, 0);//写入序列化对象
    }
    else {
      _data.writeInt(0);//写入0,表示序列化数据对象为null
    }
    boolean _status = mRemote.transact(Stub.TRANSACTION_setObjectMethodInout, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态。
    if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      getDefaultImpl().setObjectMethodInout(o);//调用默认实现
      return;
    }
    _reply.readException();//读取服务端执行是否有异常
    if ((0!=_reply.readInt())) {//服务端有写入0或1,非0代表序列化对象不为null
      o.readFromParcel(_reply);//反序列化修改参数中数据对象o的数据
    }
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
}
//服务端Stub类
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR; 
    switch (code) {
        case TRANSACTION_setObjectMethodInout:
        {
          data.enforceInterface(descriptor);//对描述符进行了校验
          com.zhukai.aidlservice.MethodObject _arg0;
          if ((0!=data.readInt())) {//客户端有写入0或1,非0代表序列化对象不为null
             _arg0 = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(data);//进行反序列化
          }
          else {
            _arg0 = null;
          }
            this.setObjectMethodInout(_arg0);//调用自己的函数,传入刚刚的数据对象。
            reply.writeNoException();//写入无异常
          if ((_arg0!=null)) {//数据对象不为null
            reply.writeInt(1);//写入1,表示序列化数据对象不为null
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//写入序列化对象
          }
          else {
            reply.writeInt(0);//写入0,表示序列化数据对象为null
          }
          return true;
        }
    }
}

setObjectMethodInout()函数参数同样是一个对象类型,并在AIDL文件中进行了inout修饰前缀修饰,参数的数据对象既能传输到服务端,同时服务端对数据对象的修改也能同步到客户端,所以在逻辑处理上客服端在调用mRemote.transact()函数之前,进行了序列化处理,在服务端进行了反序列化处理。服务端在调用自己函数时传入了这个反序列化得来的数据对象,同时函数执行完又将这个数据对象再进行序列化;等到服务端执行完毕后,客户端阻塞停止,客户端也进行一次反序列化,修改了参数传入的数据对象数据。整体上就是前面两个函数的逻辑结合,在客服端到服务端一次序列化和反序列化操作,从服务端回到客户端也是一次序列化和反序列化操作。

MethodObject getObjectMethod()

前面函数都是没有带返回值的,这个函数是无参带返回值。

//客户端Proxy类
@Override public com.zhukai.aidlservice.MethodObject getObjectMethod() throws android.os.RemoteException
{
  //序列化操作对象Parcel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  com.zhukai.aidlservice.MethodObject _result;
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入描述符
    boolean _status = mRemote.transact(Stub.TRANSACTION_getObjectMethod, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态
    if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      return getDefaultImpl().getObjectMethod();//调用默认实现
    }
    _reply.readException();//读取服务端执行是否有异常
    if ((0!=_reply.readInt())) {//服务端有写入0或1,非0代表序列化对象不为null
      _result = com.zhukai.aidlservice.MethodObject.CREATOR.createFromParcel(_reply);//进行反序列化
    }
    else {
      _result = null;
    }
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
  return _result;//返回数据对象
}
//服务端Stub类
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR; 
    switch (code) {
        case TRANSACTION_getObjectMethod:
        {
          data.enforceInterface(descriptor);//进行描述符校验
          com.zhukai.aidlservice.MethodObject _result = this.getObjectMethod();//调用自己的函数活的数据对象。
          reply.writeNoException();//写入无异常
          if ((_result!=null)) {//数据对象不为null
              reply.writeInt(1);//写入1,标识序列化数据对象不为null
              _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//进行序列化操作
          }
          else {
            reply.writeInt(0);//写入0,标识序列化数据对象为null
          }
          return true;
        }
    }
}

MethodObject getObjectMethod()和setObjectMethodOut(out MethodObject o)函数在逻辑上有些相似,差异是客户端在对服务端写入的序列化对象进行反序列化处理时,因为setObjectMethodOut(out MethodObject o)函数原本参数中就有一个数据对象,所以直接调用了数据对象的readFromParcel()函数,通过反序列化修改了数据对象的数据;而MethodObject getObjectMethod()函数,则是要通过调用createFromParcel()函数,反序列化重新创建一个对象。但两者在实现效果上都是一样的。

register(CallBackAIDLInterface aidl)

//客户端Proxy类
@Override public void register(com.zhukai.aidlservice.CallBackAIDLInterface aidl) throws android.os.RemoteException
{
  //序列化操作对象Parcel准备
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);//写入操作符
    _data.writeStrongBinder((((aidl!=null))?(aidl.asBinder()):(null)));//写入AIDl类的Binder对象
    boolean _status = mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0);//通过Binder调用服务端onTransact()函数,客户端进入阻塞状态
    if (!_status && getDefaultImpl() != null) {//返回false,代表Binder通信失败,反之成功。
      getDefaultImpl().register(aidl);//调用默认实现
      return;
    }
    _reply.readException();//读取服务端操作有无异常
  }
  finally {//释放序列化操作对象
    _reply.recycle();
    _data.recycle();
  }
}
//服务端Stub类
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR; 
    switch (code) {
        case TRANSACTION_register:
        {
          data.enforceInterface(descriptor);//对描述符进行校验
          com.zhukai.aidlservice.CallBackAIDLInterface _arg0;
          //读取客户端传入的Binder对象并通过Stub.asInterface()函数获取了Proxy代理对象
          _arg0 = com.zhukai.aidlservice.CallBackAIDLInterface.Stub.asInterface(data.readStrongBinder());
          this.register(_arg0);//调用自己的方法,传入代理对象
          reply.writeNoException();//写入无异常
          return true;
        }
    }
}

register(CallBackAIDLInterface aidl)函数参数是AIDL类类型,在实际的逻辑中并不是传入的本身,而是传入了自己的Binder对象(既客户端创建的Stub对象的Binder对象,此时客户端在角色上变成了服务端)。服务端读取了传入的Binder对象后,通过Stub.asInterface(data.readStrongBinder())函数完成了Proxy代理对象的获取(此时服务端在角色上变成了客户端),再调用自己的函数,把这个代理对象给服务端使用。

unregister(CallBackAIDLInterface aidl)函数不需要做额外的讲解,跟register(CallBackAIDLInterface aidl)是一样的。

四、总结

看完这个系列,希望能让大家对AIDL有一个较深入的理解,篇幅较长,十分感谢大家能耐心看完!欢迎关注点赞,继续阅读AIDL系列文章,后续将努力学习输出更高质量文章。