Android进程通信 - AIDL使用解析与Binder浅谈

文章目录


在上篇我们知道了AIDL的基本使用 Android进程通信 - AIDL的使用方法,然而还存在使用上的疑问,比如:

  1. AIDL是怎么实现IPC的?
  2. 服务端创建Binder对象或者客户端AIDL接口对象,都调用Stub()方法实现,那么该方法具体有哪些操作?
  3. 什么是Binder?

其实上面这三点可以统称理解为AIDL本质是什么;下面重点对AIDL文件生成的java文件进行解析,在创建了AIDL文件后SDK会自动生成对应的Binder类,可以简单理解为AIDL是一种实现Binder的工具。
以下是关于Binder的一些简单理解,具体的可以参考进程通信之 Binder 机制浅析Android-Binder进程间通讯机制

  • 从接口层面,Binder是Android中的一个类,它实现了IBinder接口
  • 从应用层面,Binder是客户端和服务端进行通信的中间代理,当bindService后,服务端会返回一个代理对象Binder,通过其可以获取服务端的数据。
  • 从IPC层面,Binder是Android中的一种跨进程通信方式
  • 从底层角度,Binder是连接各种Manager(ActivityManager、WindowManager等)的桥梁
  • 从物理层面,Binder是一种虚拟的物理设备,有自己的驱动设备。

AIDL原理

在上篇的例子中我们创建了两个aidl文件,分别是IBookManager.aidl、OnNewBookAddListener.aidl文件,在rebuild编译项目后,会自动生成对应的java文件,如下:
这里写图片描述
打开对应的java文件,下面以IBookManager.java为例

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\StudyAndroid\\progress\\src\\main\\aidl\\com\\hzw\\progress\\aidl\\IBookManager.aidl
 */
package com.hzw.progress.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.hzw.progress.aidl.IBookManager {
        private static final java.lang.String DESCRIPTOR = "com.hzw.progress.aidl.IBookManager";

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

        /**
         * Cast an IBinder object into an com.hzw.progress.aidl.IBookManager interface,
         * generating a proxy if needed.
         */
        public static com.hzw.progress.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.hzw.progress.aidl.IBookManager))) {
                return ((com.hzw.progress.aidl.IBookManager) iin);
            }
            return new com.hzw.progress.aidl.IBookManager.Stub.Proxy(obj);
        }

	 private static class Proxy implements com.hzw.progress.aidl.IBookManager {
 
       *********************省略********************

		}
    }

    public java.util.List<com.hzw.progress.aidl.Book> getBookList() throws android.os.RemoteException;


    public void addBook(com.hzw.progress.aidl.Book book) throws android.os.RemoteException;


    public void registerListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException;

    public void unregisterListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException;
}

以上的代码很多,我们可以通过类的树形结构图大体知道AIDL文件生成java文件的基本信息及内容:
这里写图片描述

  • IBookManager.java这个类是一个接口,继承于IInterface这个接口
  • 接着声明了一个内部类Stub,而这个Stub是继承于Binder,就是一个Binder对象;同时实现了IBookManager本身的实例。
  • 同时也声明了在aidl文件定义的四个方法,分别是:getBookList、addBook、registerListener、unregisterListener

从整个代码结构可以看出,IBookManager类的具体功能在内部类Stub实现的,接下来就看看内部类Stub的逻辑,

public static abstract class Stub extends android.os.Binder implements com.hzw.progress.aidl.IBookManager {

		//Binder的唯一标识,一般是以当前Binder的类名表示
        private static final java.lang.String DESCRIPTOR = "com.hzw.progress.aidl.IBookManager";

	    //将IBookManager接口关联到Binder对象中
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

       //将服务端的Binder对象转换成客户端需要的接口对象IBookManager。
        public static com.hzw.progress.aidl.IBookManager asInterface(android.os.IBinder obj) {
	        //判断obj是否null,为null则说明客户端与服务端连接失败
            if ((obj == null)) {
                return null;
            }
            //通过标识查询obj对象是否有关联的接口
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            //不为null,说明服务端和客户端在同一个进程中,返回自身对象
            if (((iin != null) && (iin instanceof com.hzw.progress.aidl.IBookManager))) {
                return ((com.hzw.progress.aidl.IBookManager) iin);
            }
            //为null,则返回一个Binder的代理对象Proxy
            return new com.hzw.progress.aidl.IBookManager.Stub.Proxy(obj);
        }
… …… ………  ……
}

Stub类是继承于Binder类,同时实现了IBookManager接口,定义了两个自身的函数分别是构造函数Stub和asInterface

  • 通过构造函数 Stub()将IBookManager接口关联到Binder对象中,通过传入DESCRIPTOR 字段标识当前Binder对象,保证Binder对象的唯一性。
  • 通过asInterface函数将服务端的Binder对象转换成客户端需要的接口对象IBookManager,从而实现客户端与服务端的交互。

这里写图片描述
asInterface方法有以下几个流程逻辑

  1. 首先会判断传入的binder对象是否为null,若为null,说明客户端和服务端没有建立连接。
  2. 接着会拿着DESCRIPTOR 标识去查询binder对象是否有本地对应的接口(通过queryLocalInterface返回值判断)。
  3. 最后根据queryLocalInterface返回值判断返回具体的AIDL接口对象,若返回值存在,则返回服务端对象本身Stub,若为null,则返回系统封装好的代理对象Stub.Proxy。

