为了简化我们实现Binder进程间通信的繁琐步骤,系统提供了AIDL文件,编译通过即可生成对应的java文件。承接上篇文章Android进程间通信-AIDL的简单使用 ,这里手动实现aidl自动生成的aidl文件,便于我们进一步理解内部的一些逻辑。

实现步骤

1 定义一个IOperation接口,并在内部声明一个供客户端跨进程调用的方法,并使该接口继承IInterface接口。

public interface IOperation extends IInterface {

    /* Binder描述符 */
    static final String DESCRIPTOR = "com.example.aidlmanualtest.IOperation";

    /**
     * 方法标识符 :规定了最小和最大范围
     * 
     * The action to perform. This should be a number between
     * {@link #FIRST_CALL_TRANSACTION}
     * {@link #LAST_CALL_TRANSACTION}.
     * 
     * 这段说明是在IBiner的transact()方法中
     */

    static final int TRANSACTION_getSum = IBinder.FIRST_CALL_TRANSACTION + 0;
    // 定义了一个供跨进程调用的方法
    public double getSum(double first, double second) throws RemoteException;
}

2 跨进程方法调用的处理逻辑,主要集中在接口实现类Stub和Stub的代理Proxy类中

public class IOperationStub extends Binder implements IOperation {

    public IOperationStub() {
        /**
         * Convenience method for associating a specific interface with the
         * Binder. After calling, queryLocalInterface() will be implemented for
         * you to return the given owner IInterface when the corresponding
         * descriptor is requested.
         * 
         * 将一个IInterface类型的接口实例与Binder关联起来,DESCRIPTOR相当于一个标识。当该方法被调用后,
         * 可通过queryLocalInterface(DESCRIPTOR)获取与这个标识相应的接口实例
         */
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * 用于将服务端的Binder对象转换成客户端需要的AIDL接口类型的对象区分进程:
     * <p/>
     * 客户端和服务端处于同一进程:直接返回服务端的Stub对象
     * <p/>
     * 客户端和服务端处于不同进程:返回封装好的Stub.proxy对象
     * 
     * @param obj
     * @return
     */
    public static IOperation asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        /**
         * Attempt to retrieve a local implementation of an interface for this
         * Binder object. If null is returned, you will need to instantiate a
         * proxy class to marshall calls through the transact() method.
         * 
         * 尝试在本地检索实现了该接口的Binder对象实例
         */
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (iin != null && (iin instanceof IOperation)) {
            return ((IOperation) iin);
        }
        /**
         * 假如本地检索返回为null,需要手动生成一个proxy代理类,并在其中通过transact() 方法去处理请求
         */
        return new IOperationStub.Proxy(obj);
    }

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

    /**
     * 该方法运行在服务端,当客户端发起请求,会进入到该方法进行处理
     * <p/>
     * code:用于标识客户端请求调用的目标方法(即在IOperation中定义的方法标识符)
     * <p/>
     * data:当请求的目标方法含有参数时,该参数封装了请求的参数
     * <p/>
     * reply:当请求需要返回结果时,该参数封装了处理结果
     */
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        // 通过code区分不同的方法调用
        switch (code) {
        case INTERFACE_TRANSACTION:
            reply.writeString(DESCRIPTOR);
            return true;
        case TRANSACTION_getSum:
        /**
             * Read an IBinder interface token in the parcel at the current
             * {@link #dataPosition}. This is used to validate that the
             * marshalled transaction is intended for the target interface.
             */
            data.enforceInterface(DESCRIPTOR);
            // 通过data获取请求的参数
            double first = data.readDouble();
            double second = data.readDouble();
            double result = this.getSum(first, second);
            reply.writeNoException();
            // 将结果写入到reply中
            reply.writeDouble(result);
            return true;
        default:
            break;
        }
        return super.onTransact(code, data, reply, flags);
    }

    @Override
    public double getSum(double fisrt, double second) throws RemoteException {
        return 0;
    }

    private static class Proxy implements IOperation {

        private IBinder mRemote;

        Proxy(IBinder mRemote) {
            this.mRemote = mRemote;
        }

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

        public java.lang.String getInterfaceDescriptor() {
            return DESCRIPTOR;
        }

        @Override
        public double getSum(double fisrt, double second)
                throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            double result = 0;
            try {
                /**
                 * Store an IBinder interface token in the parcel at the current
                 * {@link #dataPosition}. This is used to validate that the
                 * marshalled transaction is intended for the target interface.
                 */
                data.writeInterfaceToken(DESCRIPTOR);
                // 将请求的参数写入到data中
                data.writeDouble(fisrt);
                data.writeDouble(second);
                // 调用transact()方法,发起跨进程请求,当前进程挂起
                mRemote.transact(TRANSACTION_getSum, data, reply, 0);
                // 从reply中获取返回的结果
                reply.readException();
                result = reply.readDouble();
            } catch (Exception e) {
            } finally {
                data.recycle();
                reply.recycle();
            }
            return result;
        }
    }

}

总结

总体逻辑:

1 客户端调用getSum()方法
2 将该方法需要的传递的参数写入到data中
3 调用transact()方法发起跨进程请求
4 服务端的onTransact()的方法被调用,客户端的进程被挂起
5 服务端返回结果,从reply中取出结果,并返回