Android中AIDL的理解

首先定义

// IMyService.aidl
package com.devtom.myservice;

interface IMyService {
    void printLog(String message);
}

定义完成了之后,编译工具会自动帮我们生成接口相关的文件。
生成的代码文件如下

package com.devtom.myservice;

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

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

        /**
         * Cast an IBinder object into an com.devtom.myservice.IMyService interface,
         * generating a proxy if needed.
         */
        public static com.devtom.myservice.IMyService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.devtom.myservice.IMyService))) {
                return ((com.devtom.myservice.IMyService) iin);
            }
            return new com.devtom.myservice.IMyService.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_printLog: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.printLog(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.devtom.myservice.IMyService {
            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 printLog(java.lang.String message) 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(message);
                    mRemote.transact(Stub.TRANSACTION_printLog, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

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

    public void printLog(java.lang.String message) throws android.os.RemoteException;
}

再来看看service相关的实现

public class MyRemoteService extends Service {

    private static final String TAG = "MyRemoteService";

    public static class MyServiceBinder extends IMyService.Stub {
        @Override
        public void printLog(String message) throws RemoteException {
            Log.e(TAG, "this is message from remote " + message);
        }
    }

    private MyServiceBinder binder;

    @Override
    public void onCreate() {
        super.onCreate();
        binder = new MyServiceBinder();
    }

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

客户端调用的代码如下

public class MainActivity extends Activity {

    private IMyService binder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, MyRemoteService.class);
        bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
        this.findViewById(R.id.test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    binder.printLog("this is message from client");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binder = MyRemoteService.MyServiceBinder.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            binder = null;
        }
    };
}

目前按照个人理解

  1. MainActivity当中通过ServiceConnect 拿到的对象实际上是IMyService 当中的Proxy 对象的引用,之所以会有这个代理对象的存在,目前的理解是,系统为了方便我们调用,通过这个代理对象完成了调用远程服务数据的封装,所以我们在Proxy当中可以看到代理对printLog的实现:

    @Override
    public void printLog(java.lang.String message) 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(message);
            mRemote.transact(Stub.TRANSACTION_printLog, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }
    

在Proxy的实现中,主要是完成了对数据的封装,并没有实现其他的逻辑,完成数据的封装之后,然后调用了 mRemote的transact方法。

  1. Proxy 中成员变量 mRemote 所指向的对象是 IMyService.Stub ,因为Stub 是一个抽象类,所以最终mRemote指向的实例也就是IMyService.Stub 的实现类了

     @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_printLog: {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _arg0;
                _arg0 = data.readString();
                this.printLog(_arg0);
                reply.writeNoException();
                return true;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }
    

    在onTransact 方法当中实现了对数据的解析,将获取到的数据传给自己定义的方法当中去,最终调用了自己实现的方法。

3.通过这个例子,最重要的还是里面的Binder, 数据的传递,解析都是Binder这个对象来完成的。

知道AIDL 的套路之后,可以自己手写一个实现。

public class MyServiceBinderImpl extends Binder implements MyServiceInterface, IInterface{

    public static final String TAG  = "MyServiceBinderImpl";

    public static final String DESCRIPTOR = "com.devtom.myservice.MyServiceBinderImpl";

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION:
                reply.writeString(DESCRIPTOR);
                break;
            case Binder.FIRST_CALL_TRANSACTION + 0:
                data.enforceInterface(DESCRIPTOR);
                String strData = data.readString();
                printLog(strData);
                reply.writeNoException();
                break;
        }
        return super.onTransact(code, data, reply, flags);
    }

    @Override
    public void printLog(String message) {
        Log.e(TAG, "this message is " + message);
    }

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

这个实际上就是自己动手去解析数据。

调用了也很简单 ,

android.os.Parcel _data = android.os.Parcel.obtain();
           android.os.Parcel _reply = android.os.Parcel.obtain();
           try {
               _data.writeInterfaceToken(MyServiceBinderImpl.DESCRIPTOR);
               _data.writeString("this my own aidl implement");
               binder.transact(IMyService.Stub.TRANSACTION_printLog, _data, _reply, 0);
               _reply.readException();
           } catch (RemoteException e) {

           } finally {
               _reply.recycle();
               _data.recycle();
           }

此处的binder对象就是从ServiceConnection的onServiceConnected 方法参数中获取的,因为我们去掉了代理帮帮我们封装数据,所以这里就只能自己手动的去封装数据了。

其实从上面自己手动实现AIDL 的功能可以看出,我们新建的service只是为了方便我们自己调用,我们完全可以去掉了这些方法(printLog)在onTrasaction里面来实现各种功能,当然这个只是扯淡。