Android-Binder原理浅析

Android-Binder原理浅析

学习自

《Android开发艺术探索》

写在前头

在上一章,我们简单的了解了一下Binder并且通过 AIDL完成了一个IPC的DEMO。你可能会好奇为什么,上一章说是介绍Binder大的IPC通信呢,为什么又扯到AIDL了,通过本章就可以解除我们的疑惑。

IBookManager

在上一章中,说到了使用AIDL成功编译后会生成一个.Java的文件,我们的Dome中生成的文件是 IBookManager.java 下面我们来看一下其中的源码,如下所示(生成的代码没有缩进,找了个工具格式化了一下). 其中主要的地方都写了注释。

/*
 * This file is auto-generated. DO NOT MODIFY.
 * Original file: F:\\MyCode\\Android\\StudyIPC\\app\\src\\main\\aidl\\top\\littledavid\\studyipc\\IBookManager.aidl
 */
package top.littledavid.studyipc;

public interface IBookManager extends android.os.IInterface {
    public java.util.List<top.littledavid.studyipc.beans.Book> getBookList()
        throws android.os.RemoteException;

    //这是如果不是使用的基础数据类型,一定要使用方向类型标识 : in ,out ,inout
    public void addBook(top.littledavid.studyipc.beans.Book book)
        throws android.os.RemoteException;

    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements top.littledavid.studyipc.IBookManager {
  //Binder的唯一标识
        private static final java.lang.String DESCRIPTOR = "top.littledavid.studyipc.IBookManager";
        //方法的标识
  static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION +
            0);
  //方法的标识
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION +
            1);

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

        /**
         * Cast an IBinder object into an top.littledavid.studyipc.IBookManager interface,
         * generating a proxy if needed.
   * 将IBinder对象转化为我们定义的AIDL接口,如果需要的话则生成代理类
         */
        public static top.littledavid.studyipc.IBookManager asInterface(
            android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
   
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
   
   /**
   如果iin不为null表示Binder运行与本地进程
   否则则是运行在其他的进程
   则通过代理来实现通信
   */
            if (((iin != null) &&
                    (iin instanceof top.littledavid.studyipc.IBookManager))) {
                return ((top.littledavid.studyipc.IBookManager) iin);
            }

            return new top.littledavid.studyipc.IBookManager.Stub.Proxy(obj);
        }
  
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }
  
  /**
  此方法运行在服务端,处理我们的RPC
  此方法如果返回为false那么客户端的请求将会失败
  可以利用此方法来做权限验证
  */
        @Override
        public boolean onTransact(int code, android.os.Parcel data,
            android.os.Parcel reply, int flags)
            throws android.os.RemoteException {
   //根据code的不同调用不同的方法
            switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);

                return true;
            }
   
            case TRANSACTION_getBookList: {
                data.enforceInterface(DESCRIPTOR);

                java.util.List<top.littledavid.studyipc.beans.Book> _result = this.getBookList();
                reply.writeNoException();
                reply.writeTypedList(_result);

                return true;
            }

            case TRANSACTION_addBook: {
                data.enforceInterface(DESCRIPTOR);

                top.littledavid.studyipc.beans.Book _arg0;
    //从_data中取得参数调用
                if ((0 != data.readInt())) {
                    _arg0 = top.littledavid.studyipc.beans.Book.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }

                this.addBook(_arg0);
                reply.writeNoException();

                return true;
            }
            }

            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements top.littledavid.studyipc.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;
            }
   //getBookList的方法流程和addBook方法的流程相似
   //这里就不多做解释
            @Override
            public java.util.List<top.littledavid.studyipc.beans.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<top.littledavid.studyipc.beans.Book> _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data,
                        _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(top.littledavid.studyipc.beans.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }

            //这是如果不是使用的基础数据类型,一定要使用方向类型标识 : in ,out ,inout
            @Override
            public void addBook(top.littledavid.studyipc.beans.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);
                    }
     //发起RPC(远程调用请求)
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
    }
}

类的整体结构如下

首先是一个Java接口,该接口就是我们通过 AIDL 定义的接口,这个接口并没有什么特殊,其中的嵌套类才是我们需要注意的地方,Stub嵌套类继承自Binder同时也实现了IBookManager接口,是本地IPC的实现类,我们就是通过 asInterface 方法,获取IBookManager对象的实例完成IPC操作。在Stub的类中还有一个嵌套类,是一个代理类,这个代理类真正实现了我们在AIDL中定义的方法并完成了IPC通信。

类成员的详细的解释

__DECRIPTOR: __Binder的唯一标识一般使用全类名表示

__asInterface方法: __用户将服务端的Binder对象转化为客户端所需要的 AIDL对象,在此方法中分为两种情况,如果服务端和客户端位于同一个进程,那么返回的就是我们在Service中定义的Stub对象自身,否则返回封装后代理对象。

__asBinder方法: __返回当前的Binder对象

__onTransact方法: __此方法运行在服务端的Binder线程池中,当客户发起跨线程请求的时候,远程请求会通过系统的封装后,由此方法处理。此方法通过code参数来区分执行的方法时什么,如果需要当执行完毕后先_reply中写入返回值信息。如果此方法的返回值为false,那么请求会失败,我们可以在此方法中做权限的过滤。

__addBook方法: __getBookList方法和此方法的业务逻辑类似,所以这里仅仅介绍一种,在方法中首先会创建代表输入参数和返回值的Parcel对象_data和_reply,然后将方法所需的参数写入到_data中,紧接着就发送了远程调用请求,因为此方法并没有返回值,所以并没有来获取返回值。

Binder-IPC的流程

下面是一个IPC的简单的流程图,来自《Android开发艺术探索-55页》

image.png | left | 826x303

总结

使用AIDL就是为了生成上面的那个类,AIDL只是提供了一种更为快捷的方式来生成上面的那个接口,其实我们完全可以自己动手写那个接口也可以完成IPC通信,并且在沙面的代码中我们发现了其中大量使用了Parcel类,这也是为什么我们的实体类要实现Parcelable接口的原因。关于手写IBookManager接口可以参考任玉刚老师的《Android开发艺术探索》,在这里我就不误导大家了。毕竟Binder是一个非常深入的概念如果深究的话会涉及到很多的Android底层的知识,我也不会 😂。

posted @ 2018-07-31 10:00  鲁迅认识的那只猹  阅读(449)  评论(0编辑  收藏  举报