在Binder系列1 Binder总体设计思想中,主要从宏观上讲了 Binder 的总体设计思想和一些关键部分的设计细节,比如接收缓存管理,接收线程优化和线程池管理,接收包管理等.在系列2中会进一步细化 Binder 的概念和介绍实现 Binder 通信架构所用到的相关接口和类.
一 什么是Binder
简单地说,Binder 是 Android 平台上的一种跨进程通信技术。该技术最早并不是由 Google 公司提出的,它的前身是 Be Inc 公司开发的 OpenBinder,而且在 Palm 中也有应用。后来 OpenBinder 的作者 Dianne Hackborn 加入了 Google公司,并负责Android平台的开发工作,所以把这项技术也带进了 Android.
在 Android 的应用层次上,基本上已经没有过去的进程概念了。取而代之的都是 Activity,Service,BroadcastReceiver,和 ContentProvider 等各个组件.然而在实现层次,它毕竟还是要建构在一个个进程之上的。实际上,在 Android 内部,那些支撑应用程序的各个组件,往往会身处于不同的进程,那么应用程序的底层,必然会牵涉到大量的跨进程通信。为了保证通信的高效性,Android 提供了 Binder 机制.
Binder 机制具有两层含义:
1) 是一种跨进程通信手段(IPC,Inter-Process Communication)。
2) 是一种远程过程调用手段(RPC,Remote Procedure Call)。
从实现的角度来说,Binder 的核心被实现成了一个 Linux 驱动程序,并运行于内核态。这样它才能具有强大的跨进程访问能力。
1.1 简述Binder的跨进程通信机制
为了理解 Binder,我们可以先画一张最简单的跨进程通信示意图:
这个很容易理解,不需赘言。到了 Android 平台上,IPC 机制就变成了 Binder 机制,情况类似,只不过为了便于说明问题,我们需要稍微调整一下示意图:
图中A侧的圆形块,表示“Binder代理方”也叫 Binder 引用,主要用于向远方发送语义,而B侧的方形块
则表示“Binder响应方”也叫 Binder 实体,主要用于响应语义。需要说明的是,这种图形表示方法只是为了便于理解,个人觉得这种图形非常简便,所以在分析 Android 架构时,会经常使用这种表示法。
在后文中,我们可以看到,Binder 代理方对应于 C++ 层次的 BpBinder 对象,而 Binder 响应方则对应于 BBinder 对象。这两个对象在后文会详细阐述,此处不必太细究。
然而,上图的 Binder 代理方主要只负责了“传递信息”的数据传输工作,并没有起到“远程过程调用”的作用,如果要支持远程过程调用,我们还必须提供“接口代理方”和“接口实现体”。这样,我们的示意图就需要再调整一下,如下:
从图中可以看到,A进程并不直接和 BpBinder(Binder代理)打交道,而是通过调用 BpInterface(接口代理)的成员函数来完成远程调用的。此时,BpBinder 已经被聚合进 BpInterface 了,它在 BpInterface 内部完成了一切跨进程通信的机制。另一方面,与 BpInterface 相对的响应端实体就是 BnInterface(接口实现)了。需要注意的是,BnInterface 是继承于 BBinder 的,它并没有采用聚合的方式来包含一个 BBinder 对象,所以上图中B侧的 BnInterface 块和 BBinder 块的背景图案是相同的,BpBinder 是聚合进 BpInterface,而 BnInterface 是继承自 BBinder,了解和理解这一点非常重要。
这样看来,对于远程调用的客户端而言,主要搞的就是两个东西,一个是 Binder 代理:BpBinder,另外一个就是“接口代理”:BpInterface。而服务端主要搞的则是“接口实现体”:BnInterface。因为 Binder 是一种跨进程通信机制,为了便于管理Binder服务,和便于 Client 获取 Binder 引用,Binder 机制就搞了一个专门的管理器来为通信两端牵线搭桥,这个管理器就是 SMgr。不过目前我们可以先放下 ServiceManager,在Binder系列3 ServiceManager启动和实现中会详细研究。
二 Binder相关接口和类
由于 Android 系统是分层次的系统,所以跨进程通信的 Binder,不但会在底层使用,也会在上层使用,所以需要提供 Java 和C++ 两个层次的支持。
2.1 Java层次的Binder元素
Java 层次里并没有我们前文图中所表示的 BpBinder、BpInterface、BBinder、BnInterface 等较低层次的概念,取而代之的是IBinder 接口、IInterface 等接口。Android 要求所有的 Binder 实体都必须实现 IBinder 接口,该接口的定义截选如下:
frameworks/base/core/java/android/os/IBinder.java
public interface IBinder
{
. . . . . .
public String getInterfaceDescriptor() throws RemoteException;
public boolean pingBinder();
public boolean isBinderAlive();
public IInterface queryLocalInterface(String descriptor);
public void dump(FileDescriptor fd, String[] args) throws RemoteException;
public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback shellCallback,
@NonNull ResultReceiver resultReceiver) throws RemoteException;
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
throws RemoteException;
public interface DeathRecipient {
public void binderDied();
}
public void linkToDeath(DeathRecipient recipient, int flags)throws RemoteException;
public boolean unlinkToDeath(DeathRecipient recipient, int flags);
}
另外,不管是代理方还是实体方,都必须实现 IInterface 接口:
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();
}
Java 层次中,与 Binder 相关的接口或类的继承关系如下:
在实际使用中,我们并不需要编写上图的 XXXXNative、XXXXProxy,它们会由 ADT 根据我们编写的 AIDL 脚本自动生成。用户只需继承 XXXXNative 编写一个具体的 XXXXService 即可,这个 XXXXService 就是远程通信的服务实体类,而 XXXXProxy 则是其对应的代理类。
关于 Java 层次的 Binder 组件,我们就先说这么多,主要是先介绍一个大概。就研究跨进程通信而言,其实质内容基本上都是在 C++ 层次,Java 层次只是一个壳而已。以后我会写专文来打通 Java 层次和 C++ 层次,看看它们是如何通过 JNI 技术关联起来的。现在我们还是把注意力集中在 C++ 层次吧。
2.2 C++层次的Binder元素
在 C++ 层次,就能看到我们前文所说的 BpBinder 类和 BBinder 类了。这两个类都继承于 IBinder,IBinder 的定义截选如下:
frameworks/native/include/binder/IBinder.h
class IBinder : public virtual RefBase
{
public:
.........
IBinder();
virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
static status_t shellCommand(const sp<IBinder>& target, int in, int out, int err,
Vector<String16>& args, const sp<IShellCallback>& callback,
const sp<IResultReceiver>& resultReceiver);
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) = 0;
class DeathRecipient : public virtual RefBase {
public:
virtual void binderDied(const wp<IBinder>& who) = 0;
};
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = NULL,