Android AIDL 讲解

一步一步的,带着疑问,用示例讲解aidl文件。

创建生成aidl文件

路径:src/main/aidl/com/example/aidl/IMyAidlInterface.aidl

package com.example.aidl;

interface IMyAidlInterface {
    void test(in int a);
}

编译生成java文件:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /media/fukaiqiang/Disk960/AndroidProject/Test_AIDL/app/src/main/aidl/com/example/aidl/IMyAidlInterface.aidl
 */
package com.example.aidl;

public interface IMyAidlInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.aidl.IMyAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.example.aidl.IMyAidlInterface";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.aidl.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.example.aidl.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.aidl.IMyAidlInterface))) {
                return ((com.example.aidl.IMyAidlInterface) iin);
            }
            return new com.example.aidl.IMyAidlInterface.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_test: {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _result = this.test(_arg0);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.example.aidl.IMyAidlInterface {
            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 test(int a) 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(a);
                    mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

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

    public int test(int a) throws android.os.RemoteException;
}

结构分析

package com.example.aidl;

public interface IMyAidlInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.aidl.IMyAidlInterface {
    }

    public void test(int a) throws android.os.RemoteException; 
}
  1. aidl生成的java文件依然是一个接口文件,它继承了android.os.IInterface,并创建了一个名为Stub的内部抽象类,原来的test方法抛出一个RemoteException异常。
  2. 先看IInterface的接口文件,内容如下:
package android.os;

/**
 * Base class for Binder interfaces.  When defining a new interface,
 * you must derive it from IInterface.
 */
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

通过注释了解到,当创建一个新的aidl接口文件的时候,你就需要继承IInterface,并让与IMyAidlInterface关联的Binder对象所在类实现asBinder方法,并返回this,即返回这个Binder对象。所以一个普通类如果实现IMyAidlInterface,需要实现两个方法,一个方法是test,一个方法是asBinder,asBinder这个时候返回null即可,因为根本不需要通过binder进行通信;如果一个继承了Binder的类实现IMyAidlInterface,同样需要实现上面两个方法,而且asBinder需要返回这个Binder对象。
普通类:

public class TestAidl implements IMyAidlInterface{
    @Override
    public void test(int a) throws RemoteException {

    }
    @Override
    public IBinder asBinder() {
        return null;
    }
}

继承了Binder的类

class InterTestAild extends Binder implements IMyAidlInterface{
    @Override
    public void test(int a) throws RemoteException {

    }
    @Override
    public IBinder asBinder() {
        return this;
    }
}
  1. 现在看内部抽象类Stub(强调Stub是一个抽象类,必须由其他类继承使用),这个类继承了Binder,并实现了IMyAidlInterface接口,为了更加方便的看清内部类的结构,截图如下:

    让我们分析下内部类的结构:
    首先:定义了一个静态常量DESCRIPTOR,其值由包名加接口名组成。
    其次:在构造方法中调用了attachInterface方法,并传入了两个参数分别是this对象和静态常量DESCRIPTOR。这里的this对象指的是继承了Stub的类的对象。
    接着:定义了一个静态方法asInterface,其参数的类型是IBinder接口类型,即实参必须是实现了IBinder接口的对象。
    继续:如分析2,实现了接口IInterface的类,需要实现asBinder方法,并返回其对象this。
    然后:实现了onTransact方法,一共4个参数,分别是int类型的code,Parcel类型的data,Parcel类型的reply,int类型的flags。
    接着:定义了一个静态内部类Proxy,并实现了IMyAidlInterface接口。
    最后:定义一个静态常量TRANSACTION_test,其名称组成是TRANSACTION + 下划线 + 方法名,其值是常量FIRST_CALL_TRANSACTION + 0,FIRST_CALL_TRANSACTION = 0x00000001。

详细分析

首先看attachInterface方法。这里涉及到了this,所以需要改写下InterTestAild类,如下:

class InterTestAild extends IMyAidlInterface.Stub {
    @Override
    public void test(int a) throws RemoteException {

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

让InterTestAild由继承Binder,改为继承IMyAidlInterface.Stub。所以当创建InterTestAild对象的时候,就会调用IMyAidlInterface.Stub类的构造方法,并调用attachInterface方法。这里的this即InterTestAild对象。

    public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }

所以这里的mOwner = InterTestAild对象,mDescriptor即为常量DESCRIPTOR。
接着分析asInterface方法:

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

通过注释,了解到这个方法的作用:将接口IBinder类型转换为IMyAidlInterface接口,如果需要,创建IMyAidlInterface.Stub.Proxy类型的对象。大体逻辑,如果obj == null直接返回,如果iin == null,那就创建com.example.aidl.IMyAidlInterface.Stub.Proxy类的对象,否则强转为IMyAidlInterface类型。
核心的地方就是queryLocalInterface方法,它是在IBinder中定义的。这个时候你要注意了,用AndroidStudio做的跳转是错误的。如果你用AndroidStudio跳转,只会跳转到Binder类的queryLocalInterface方法。如下:

    /**
     * Use information supplied to attachInterface() to return the
     * associated IInterface if it matches the requested
     * descriptor.
     */
    public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
        if (mDescriptor != null && mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }

但其实不止Binder类实现了IBinder的queryLocalInterface方法,还有BinderProxy类也实现了IBinder的queryLocalInterface方法(我是怎么发现的,这个后面说)。

