Android AIDL

作者: 星空下奔跑 | 来源:发表于2018-04-16 20:32 被阅读0次

通过此文记录以下自己在使用AIDL时的一些理解。
在Android Studio中首先定义.aidl文件:

package com.github.androidfdm.service.aidl;

interface ISampleAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    String sample(int str);
}

紧接着Make Project,AS会自动生成对应的AIDL类文件:

package com.github.androidfdm.service.aidl;


public interface ISampleAidlInterface extends android.os.IInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;

    public java.lang.String sample(int str) throws android.os.RemoteException;

    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.github.androidfdm.service.aidl.ISampleAidlInterface {
        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_sample = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        private static final java.lang.String DESCRIPTOR = "com.github.androidfdm.service.aidl.ISampleAidlInterface";

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

        /**
         * Cast an IBinder object into an com.github.androidfdm.service.aidl.ISampleAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.github.androidfdm.service.aidl.ISampleAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.github.androidfdm.service.aidl.ISampleAidlInterface))) {
                return ((com.github.androidfdm.service.aidl.ISampleAidlInterface) iin);
            }
            return new com.github.androidfdm.service.aidl.ISampleAidlInterface.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 {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_basicTypes: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_sample: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    java.lang.String _result = this.sample(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.github.androidfdm.service.aidl.ISampleAidlInterface {
            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 basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.lang.String sample(int str) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(str);
                    mRemote.transact(Stub.TRANSACTION_sample, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
    }
}
注意到,生成的类(.java)文件中包含了我们在.aidl文件中定义的方法。附带的还生成了两个内部的静态类。一个是Stub(抽象类),该内部静态类继承自Binder类,并且实现了我们定义的.aidl文件中的接口。

另一个是Proxy,其构造函数接收一个Stub对象并是实现了.aidl文件中的接口,并实现了其中的方法。拿sample(int str)函数来说,这个实现从代码中可以看出obtain了两个Parcel:_data和_reply分别用来传递参数和返回值。之后将接收到的参数写进_data这个Parcel紧接着调用Stub的transact方法。再回到Stub中,transact方法最终会调用到Stub中的onTransact方法,通过第一个参数来区分我们具体调用的哪个方法。然后onTransact方法会从刚刚的_data中读取出来数据调用本身的sample(int str)方法,然后将返回值写到_reply中。再回到Proxy中,调用完Stub(mRemote)中的对应方法后,从_reply中读取到返回值然后返回。整个调用过程就是如此。

但目前还有些不解的是,在Proxy(client)中调用的函数是如何在Service(server)中执行的,从上面的过程来看Proxy只是传递了参数到Parcel中,便可以调用Binder的transact方法让server执行相应的函数?答:通过系统调用调用到binder驱动的transact()函数,然后又通过某种消息机制调用server的onTransact()

接着上面的步骤,再定义个Service,并在manifast文件中指定其android:process属性.

public class SampleAidlService extends SampleService {

    private ISampleAidlInterface.Stub aidlBinder = new ISampleAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            L.e(this.getClass().getSimpleName(), "Im aidl binder!");
        }

        @Override
        public String sample(int str) throws RemoteException {
            switch (str) {
                case 0:
                    return "Im aidl binder!";
                default:
                    return null;
            }
        }
        @Override
        public String toString() {
            return "Im aidl binder!";
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        L.e(this.getClass().getSimpleName(), "onBind AIDL");
        return aidlBinder;
    }
}

可以看到,我们在OnBind()方法中返回的是那个叫做Stub(extends Binder)的抽象内部类的对象!
之后在ServiceConnection中获取返回的Binder:

aidlConn = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    ISampleAidlInterface binder = ISampleAidlInterface.Stub.asInterface(service);

                    try {
                        L.e(MainActivity.this.getClass().getSimpleName(), binder.sample(0));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {

                }
            };

然后就可以利用这个代理类的对象愉快的进行通信了。

相关文章

网友评论

    本文标题:Android AIDL

    本文链接:https://www.haomeiwen.com/subject/uptykftx.html