AIDL生成的java文件分析

作者: 黑猫警长_01 | 来源:发表于2018-03-02 16:36 被阅读31次

    aidl生成的java代码是一个接口文件,这个接口继承了android.os.IInterface,这个接口生成的java文件中一共包括两个部分:
    1、静态内部抽象类Stub
    2、声明了具体的功能的抽象方法(aidl文件中声明的方法)
    如图:


    1.png

    看来这个类的重点就是在Stub中了,主要来分析一下Stub类。文字不够,图片来凑:


    2.png 3.png

    从图中可以看到,Stub中一共分为以下几个部分:
    一、构造方法

       /**
         * Construct the stub at attach it to the interface.
         * 构造方法
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
         //binder中的方法
        public void attachInterface(IInterface owner, String descriptor) {
           mOwner = owner;
           mDescriptor = descriptor;
        }
    

    构造方法中调用了binder中的attachInterface(IInterface owner, String descriptor)方法,其中descriptor可以看做是进程的唯一标识,IInterface c参数则把Stub自己传了进去,这个在后面asInterface()方法中会用到。

    二、asInterface(android.os.IBinder obj)方法。这个方法是在绑定服务成功后客户端调用的,用于在获取到服务端返回的IBInder对象后,将其转换为对应的具有功能方法的对象,毕竟IBinder只是一个具有跨进程传输的接口。(类似是把一个接口转换成它对应的实现类,可以这么理解,但并不是这样的)

    /**
         * Cast an IBinder object into an com.example.aidldemo2.OperateInterface interface,
         * generating a proxy if needed.
         * 根据服务返回的IBinder返回所需要具有相应的功能方法的实体类
         */
        public static com.example.aidldemo2.OperateInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            //检查传过来的binder是否和现在的进程是同一进程,如果是,返回值不为null
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.aidldemo2.OperateInterface))) {
                return ((com.example.aidldemo2.OperateInterface) iin);
            }
            //不是同一进程,返回stub的poxy
            return new com.example.aidldemo2.OperateInterface.Stub.Proxy(obj);
        }
    

    主要做了一件事,根据 android.os.IInterface iin = queryLocalInterface (DESCRIPTOR) 得到的结果返回不同的值。如果iin不空就返回iin,否则就返回Stub的一个代理类。看一下queryLocalInterface (DESCRIPTOR) 具体做了什么操作:

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

    如果(mDescriptor.equals(descriptor)) 为true,就返回mOwner。表示如果在同一进程中,就返回mOwner,不在同一进程中就返回null。这个mOwner是谁呢,就是在Stub类在构造方法里面传进来的this。
    public Stub() {
    this.attachInterface(this, DESCRIPTOR);
    }
    //binder中的方法
    public void attachInterface(IInterface owner, String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
    }
    总之,这个方法的作用就是binder和现在的进程是同一进程,就返回Stub类,否则返回Stub的代理类Proxy类。至于Proxy,下面分析。

    三、Stub的内部类Proxy类。

     //Stub的代理类,代理类只有在跨进程的时候用到。实现了接口,具有了相应的功能方法
      private static class Proxy implements com.example.aidldemo2.OperateInterface {
            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 add(int a, int b) throws android.os.RemoteException {
                //把数据放到了Parcel中存储
                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);
                    _data.writeInt(b);
                    //把数据传递给远程的服务
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    //获取到远程服务执行的结果
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
    

    代理类实现了功能方法的接口,这样就保证了和Stub类具有了相同的功能,只有这样才能代理Stub行使相同的功能。主要看里面方法的实现,这这个例子中,实现了add方法但是并没有真正的去做add方法的业务功能,而是把参数封装到了Parcel 中通过binder传递给了远程的服务。可以看出绑定远程服务后,要调用远程服务的方法是通过执行这个代理类中的对应方法,该方法再通过 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0)把数据传递到远程服务,等远程服务执行完后再通过代理 _result = _reply.readInt();获取到结果返回给我们的程序的。其中Stub.TRANSACTION_add是这个方法的唯一标识,是告诉远程进程我要调用哪个方法。
    总结起来这个代理类就是负责本地进程和远程进程之间的数据封装和传递(调用binder传递数据)以及解析结果的。

    四、Stub中的onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)方法。这个方法作为服务端的方法,负责接收远程客户端通过 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);发送过来的数据并处理的。

    //接收通过跨进程传递过来的数据(包括调用的方法对应的code、方法参数)
        @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_add: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    

    这个方法的参数和上面提到的代理发送数据 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0)的参数一一对应,code指对应的要调用的add方法的唯一标识,data里面存放着要执行的add方法需要的参数,reply用来存储add方法执行完后要返回的结果。

    到这里aidl生成的java文件就分析完了,总结一下就是,整个文件的核心就是静态内部抽象类Stub。Stub中包含了一下几项内容:
    1、asInterface(android.os.IBinder obj) 用来根据不同进程返回Stub类自己还是Proxy代理类
    2、代理类proxy 用来向远程进程包装数据、发送数据、解析返回结果
    3、onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)方法 作为服务端进程调用,用来处理客户端进程传递过来的数据
    4、接口的功能方法,Stub继承了接口,这些方法用来处理客户端进程的具体业务。

    相关文章

      网友评论

        本文标题:AIDL生成的java文件分析

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