    /**
     * Retrieve a local interface - always null in case of a proxy
     */
    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }

通过注释你会发现BinderProxy中的queryLocalInterface总是会返回null。也就是说如果obj的类型是BinderProxy,那么会返回null,并创建com.example.aidl.IMyAidlInterface.Stub.Proxy类的对象,如果obj的类型是Binder,那么会返回attachInterface方法存储的继承了Binder类的对象(前面有说,这里不详细说)。所以关键就是obj到底是什么类型(后面会说何时是Binder类型,何时是BinderProxy类型)。
下面分析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_test: {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    this.test(_arg0);
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

看到这里,第一反应就是一个aidl接口的方法对应一个code,根据code调用这个方法,方法和code是一一对应的关系。以下是执行这个方法的地方。

 this.test(_arg0);

通过data和reply调用的方法,了解到从data中读取数据,把数据写入reply,即data用来传递数据过来,reply用来回调处理后的信息。
最后看Proxy内部类的内部类.

        private static class Proxy implements com.example.aidl.IMyAidlInterface {
            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 void test(int a) 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.writeInt(a);
                    mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

类Proxy也实现了IMyAidlInterface,自然也有一个test方法。再看构造函数,把传入的IBinder接口类型的对象存储到mRemote变量中。getInterfaceDescriptor方法返回DESCRIPTOR常量。test方法里面,定义了_data和_reply,并把数据写入到_data,从reply中读取数据,并调用了transact方法,注意它是IBinder中定义的,在Binder和BinderProxy中都有实现,所以mRemote是Binder类型,还是BinderProxy类型,调用的transact方法是有区别的,一共有4个参数,分别是code,data,reply,flags。看到这里,你会发现test中的工作和onTransact有关联,前者负责数据的发送,后者负责数据的读取和回调,前者负责回调的读取。也就是说执行Proxy的test方法,最终会调到Stub的onTransact方法。那Proxy的test方法何时执行呢?test方法执行,首先依赖Proxy对象的创建,那最终还是回到了asInterface方法。让我们用示例调试的方法看看。

示例进行信息挖掘

以Activity和Service进行数据传递的方式进行信息挖掘。

public class AidlService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new InterTestAild();
    }

    static class InterTestAild extends IMyAidlInterface.Stub {
        private static final String TAG = "InterTestAild";

        @Override
        public void test(int a) throws RemoteException {
            Log.d(TAG, "InterTestAild test a = " + a);
        }

        @Override
        public IBinder asBinder() {
            return this;
        }
    }
}
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: " + service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindService(new Intent(this,AidlService.class),mServiceConnection,BIND_AUTO_CREATE);
    }
        

创建AidlService,InterTestAild作为内部类存在。在Activity里面bindService,接收回调,获取 InterTestAild的类对象。看看这个时候对象的类型:

2022-06-13 14:39:06.199 29443-29443/com.example.aidl D/MainActivity: onServiceConnected: com.example.aidl.AidlService$InterTestAild@d9f0308

实现了IBinder接口的对象的类型是com.example.aidl.AidlService$InterTestAild,也就是说这个时候asInterface传入的类型是com.example.aidl.AidlService$InterTestAild。此时InterTestAild和activity是在同一个进程中。假如在不同的进程中呢?


2022-06-13 14:40:06.190 29638-29638/com.example.aidl D/MainActivity: onServiceConnected: android.os.BinderProxy@4c430ab

实现了IBinder接口的对象的类型是android.os.BinderProxy。也就说在同一个进程中,实现IBinder接口的对象的类型是"com.example.aidl.AidlService$InterTestAild",不同进程是android.os.BinderProxy。
所以这个时候我们就可以推断到asInterface方法的参数类型,当同一个进程的时候是com.example.aidl.AidlService$InterTestAild,不同进程的时候android.os.BinderProxy。进而推断出,不同进程的时候会创建com.example.aidl.IMyAidlInterface.Stub.Proxy的对象。再推断出,当相同进程的时候,调用test方法,会回调IMyAidlInterface接口类的test方法,当不同进程的时候,会调用Proxy的test方法。
所以调用test方法的代码,可以这样写,如下:
当在一个进程的时候:

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: " + service);
            //same process
            try {
                ((AidlService.InterTestAild)service).test(5);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

当在一个进程或者不同进程的时候:

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: " + service);
            //same process and different process
            try {
                IMyAidlInterface.Stub.asInterface(service).test(5);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

总结

  1. Stub是用来实现功能的类的父类,而Proxy是提供给外部进程进行功能调用的类。
  2. 我们把继承了Binder类的类成为Binder类,其对象成为Binder对象。
  3. 当我们需要创建一个Binder对象的时候,只需要让类继承Stub即可。
  4. 一个接口方法对应一个code,按顺序,从1开始排序。
  5. aidl 文件的存在其实就是为我们提供了不差别的访问binder对象的方法,让我们不用关心binder对象和获取动作是在一个进程,还是在不同的进程。
  6. binder进行数据的传递,需要binder对象,方法名,参数,异步还是同步4个要素。
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);

你现在再看看这段代码,是不是比之前要明白许多了!、
到此aidl的分析完毕。

建议:

学习binder,关注核心通信逻辑,忽视面向对象的业务逻辑,忽视术语(本地,远程,对端等等)。

你可能感兴趣的:(Android AIDL 讲解)