- Binder是Android提供的一种高效安全的IPC(Inter-Process Communication进程间通信)机制;
- AIDL Android Interface Definition Language(安卓接口定义语言),它是一种以.aidl为后缀名的接口文件,在文件中定义远程服务对外提供的接口方法,这个文件是不会被编译到apk中的,它的目的是让IDE也就是Android Studio依照定义的内容生成对应的.java文件,生成的.java文件才是完成Binder提供给Client和Service间通信的实现类,也就是说,我们可以不使用AIDL文件手写一个类用于实现Client到Service的远程调用,事实上当我们为了在通信中加入特殊的处理时(比如校验调用方权限和参数封装)就不得不手写这个类,包括很多Android的原生服务的类也都是手写的,最常见的就是用于启动Activity的类ActivityManagerNative就是这样的一个类;
IDE根据AIDL文件生成的.java文件
注:大篇幅的粘贴代码会影响读者对文章内容的阅读,所以我希望大家可以对照着.java文件看这篇文章。
文件内容是一个继承自android.os.IInterface的与AIDL文件同名的接口(以下简称AIDL接口),它包含了AIDL中定义所有方法,其核心是一个名为Stub的静态内部类,以及类Stub的静态内部类Proxy。
Stub
Stub是一个继承自类android.os.Binder的抽象类也就是说Stub是一个Binder类(这也就意味着由实现了Stub的类派生出的对象是可以跨进程传递的,IPC中,Service的onBinder方法返回的就是由Stub的实现类派生的对象),它同时还实现了AIDL接口,Stub最终会由Service端实现,用于对外提供服务。它包含了以下几个部分:
- DESCRIPTOR Binder的唯一标识,一般用AIDL接口的全名表示,它是Binder的唯一标识;
- asInterface(android.os.IBinder obj) 为Client提供Service的Binder实例,方法的入参在Client与Service同进程时是Service的Binder实例,跨进程时是Service Binder的代理类BinderProxy实例(这个实例是真正处理远程调用的实例,后面说的根据它派生的Stub.Proxy实例是为了处理传参和返回值的),当Client与Service处在同一个进程时方法直接返回Service端的Binder实例,跨进程时则返回使用obj派生的Stub.Proxy实例;
- asBinder 返回当前Binder对象;
-
onTransact 方法运行在Service端的Binder线程池中,当Client发起远程调用时,系统底层会将调用封装后交由onTransact处理,该方法的原型是
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
。Service通过code区分Client要调用的目标方法是哪个(code在Stub内定义),接着从data中取出目标方法所需的参数(如果有),然后执行目标方法,当目标方法执行完毕后,就向reply写入返回值(如果有),如果onTransact方法返回flase,表示Client远程调用失败,我们可以利用这个特性来做Client权限判断; - Proxy 为Client提供Service的代理,Proxy是运行在Client进程的,当Client与Service处于同一进程时是不会使用的Proxy的,因为在Client在调用Stub.asInterface方法获取Service端Binder实例时会直接返回Binder的原始实例而不是Proxy代理实例。
Proxy
该类是Service端在Client端的代理类,实现了AIDL接口,类中的方法也是代理方法,负责参数处理-->远程调用目标方法-->返回值处理,代理方法中会调用一个远程调用相关的重要方法transact,方法的原型是public boolean transact(int code, Parcel data, Parcel reply, int flags)
,方法的参数:
- code 用于区分目标方法,code值在Stub中有常量定义;
- data 入参,如果目标方法是需要传参的切Client调用代理方法时传入了参数则为data添加参数,如果是基本类型或String则直接添加,如果是实现了Parcelable的对象则将对象序列化写入data;
- reply 返回值,如果目标方法有返回值则会将返回值写入reply中,这样当transact方法结束后代理方法就可以从reply中取得返回值;
-
flags 通常是0,也可以传入IBinder.FLAG_ONEWAY,表示不关心远程方法的执行情况,也就是说发起远程调用时不会阻塞发起调用的线程。
对data和reply的介绍也就是介绍代理方法是如何处理远程调用传参和返回值的。
网友评论