接下看看queryLocalInterface方法的源码

 /**
     * 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.
     */
    public IInterface queryLocalInterface(String descriptor);

从源码的注释可以知道一个大概,通过descriptor标识会先尝试获取本地的binder对象,所谓本地的是指客户端和服务端同属一个进程。如果返回值为null,则需要实例化一个代理对象。我们也可以通过测试来在不同进程queryLocalInterface具体返回情况

  private ServiceConnection mConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                mIBookManager = IBookManager.Stub.asInterface(service);
                IInterface queryLocalInterface = service.queryLocalInterface("com.hzw.progress.aidl.IBookManager");
                if (queryLocalInterface!=null){
                    //客户端与服务端同一个进程
                    Log.i(TAG, "queryLocalInterface 不为null");
                }else {
                    //不同进程
                    Log.i(TAG, "queryLocalInterface 为null");
                }
}

既然在不同进程时,asInterface会返回一个Stub.Proxy代理对象,就看看Proxy对象是怎么样的

  private static class Proxy implements com.hzw.progress.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.hzw.progress.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.hzw.progress.aidl.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.hzw.progress.aidl.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }


            @Override
            public void addBook(com.hzw.progress.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);
                    }
                    //执行远程Rcp请求,向服务端发送请求
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
            
            @Override
            public void registerListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
                    mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public void unregisterListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
                    mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

Proxy 代理类同样也实现了IBookManager接口,同时也实现了IBookManager类中所有方法。代理类的方法是在客户端调用的,客户端可以通过代理Proxy对象调用相应的方法getBookList、addBook等等。内部实现大概流程如下:

  1. 获取输入型Parcel包对象_data和输出型Parcel包对象_reply;
  2. 如果方法传入的参数不为null,则将其参数信息写入_data对象中,其实是个对象序列化过程
  3. 接着通过远程Binder对象调用transact方法来发送RPC(远程过程调用)请求,同时当前线程会被挂起;
  4. 最后,服务端的onTransact会被调用,当服务端处理完请求后,会返回数据,当前线程继续执行知道返回 _result结果。返回数据的过程其实就是一个反序列化过程

在第三步开始,当客户端向服务端发送远程请求,服务端接受到请求,会回调Binder的onTransact方法,并将数据返回给客户端,接下来就看看onTransact的实现逻辑是如何的:

		@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<com.hzw.progress.aidl.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
	                //从输入型对象取出参数信息
                    data.enforceInterface(DESCRIPTOR);
                    com.hzw.progress.aidl.Book _arg0;
	                //读取数据
                    if ((0 != data.readInt())) {
	                    //传入参数存在,则反序列化过程
                        _arg0 = com.hzw.progress.aidl.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_registerListener: {
                    data.enforceInterface(DESCRIPTOR);
                    com.hzw.progress.aidl.OnNewBookAddListener _arg0;
                    _arg0 = com.hzw.progress.aidl.OnNewBookAddListener.Stub.asInterface(data.readStrongBinder());
                    this.registerListener(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_unregisterListener: {
                    data.enforceInterface(DESCRIPTOR);
                    com.hzw.progress.aidl.OnNewBookAddListener _arg0;
                    _arg0 = com.hzw.progress.aidl.OnNewBookAddListener.Stub.asInterface(data.readStrongBinder());
                    this.unregisterListener(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

当客户端发起跨进程请求时,远程服务端会通过系统底层封装好的方法来处理返回数据,这个就是方法就是onTransact,它内部大概流程如下:

  1. 首次会根据客户端请求code来确定需要执行的内容是什么
  2. 接着从输入型对象data中取出目标参数,如果参数存在,则进行反序列化操作。
  3. 当目标方法执行完毕后,就向输出型reply对象写入数据,并将数据返回给Binder对象,最后返回给客户端。

上面就是整个AIDL实现进程通信的原理流程。

总结

下面简单总结Binder的工作机制

这里写图片描述

Binder的工作流程可以分为三部分,分别是连接请求、序列化写入数据、反序列化结果返回客户端
1、绑定服务建立连接后,服务端会返回一个Binder对象给客户端,通过Binder对象就可以跨进程交互。在获取Binder实例对象时,需调用asInterface方法进行判断客户端和服务端是否在同一进程,若在同一个进程,则返回一个本地binder对象,反之则需创建一个代理对象Stub.Proxy返回。
2、获取到代理对象Proxy后,客户端可以调用服务端相应的方法(addBook、getBookList等)传入参数,当Binder拿到数据后,会根据参数的有无(序列化过程)写入包裹类Parcel中,接着调用binder对象的transact方法。
3、最后会触发Stub类(Binder类)的onTransact方法,从线程池中取出数据,写入reply中把结果返回给客户端,最终唤醒线程。

参考

  • 安卓开发艺术探索
  • https://www.jianshu.com/p/b96713fc4e5e
  • https://blog.csdn.net/u011240877/article/details/72801425

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/81056445