美文网首页
从AIDL分析Binder的工作机制

从AIDL分析Binder的工作机制

作者: 空山Echo | 来源:发表于2019-05-23 15:10 被阅读0次

    问题等同:Binder是如何实现进程间通信的?或者AIDL的原理?

    我们在客户端通过IBookManager接口对象尝试调用接口方法时,接口内部是如何工作的呢?到底是如何使用Binder实现跨进程通信的呢?

    要明白上面的问题,就需要对IBookManager类进行分析才能得到答案

    一、IBookManager.java的结构

    1. 首先IBookManager接口继承了IInterface接口, 所有在Binder中传输的接口都需要继承IInterface
    2. 声明内部Stub类,继承Binder并且实现了IBookManager。(由此可见Stub为核心类)
    3. 声明我们在IBookManager.aidl定义的方法getBookList和addBook


      image.png

    二、核心实现IBookManager.Stub(Binder)类分析

    1. DESCRIPTOR常量:为Binder指定唯一标识
    2. 整形id常量:为getBookList和addBookfangf方法指定标识
    3. 构造方法:调用asInterface
    4. asInterface方法: 将服务端的Binder对象转换成客户端需要的AIDL接口类型对象。
    • 如果服务端和客户端同进程,返回IBookManager接口对象本身,否则返回系统封装后的Stub.Proxy对象
    • 之前的项目案例中,我们在客户端就是通过IBookManager.Stub.asInterface(service)来获取接口对象的
    1. asBinder方法: 返回当前Binder对象
    6. onTransact方法:这个方法运行在服务端中的Binder线程池,当客服端发起跨进程请求时,远程请求通过系统底层封装后交由此方法处理。工作过程如下:

    onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

    1. 服务端通过code确定请求的目标方法
    2. 从data中取出目标方法需要的参数(如果目标方法有参数),然后执行目标方法
    3. 执行完毕后,就向reply中写入返回值(如果目标方法有返回值)
    4. 此方法返回false时,客户端请求失败(会抛出异常)
    7. 声明内部类Proxy实现IBookManager接口,为Stub的代理类(由4可以知)。主要工作重写getBookList和addBook方法。

    分析Proxy#getBookList,这个方法运行在客户端

    1. 创建所需要的Parcel对象:输入型_data、输出型_reply,以及返回值对象List
    2. 然后将方法的参数信息写入_data中(如果有参数的话)
    3. 接着通过IBinder类型的成员变量mRemote(实际就是通过绑定服务成功获得的IBinder对象)调用transact方法来发起RPC(远程过程调用)请求,同时线程挂起;
    4. 然后服务端onTransact方法被调用,直到RPC过程返回,当前线程继续执行,并从_reply取出返回结果(即6中的reply)
    5. 最后返回_reply结果

    注意:

    - 客户端的发出的同步请求,所以不能在UI线程发起远程请求
    - 服务端Binder运行在Binder线程池,即onTransact方法执行在Binder方法池中,在此方法中最终执行了我们接口中定义方法的具体实现。所以在AIDLService中的IBookManager.Stub对象实现接口方法时,不管操作是否耗时都要采用同步的方式。

    三、Binder的工作机制总结

    image.png

    从上面的分析我们可以总结出Binder工作流程(跨进程)大致如下:
    客户端:

    1. 绑定服务,并获得Binder对象
    2. 通过asInterface方法以(1)中的Binder对象为参数,获得Stub.Proxy代理类实例;
    3. 在子线程中通过Stub.Proxy实例调用其实现的接口方法。_data中写入参数,并通过Binder调用transact方法发起RPC,线程挂起,等待RPC返回结果
      服务端:
    4. 通过底层封装后回调onTransact方法。在此方法中从data取出参数,并执行目标,执行完毕在reply中写入目标方法的返回值。最后返回onTransact方法的执行结果,true则代表客户端请求成功,RPC将会返回结果,执行过程也将回到客户端。
      客户端:
    5. RPC过程返回后,原本挂起的客户端线程继续执行,从_reply中取出服务端方法执行的结果并返回。

    这样就实现了进程间通信了,至于RPC的调用过程及reply、_reply是如何在内存中存储数据的暂不讨论

    相关文章

      网友评论

          本文标题:从AIDL分析Binder的工作机制

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