美文网首页Android学习之旅Android开发经验谈Android技术知识
Android学习之旅-使用 AIDL 实现进程间通信02[艺术

Android学习之旅-使用 AIDL 实现进程间通信02[艺术

作者: TengFeiGo | 来源:发表于2018-12-08 16:57 被阅读10次

    本篇文章将着重于分析 AIDL 是如何通过 Binder 来实现进程间通信的,当然只是分析它的上层应用,不然 Binder 让我现在的能力去看绝对是云里雾里,没多大价值,倒不如退而求其次,毕竟学习需要一步一步的来,而且前面的两篇文章也是这周学习完 IPC 机制后利用空余时间来一次实践总结,我计划在每周学习完一个专题的内容后都去总结一遍,一步一步的提示自身的开发能力。
    好了,通过上篇文章我们知道 AIDL 其实就是帮助我们来实现进程间通信的一个工具,新建完 AIDL 文件重新 rebuild 之后在 AS 的 build 文件夹下会自动生成 java 代码,其实就是协助我们进行跨进程通信的,你可以理解为 AIDL 是在 binder 的基础上进行了一次封装,方便了我们的开发者,👌下面看代码:

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: /Users/tengfei/AndroidStudy/Android-HotYong/01_AndroidCrossProcess/client/src/main/aidl/com/example/tengfei/aidl/IBookManager.aidl
     */
    package com.example.tengfei.aidl;
    
    public interface IBookManager extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.example.tengfei.aidl.IBookManager {
            private static final java.lang.String DESCRIPTOR = "com.example.tengfei.aidl.IBookManager";
    
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.example.tengfei.aidl.IBookManager interface,
             * generating a proxy if needed.
             */
            public static com.example.tengfei.aidl.IBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.example.tengfei.aidl.IBookManager))) {
                    return ((com.example.tengfei.aidl.IBookManager) iin);
                }
                return new com.example.tengfei.aidl.IBookManager.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 {
                java.lang.String descriptor = DESCRIPTOR;
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(descriptor);
                        return true;
                    }
                    case TRANSACTION_getBookList: {
                        data.enforceInterface(descriptor);
                        java.util.List<com.example.tengfei.aidl.Book> _result = this.getBookList();
                        reply.writeNoException();
                        reply.writeTypedList(_result);
                        return true;
                    }
                    case TRANSACTION_addBook: {
                        data.enforceInterface(descriptor);
                        com.example.tengfei.aidl.Book _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = com.example.tengfei.aidl.Book.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        this.addBook(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                    default: {
                        return super.onTransact(code, data, reply, flags);
                    }
                }
            }
    
            private static class Proxy implements com.example.tengfei.aidl.IBookManager {
                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 java.util.List<com.example.tengfei.aidl.Book> getBookList() throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    java.util.List<com.example.tengfei.aidl.Book> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.createTypedArrayList(com.example.tengfei.aidl.Book.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public void addBook(com.example.tengfei.aidl.Book book) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        if ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
            static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        public java.util.List<com.example.tengfei.aidl.Book> getBookList() throws android.os.RemoteException;
    
        public void addBook(com.example.tengfei.aidl.Book book) throws android.os.RemoteException;
    }
    
    
    

    代码很多,但其实整体结构上还是很清晰的,首先是一个接口 IBookManager 继承了 IInterface ,在接口内部定义了两个方法 getBookList() 和 addBook(com.example.tengfei.aidl.Book book) 只有继承了 IInterface 的接口才可以通过 binder 传递,在其内部定义了一个静态抽象类 Stub 继承自 Binder 并且实现了 IBookManager 接口,所以说 IBookManager.java
    这个类的核心就是 Stub 类,下面让我们来具体看一下 Stub 的内部结构。

    1. DESCRIPTOR : 给继承自 binder 的 stub 类定义一个唯一的标记,一般用当前的类名来表示,在 Stub 的构造方法中 调用 binder 的 attachInterface 并将当前定义的 DESCRIPTOR 传递进参数中,其作用是为了将特定接口与 binder 关联
    2. TRANSACTION_getBookList : 一个 int 整型值用来标记 getBookList 方法
    3. TRANSACTION_addBook : 一个 int 整型值用来标记 addBook 方法
    4. asInterface(android.os.IBinder obj) : 将服务端的 binder 对象转换为客户端所需要的 AIDL 接口类型的对象,如果是客户端与服务端处于同一个进程,那么返回的就是服务端的 Stub 对象,否则返回的就是代理类 Proxy 对象
    5. asBinder : 返回当前的 binder 对象
    6. onTransact : 运行在服务端 binder 线程池中,调用远程服务的 transact 过程其实最终就是回调 onTransact 方法,通过它参数中的 code 可以确定调用的是哪一个方法,从 data 中取出调用的目标方法所需要的参数,当方法执行完毕后向reply中写入返回值,值得注意的是如果 onTransact 方法的返回值是 false 那么客户端的请求会失败
    7. Proxy : Proxy 是一个代理类,它实现了 IBookManager 接口,在其内部重写了 getBookList 和 addBook 方法,这两方法运行在客户端中,由我们开发者自己去调用,让我们简单分析下这个类的具体实现,看代码:
     private static class Proxy implements com.example.tengfei.aidl.IBookManager {
                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 java.util.List<com.example.tengfei.aidl.Book> getBookList() throws android.os.RemoteException {
                    //创建输入型Parcel对象
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    //创建输出型Parcel对象
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    //返回值对象
                    java.util.List<com.example.tengfei.aidl.Book> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.createTypedArrayList(com.example.tengfei.aidl.Book.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public void addBook(com.example.tengfei.aidl.Book book) throws android.os.RemoteException {
                     //创建输入型Parcel对象
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    //创建输出型Parcel对象
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        if ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
    

    首先它是一个静态内部类,我们不管这些,其实都可以分开来写的,将我们的注意力重点放在 getBookList 和 addBook 方法上,首先是 getBookList 方法,分别通过 Parcel.obtain() 构造出 两个Parcel 对象 _data 和 _reply 一个用于输入数据,一个用于输出数据,Parcel是一个容器,它可以包含数据或者是对象引用,并且能够用于Binder的传输。调用 Parcel 的 writeInterfaceToken 用于说明给当前的数据加上中介数据用来标识data是给含有DESCRIPTOR标志的Binder接口的参数,这句话的意思是说我 data 的数据是给定义了 DESCRIPTOR 标记的接口来用的,这本示例中对应着 Stub 类,紧接着调用 IBinder 的 transact 方法来执行远程RPC过程,调用 transact 方法最终回调服务端 binder线程池终的 onTransact 方法,至于 addBook 与 getBookList 差不多,就不讲啦。。。

    总结:

    1.定义一个接口继承自 IInterface,在接口中定义客户端与服务端通信的方法,只有继承了 IInterface 的接口才能在binder中传递
    2.定义一个抽象类继承自 Binder 并且实现了 IInterface 类型的接口,在它的构造方法中为此类定义唯一的标记,在 asInterface 方法中将服务端的 IBinder 对象返回为客户端所需要的 AIDL 接口类型的对象,但是是有区别的,如果客户端与服务端处于同一个进程,那么返回的是服务端的 Stub 对象,否则返回的就是 Stub.Proxy 代理类对象
    3.代理类 Proxy 实现了 IInterface类型的接口,并重写相关方法,这些方法运行在客户端,由我们开发人员自己调用,并最终调用 IBinder 的 transact 方法执行远程 RPC 过程,在 transact 方法中传入指定执行方法的标记以及输入输出型Parcel对象和 flag ,flag 一般定义为 0
    4.执行 transact 方法最终会回调服务端binder线程池中的 onTransact 方法,在 onTransact 方法中通过传递过来的 code 可以判断出具体要执行的方法,在其内部执行写入和读取数据的操作的相关逻辑
    5.客户端在发起远程请求时,客户端会被挂起知道服务端返回数据给客户端才会被唤醒

    最后用一张流程图来描述下使用 AIDL 是如何实现进程间通信的,如下:


    AIDL执行进程间通信的方式

    我上面写的不一定都是对的,仅仅是我个人学习过程中的思考以及摘录,在以后的学习过程中如果我发现了错误我会及时改正,也请开发前辈们如果发现了本文的错误及时指出,大家一起进步😄😄😄😄

    参考资料

    1、Android开发艺术探索
    2、对Binder的浅显分析及AIDL的使用
    3、Android Parcel对象详解

    相关文章

      网友评论

        本文标题:Android学习之旅-使用 AIDL 实现进程间通信02[艺术

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