Android进程间通信之AIDL(二)—— 源码简要分析

上一篇我们了解到了如何书写AIDL让客户端和服务端通信,那么接下来我将简单介绍一下其工作原理:

1、首先我们创建一个AIDLAnalysisInterface.aidl文件

// AIDLAnalysisInterface.aidl
package com.zui.lib;

import com.zui.lib.data.Worker;

interface AIDLAnalysisInterface {
    void analyze(in Worker worker_in, out Worker worker_out, inout Worker worker_inout);
}

对于定义的aidl文件,android studio会自动的生成一个相同文件名的java文件,如下图

Android进程间通信之AIDL(二)—— 源码简要分析

接下来我们来看看studio生成的AIDLAnalysisInterface.java的内容

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\github\\android\\practice_project\\AIDL\\app\\src\\main\\aidl\\com\\zui\\lib\\AIDLAnalysisInterface.aidl
 */
package com.zui.lib;

/**AIDLAnalysisInterface类由一个静态抽象类Stub和我们定义的analyze()接口组成 */
public interface AIDLAnalysisInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.zui.lib.AIDLAnalysisInterface {   //Stub类名是永远固定的写法,我们在服务端service里面实现的也就是这个内部类
        private static final java.lang.String DESCRIPTOR = "com.zui.lib.AIDLAnalysisInterface";          // 标识,也就是AIDLAnalysisInterface的包名 + 类名

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

        /**
         * Cast an IBinder object into an com.zui.lib.AIDLAnalysisInterface interface,
         * generating a proxy if needed.
         */

         //此方法就是返回此Stub对象或者Stub对象的代理,我们在客户端成功绑定service后,在onServiceConnect中会调用到此方法:
         // mAIDLAnalysisInterface = AIDLAnalysisInterface.Stub.asInterface(service)
        public static com.zui.lib.AIDLAnalysisInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.zui.lib.AIDLAnalysisInterface))) {    /** 进程内通信的话就会返回自身 */
                return ((com.zui.lib.AIDLAnalysisInterface) iin);
            }
            return new com.zui.lib.AIDLAnalysisInterface.Stub.Proxy(obj);            /**  进程间通信的话返回Stub的代理Stub.Proxy */
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }           /** 返回当前Stub对象 */

        /**
         *  此方法只有在跨进程通信的时候才会用到,onTransact 这个方法 就是运行在Binder线程池中的,一般就是客户端发起请求,然后android底层代码把这个客户端发起的请求 封装成3个参数 来调用这个onTransact方法,
         * @param code 表示请求的是哪个方法,用int类型的值标识服务端定义的接口
         * @param data  客户端请求的所有参数会被封装成data输入对象
         * @param reply 客户端请求方法的输出对象,与data相对应
         * @param flags  一般都是0
         * @return 一般返回值为ture,如果返回false了,就说明执行失败了
         * @throws android.os.RemoteException
         */
        @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_analyze: {     /** 客户端调用我们定义的AIDL接口 void analyze(in Worker worker_in, out Worker worker_out, inout Worker worker_inout)时,会进此case*/
                    data.enforceInterface(DESCRIPTOR);
                    com.zui.lib.data.Worker _arg0;         /** _arg0第一个参数也就是对应的 worker_in参数 */
                    if ((0 != data.readInt())) {
                        _arg0 = com.zui.lib.data.Worker.CREATOR.createFromParcel(data);  /** 从data流里读传入的worker_in参数信息,这里可以看到定向tag为in时,客户端会将参数对象的完整信息传入服务端 */
                    } else {
                        _arg0 = null;
                    }
                    com.zui.lib.data.Worker _arg1;          /** _arg1 对应的worker_out参数 */
                    _arg1 = new com.zui.lib.data.Worker(); /** 创建新对象,可以看出参数的定向tag为out时,客户端并没有将worker_out的完整信息传入服务端,而是新建一个worker_out类型的对象*/
                    com.zui.lib.data.Worker _arg2; /** _arg2 对应的worker_inout参数 */
                    if ((0 != data.readInt())) {
                        _arg2 = com.zui.lib.data.Worker.CREATOR.createFromParcel(data);  /** 参数定向tag为inout时,同样也会从data流中读入传参信息*/
                    } else {
                        _arg2 = null;
                    }
                    this.analyze(_arg0, _arg1, _arg2);      /** 这里开始执行真正的逻辑,调用服务端的具体实现 */
                    reply.writeNoException();               /** reply 是执行服务端执行具体逻辑后的输出,对于客户端传入参数的修改都会封装在reply对象中*/
                    if ((_arg1 != null)) {                  /** _arg1 的定向tag为out,表示客户端会同步服务端的修改,也就是说服务端如果修改了worker_out,客户端也会体现出来 */
                        reply.writeInt(1);
                        _arg1.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }
                    if ((_arg2 != null)) {          /** _arg2的定向tag为inout,表示客户端传入的worker_inout参数也会同步服务端对它的的修改 */
                        reply.writeInt(1);
                        _arg2.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }                                /** 这里并没有从输出流reply对象里面读_arg0参数信息,说明定向tag为in的参数,客户端并不会同步服务端对它的修改 */
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.zui.lib.AIDLAnalysisInterface {          /**  跨进程通信会返回此代理对象 */
            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 analyze(com.zui.lib.data.Worker worker_in, com.zui.lib.data.Worker worker_out, com.zui.lib.data.Worker worker_inout) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();       /**  这里一进来就创建两个对象_data 和 _reply */
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((worker_in != null)) {
                        _data.writeInt(1);                          /**  定向tag为in 和 inout的参数,会被写入data流中 */
                        worker_in.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    if ((worker_inout != null)) {
                        _data.writeInt(1);
                        worker_inout.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_analyze, _data, _reply, 0);   /** 调用了transact这个方法 来发送rpc请求,当前线程会被挂起,服务端的onTransace方法被调用(跨进程的情况),调用结束以后 当前线程继续执行,直到从_reply中取出rpc的返回结果 然后返回_reply的数据 */
                    _reply.readException();
                    if ((0 != _reply.readInt())) {                  /**  定向tag为out 和 inout的参数,服务端对他们的修改会被写入reply流中,客户端通过此reply对象同步服务端的修改 */
                        worker_out.readFromParcel(_reply);
                    }
                    if ((0 != _reply.readInt())) {
                        worker_inout.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();           /**  回收 _reply 和 _data 对象*/
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_analyze = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);     /**  给不同的方法定义的标识*/
    }

    public void analyze(com.zui.lib.data.Worker worker_in, com.zui.lib.data.Worker worker_out, com.zui.lib.data.Worker worker_inout) throws android.os.RemoteException;
}

简单总结一下就是:客户端成功绑定service后,获取到服务端的实现的Stub对象,然后客户端可以调用服务端的接口时,首先会创建_data 输入对象,_reply输出对象,然后将客户端传入的参数封装到_data中,接着调用transact()方法,如果是跨进程通信,此时服务端的onTransace()方法会被调用,当调用结束后,会从_reply中取出rpc的返回结果 然后同步_reply的数据。

同时,通过对源码分析,可以看出AIDL传参数的定向tag:in、out、inout的具体含义以及它们之间的区别。

以上就是aidl源码的大致分析