AIDL(Android Interface Defination Language),Android接口定义语言。是Google专门为Android中跨进程调用服务所设计的一种接口语言。
其本质是Android中特有的一种IPC机制:Binder机制。通过对AIDL的分析我们也可以对Binder机制有所了解

AIDL的使用

首先让我们简单回顾一下AIDL是如何使用的。下面的操作基于Android Studio。

  • 创建AIDL文件
    在Project视图下,在/src/main/下创建与java同级的aidl文件夹,并在该文件夹下创建包名(例:com.example.diov.testaidl),在该文件夹下创建AIDL文件
package com.example.diov.testaidl;

interface TestAidl {
    void add(int i);
}

在这个接口文件中定义Service需要实现的方法。

  • 实现AIDL中的方法
    创建完AIDL文件后,通过Gradle编译。编译成功后可以在/generated/source/debug/{packagename}/下找到生成的TestAidl.java文件。
    然后我们回到Service中,实现AIDL接口中定义的方法
public class IRemoteService extends Service{

  // 绑定服务时将IBinder对象返回出去
  @Override
  public IBinder onBind(Intent intent){
    return iBinder;
  }

  private IBinder iBinder = new TestAidl.Stub(){

    @Override
    public int add(int i, int j) throws RemoteException {
      // 具体实现
      return i + j;
    }
  }
}
  • 调用AIDL
    在Client里按照第一步,把相同的AIDL文件创建出来。
    绑定Service需要调用bindService(Intent intent, ServiceConnection conn, int flag)方法。
    这里主要是实现ServiceConnection接口,在这个接口的回调方法中就可以得到对应的服务所提供IBinder对象了
private TestAidl aidl;
private ServiceConnection conn = new ServiceConnection{
  // 绑定成功时回调
  @Override
  public void onServiceConnected(ComponentName name, IBinder service){
    // 获取到了远程服务
    aidl = TestAidl.Stub.asInterface(service);
  }

  // 解除绑定时回调
  @Override
  public void onServiceDisconnected(ComponentName name){
    aidl = null;
  }
}

获取到IBinder对象后,就可以实现IPC,调用远程服务了。

AIDL的实现原理

现在来看看AS自动帮我们生成的TestAdil.java这个文件

package com.example.diov.testaidl;

public interface TestAidl extends android.os.IInterface {
    /**
     * 存根类,实现了Binder和TestAidl接口(IInterface接口)
     */
    public static abstract class Stub extends android.os.Binder implements com.example.dio_v.materialdemo.TestAidl {
        private static final java.lang.String DESCRIPTOR = "com.example.dio_v.materialdemo.TestAidl";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * 将IBinder对象转换成com.example.diov.testaidl.TestAidl接口,
         * 如果需要的话生成一个代理.
         */
        public static com.example.dio_v.materialdemo.TestAidl asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.dio_v.materialdemo.TestAidl))) {
                return ((com.example.dio_v.materialdemo.TestAidl) iin);
            }
            return new com.example.dio_v.materialdemo.TestAidl.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        // 当Client调用Service时,获取代理类发送过来的数据
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws
                android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_add: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();

                    // 通过子类来实现方法中具体的操作,并将结果通过reply对象返回出去
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        // 代理类,实现了TestAidl接口(IInterface接口)
        private static class Proxy implements com.example.dio_v.materialdemo.TestAidl {
            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;
            }

            @Override
            public int add(int i, int j) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    // 通过序列化将参数发送
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(i);
                    _data.writeInt(j);

                    // 通过Framework将序列化后的参数发送给IBinder对象
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();

                    // 通过返回的reply将Service返回的结果解析出来
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    // 接口中的方法
    public int add(int i, int j) throws android.os.RemoteException;
}
  1. 在Client中绑定Service,会通过TestAdil.Stub.asInterface()方法去转换返回的IBinder对象(Stub继承的Binder类是IBinder接口的实现类),得到的是一个Proxy类对象
  2. Proxy类将参数序列化之后,通过Framework将参数发送给Service.onBind()返回的IBinder对象
  3. Service中返回的IBinder对象(Stub对象),通过具体实现来完成对参数的操作,并且将返回值封装在一个Parcel对象中
  4. Framework层将封装后的Parcel对象再返回给Proxy对象
  5. Proxy对象从Parcel对象中获取返回值

Binder机制

其实在Binder机制中存在一个重要的角色,ServiceManager,他是Service和Client中IPC交互的重要一环。ServiceManager负责在Framework层将参数传递、返回Proxy对象等等

而在Client,并不是真正持有了Service中的对象,而是通过ServiceManager,借助Proxy对象来完成跨进程通信。所以说Binder机制使用的其实就是/代理模式/。

对于Binder机制,我也还只是对概念有初步的了解。想要深入了解Binder机制,还需要继续学习。


资料推荐:

  1. Binder设计与实现
  2. Android进程间通信(IPC)机制Binder简要介绍和学习计划