文章大纲
- 引言
- 一、Binder Java家族核心成员关系图
- 二、Binder Java家族核心成员源码概述
- 1、android.os.IBinder
- 1.1、boolean transact(int code, Parcel data, Parcel reply, int flags) send a call to an IBinder object
- 1.2、String getInterfaceDescriptor()
- 1.3、boolean pingBinder() 检测Binder是否存活
- 1.4、boolean isBinderAlive()检测托管进程是否存在
- 1.5、 IInterface queryLocalInterface(String descriptor) 获取Binder对应的本地实现对象
- 1.6、android.os.IBinder.DeathRecipient
- 1.7、android.os.IBinder 小结
- 2、android.os.Binder 和 android.os.BinderProxy
- 2.1、Binder 构造方法
- 2.2、attachInterface(IInterface owner, String descriptor) 初始化
- 2.3、boolean onTransact(int code, Parcel data, Parcel reply,
- 2.4、android.os.BinderProxy
- 3、android.os.IInterface
- 4、Stub和Stub.Proxy角色
引言
上一篇文章解读了Binder native家族成员的关系和功能,不过呢,和这篇文章关系也不是很大,不存在先后的顺序,因为这篇文章是主要解读Binder 代码层面主要Java家族成员类功能和部分代码的,目的是从代码和逻辑设计对Binder 有更深的理解。不过呢,Android中Java 、Native层使用同一套架构实现Binder服务,而且Java层最终是通过JNI调用Native 层的实现的,因此可以对照native层学习Java层将更容易掌握,所以建议先看native层的。
一、Binder Java家族核心成员关系图
主要有IBinder、IInterface、 Binder、BinderProxy类和Stub、Stub.Proxy角色。
- IBinder接口——代表一种跨进程传输的能力,实现这个接口就能将这个对象进行跨进程传递。
- Binder类——Binder本地对象。
- BinderProxy类——代表服务进程的Binder对象的本地代理。
- Parcel类——主要用于存储序列化数据,然后可以通过Binder在进程间传递这些数据。
- IInterface接口——Client端与Server端的调用契约(提供什么样的能力),实现这个接口就代表远程Server对象具有什么能力,其asBinder方法可以将Binder本地对象或代理对象返回。
- Stub角色(Local-side IPC implementation stub class)——是AIDL接口的静态内部抽象类,继承Binder并实现了具体的IInterface派生接口,负责把Binder转为Stup.Proxy角色。
- Stub.Proxy角色——Binder代理对象,Stub的静态内部类同样实现了AIDL接口派生类,真正去实现Binder#transact方法去实现AIDL接口方法的跨进程通信逻辑。
asInterface方法——当客户端bindService的onServiceConnecttion的回调里面,通过asInterface方法获取远程的service的。其函数的参数IBinder类型的obj,这个对象是驱动给我们的,如果是Binder本地对象,那么它就是Binder类型,如果是Binder代理对象,那就是BinderProxy类型。asInterface方法中会调用queryLocalInterface,查找Binder本地对象,如果找到,说明Client和Server都在同一个进程,这个参数直接就是本地对象,直接强制类型转换然后返回,如果找不到,说明是远程对象那么就需要创建Binder代理对象,让这个Binder代理对象实现对于远程对象的访问首先用Parcel把数据序列化,然后调用mRemote.transact方法,mRemote就是new Stub.Proxy(obj)传进来的,即BinderProxy对象
二、Binder Java家族核心成员源码概述
Framework层的Binder通过JNI来调用(C/C++)层的Binder框架,从而为上层应用程序提供服务。而Java层在命名与架构上和Native也非常相近,基本上是无缝衔接,同样也实现了一套类似的IPC通信架构供应用开发使用,当然最后都是通过Native层的Binder框架实现的。
1、android.os.IBinder
IBinder
是远程对象的Base接口,不仅可以在跨进程可以调用,也可以在进程内部调用。IBinder接口代表一种跨进程传输的能力,实现这个接口(不过通常都是去继承其子类android.os.Binder)就能将这个对象进行跨进程传递,IBinder用于定义了与远程对象进行交互的抽象协议。
1.1、boolean transact(int code, Parcel data, Parcel reply, int flags) send a call to an IBinder object
public boolean transact(int code, Parcel data, Parcel reply, int flags)
transact
方法是Binder IPC机制中真正去执行跨进程的方法,通过把序列化后的对象封装为Parcel 数据进行传递。换言之,所有跨进程的方法的调用最终都是会经过transact。通过**transact
方法可以向一个IBinder对象发送调用请求**,而在**Binder.onTransact
方法接收到一个Binder对象的调用**。transact()方法是同步调用,通常调用发出后会阻塞直到对方的Binder.onTransact()
方法调用完成后才会返回。
参数 | 说明 |
---|---|
code | “协议”代码,取值为android.os.IBinder#FIRST_CALL_TRANSACTION+N,用AIDL时与定义接口方法的顺序有关 |
data | 传输给服务端的数据,如果你没有传输任何数据,你必须创建一个空的Parcel实例。 |
reply | 从服务端接收的数据,如果不需要处理返回的值,传入null |
flags | IPC逻辑控制,如传入0表示是普通调用,而当且仅当调用者和响应者在不同进程时,传入android.os.IBinder#FLAG_ONEWAY时表示单向RPC,调用者会马上返回,而不必等结果从响应者响应之后再返回。 |
Parcel(一个通用缓冲区具体实现在Native层)除了有数据外还带有一些描述它内容的元数据(保存着IBinder对象的引用)。这样就能在缓冲区从一个进程移动到另一个进程时,保存这些引用。这确保了当一个 IBinder 在A进程内被写入到一个 Parcel 并发送到B进程后,B进程能将同一个 IBinder 的引用发送回A进程且确保A进程将收到相同的 IBinder 对象。因此可以将 IBinder/Binder 对象用作可以跨进程管理的唯一TOKEN。此外,系统为每一个进程维持一个Binder线程池,用于派发所有从其他进程发来的IPC调用。当进程A向进程B发起一个IPC 调用,A发出后,调用的线程就阻塞在transact()方法中了,进程B中Binder线程池的接收并调用Binder.onTransact(),完成后返回一个Parcel,然后A中的之前等待的线程在收到返回的Parcel才能继续执行,让你感觉像是在一个进程内线程之间的通信一样,实际上却是进程间的通信。
Binder机制还支持进程间的递归调用,transact()方法将在IBinder所在的进程不存在时抛出RemoteException异常
1.2、String getInterfaceDescriptor()
获取Binder 对应的标识,后续传入到queryLocalInterface中得到相应的IInterface对象。
1.3、boolean pingBinder() 检测Binder是否存活
如果目标进程不存在,那么调用pingBinder()时返回false,否则返回另一端的 pingBinder() 实现返回的结果(默认始终为 true)。
1.4、boolean isBinderAlive()检测托管进程是否存在
检查Binder所在的进程是否还活着,返回false则表示已经死亡,返回true有可能是正在返回结果或者活跃状态。
1.5、 IInterface queryLocalInterface(String descriptor) 获取Binder对应的本地实现对象
获取 Binder 对象的对应的本地实现对象, 返回null,则需要实例化一个代理类。
1.6、android.os.IBinder.DeathRecipient
监听当前进程所托管的Binder对象死亡的接口(只有一个方法android.os.IBinder.DeathRecipient#binderDied),可以通过linkToDeath(DeathRecipient recipient, int flags)方法注册监听IBinder生命周期,当Binder对象死亡时会被触发,而在不需要监听时调用unlinkToDeath(DeathRecipient recipient, int flags)。
1.7、android.os.IBinder 小结
总之,Binder 机制就是让我们感觉到跨进程的调用与进程内的调用没有什么区别。
- IBindre是远程对象的基接口,不仅可以在跨进程可以调用,也可以在进程内部调用
- 在远程调用的时候,一端用IBinder.transact()发送(封装为Parcel同步调用),另一端用Binder的Binder.onTransact()接受。
- 系统为每个进程维护一个进行跨进程调用的Binder线程池。
2、android.os.Binder 和 android.os.BinderProxy
android.os.Binder 和android.os.BinderProxy实现了android.os.IBinder接口,因而都可以被跨进程传输,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。Binder 是IBinder的标准实现,IPC 执行时直接继承的基类,但只是一个basic IPC primitive,它对应用程序的生命周期没有影响且只有在创建它的进程继续运行时才有效,因此要正确使用它必须在android.app.Service、android.app.Activity 或 android.content. ContentProvider里让创建它的进程一致存活。
2.1、Binder 构造方法
只有一个构造方法,由Native 进行,会在Stub 自动被调用。Binder实现了IBinder接口,但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具根据AIDL语法自动生成Binder的派生类。
2.2、attachInterface(IInterface owner, String descriptor) 初始化
初始化Binder和对应的标识,在Stub 构造函数中被调用并传入Stub自身对象和对应的全类名。
public static abstract class Stub extends android.os.Binder implements com.xxx.netservice.ICallback{
private static final java.lang.String DESCRIPTOR = "com.xxx.netservice.ICallback";
/** Construct the stub at attach it to the interface. */
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}
2.3、boolean onTransact(int code, Parcel data, Parcel reply,
int flags)
Binder中对应IBinder transact的实现,本质上就是调用Parcel 进行类“IO"操作。
2.4、android.os.BinderProxy
BinderProxy类也实现IBinder接口且是final类型的,主要API 的实现都是通过JNI调用Native 层的Binder,代表远程进程的Binder对象的本地代理,它的transact方法通过JNI去借助Binder驱动完成数据的传输,当完成数据传输后,会唤醒Server端,调用了Server端本地对象的onTransact函数,在Server进程里面,onTransact根据调用code会调用相关函数,接着将结果写入reply并通过super.onTransact返回给驱动,驱动唤醒挂起的Client进程里面的线程并将结果返回。
3、android.os.IInterface
Binder 的基类接口(定义的AIDL 实现时直接继承这个IInterface),主要是用于把IInterface 转为IBinder,以便确保代理对象可以返回正确的结果。
public interface IInterface{
/**
* Retrieve the Binder object associated with this interface.You must use this instead of a plain cast, so that proxy objects can return the correct result.
*/
public IBinder asBinder();
}
4、Stub和Stub.Proxy角色
Stub(抽象类)和Stub.Proxy(实体类) 是AIDL提供的标准实现定义的静态内部类,Stub.Proxy类和Stub类,都实现了AIDL接口,分别对应于本地进程和远程进程的Binder实例。其中Stub类在Server进程中实例化并通过 Service.onBind
方法传递给 Client 进程;而Client 进程接收到 IBinder 以后,通过 Stub.asInterface
方法转换成 AIDL接口之后使用。Stub.asInterface
在本地进程工作时直接返回 Stub 实例,否则创建一个 Proxy 实例来代理通讯。
Stub#onTransact方法该方法运行在服务端中的Binder线程池中,服务端通过code确定客户端所请求的目标方法是什么,从data中取出目标方法所需的参数,然后执行目标方法,并将目标方法的返回值写入reply。如果该方法的返回false,则表示客户端的请求回失败,可以利用这个特性来做权限验证。
Stub.Proxy实现aidl接口并将方法的标识,参数和返回值对象传入方法mRemote.transact中,发起远程调用请求,同时挂起当前线程,然后服务端的Stub#onTransact被调用,当onTransact返回true,调用成功,从reply对象中取出返回值,返回给客户端调用方,当Client 进程使用时通过 Stub.asInterface 创建,同时会将方法调用的数据,都通过mRemote 转发给Server端的 Binder 实例。
package com.xx.netservice;
public interface IBaseIPC extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.xx.netservice.IBaseIPC {
private static final java.lang.String DESCRIPTOR = "com.xx.netservice.IBaseIPC";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 无论是哪个进程,拿到反序列化的 IBinder 对象以后,通过这个静态方法来获取ICallback接口。
* 如果是 Server 进程(local),可以从 binder 中直接取出之前 attach的IInterface 实例,那么调用ICallback的方法,就相当于直接调用Stub 实例的方法了。
* 如果是 Client 进程,IBinder 只是系统在远程创建的一个 Proxy 类并无实现,因此iin 将变成 null,此时 asInterface 会创建一个Stub.Proxy 代理类,来实现 IBaseIPC 接口。
*/
public static com.xx.netservice.IBaseIPC asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.xx.netservice.IBaseIPC))) {
return ((com.xx.netservice.IBaseIPC) iin);
}
return new com.xx.netservice.IBaseIPC.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
// Server 进程的 Binder,在这里接收 transaction,并将数据反序列化以后,调用 IBaseIPC 抽象方法。
case TRANSACTION_baseIPC: {
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
int _arg1;
_arg1 = data.readInt();
boolean _arg2;
_arg2 = (0 != data.readInt());
this.IBaseIPC(_arg0, _arg1, _arg2);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
/**
* Client 进程持有的代理类,通过 Stub.asInterface 创建,Proxy 也实现了 IBaseIPC,会将方法调用的数据,都通过 mRemote 转发给远程的 Binder 实体。
*/
private static class Proxy implements com.xx.netservice.IBaseIPC {
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 void baseIPC(java.lang.String type, int deviceType, boolean status) 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.writeString(type);
_data.writeInt(deviceType);
_data.writeInt(((status) ? (1) : (0)));
mRemote.transact(Stub.TRANSACTION_baseIPC, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_baseIPC = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void baseIPC(java.lang.String type, int deviceType, boolean status) throws android.os.RemoteException;
}
未完待续…