Android进程间通信:Binder与AIDL

117 阅读3分钟
Binder

创建接口和Binder

创建一个继承自IInterface的接口,表示服务端提供了哪些方法(所有在Binder中传输的接口都需要继承IInterface接口)

image-20220608234033571

创建抽象类Stub继承自Binder并实现该接口

Snipaste_2022-06-08_17-18-27

Stub类下有asInterface(),客户端调用此方法可以拿到Stub/Stub.Proxy对象

Snipaste_2022-06-08_17-17-17

服务端

创建Stub类对象mBinder并实现接口方法,在onBind()中将mBinder暴露给外界

image-20220608230335720

image-20220608230551290

客户端

只讨论客户端与服务端不在同一进程的情况,所以客户端拿到的是Stub.Proxy对象

(因为Stub.Proxy实现了IMyAidlInterface,所以mBookManager可以声明为IMyAidlInterface类型)

image-20220608225853928

调用过程

Stub.Proxy对象内部持有着Stub对象(位于服务端)的引用

当客户端发起方法调用请求时,在这里组装好参数后发起transact过程,该过程最终会调用到Stub对象的onTransact()

Snipaste_2022-06-08_17-50-18

在Stub对象(位于服务端)的onTransact()中,去执行具体的目标方法,最后将返回值写入reply参数中

Snipaste_2022-06-08_17-37-35

意外情况

Binder运行在服务端进程,如果服务端进程异常终止导致Binder连接断裂,而客户端却不知道,那会有大问题

有两种方式可以重连Binder,两者区别主要是运行的线程不同

  1. 在客户端onServiceDisconnected()中重连Binder

    image-20220609102834193

  1. 在客户端创建DeathRecipient监听器,并在连接到Binder的时候将该监听器注册到Binder上

    image-20220609103334252

    image-20220609103443311

AIDL

AIDL文件的本质是快速实现Binder的工具,作用是编译后自动生成接口和Binder的实现类Stub...

适用于跨进程方法调用,服务端支持处理并发请求

创建AIDL文件
  1. 客户端和服务端的所有与aidl相关的类路径需要保持一致

    image-20220604140223953

    否则运行会出错

    image-20220604140054920

  1. 如果使用自定义类Book 需要创建Book.java并实现Parcelable

    然后创建Book.aidl

    image-20220608231738064

    并且在使用了Book的aidl文件中import

    image-20220608231852735

    如果单独建了一个aidl文件夹的话,需要在main/build.gradle中添加import路径

    image-20220604142530842

  2. AIDL接口中除了基本数据类型,其他参数必须标上方向(in传入该方法、out、inout)

使用时的一些Tips
  1. AIDL接口中所定义方法都是在实现方的Binder线程池中执行

    image-20220606195459254

    image-20220606195401340

所以如果方法执行耗时过长,可能会导致另一方ANR

  1. 使用观察者模式时,注册监听器时服务端反序列化mListener之后得到mListener的Proxy代理对象,随后放入集合;但是在解注册时,客户端传同样的mListener,服务端反序列化之后又会生成一个新的Proxy代理对象,此时去集合中删除是找不到对象的

    image-20220606190951310

    使用RemoteCallbackList解决

引入权限验证

在服务端定义并声明权限

image-20220609104844876

在服务端的onBind()中进行权限验证

image-20220609105051715

如果你没有使用AIDL而是手动实现的Binder,也可以在Stub:onTransact()中进行权限校验

\