优点
对比 Linux (Android基于Linux)上的其他进程通信方式(管道/消息队列/共享内存/信号量/Socket),Binder 机制的优点有:
高效
Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次
通过驱动在内核空间拷贝数据,不需要额外的同步处理
安全性高
Binder 机制为每个进程分配了 UID/PID 来作为鉴别身份的标示,并且在 Binder 通信时会根据 UID/PID 进行有效性检测
传统的进程通信方式对于通信双方的身份并没有做出严格的验证如,Socket通信 ip地址是客户端手动填入,容易出现伪造
使用简单
采用Client/Server 架构
实现 面向对象 的调用方式,即在使用Binder时就和调用一个本地对象实例一样
Binder
官方文档中建议:
日常开发中一般不需要我们再实现 IBinder,直接使用系统提供的 Binder 即可。
Binder 实现了 IBinder 定义的操作,它是 Android IPC 的基础,平常接触到的各种 Manager(ActivityManager, ServiceManager 等),以及绑定 Service 时都在使用它进行跨进程操作。
它的存在不会影响一个应用的生命周期,只要创建它的进程在运行它就一直可用。
通常我们需要在顶级的组件(Service, Activity, ContentProvider)中使用它,这样系统才知道你的进程应该一直被保留。
下面介绍 Binder 的几个关键方法:
实现 IBinder 的 transact() 方法:
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v(“Binder”, “Transact: ” + code + ” to ” + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
可以看到,这个方法就是调用 onTransact() ,然后将返回的结果再返回回去。
接着看看 onTransact() 方法:
没什么特别,略去。。
也没看出什么特别的,系统的 Binder.onTransact() 方法只定义了系统要进行的操作,我们如果创建自己的 Binder 时,就需要重写这个方法,根据 code 对传入的参数 data 做相应的处理,然后写入 reply,这样就能返回操作后的数据。
另外一个关键的方法 attachInterface:
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
/* mObject is used by native code, do not remove or rename */
private long mObject;
private IInterface mOwner;
private String mDescriptor;
这个方法的作用是将一个描述符、特定的 IInterface 与当前 Binder 绑定起来,这样后续调用 queryLocalInterface 就可以拿到这个 IInterface,那 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();
}
其实看名字就可以大概猜出来,IInterface 应该就是进程间通信定义的通用接口,我们通过定义接口,然后再服务端实现接口、客户端调用接口,就可以实现跨进程通信。
IInterface 里只定义了一个 asBinder() 方法,这个方法可以返回当前接口关联的 Binder 对象。
Binder通信机制
在 Android 系统的 Binder 机制中,由四个组件组成,分别是:
Client
Server
ServiceManager:提供辅助管理 Server 的功能
Binder 驱动程序:整个机制的核心,把这四个组件粘合在一起的粘结剂。
Binder 驱动
驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机和设备通信的特殊程序。相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作。
我们知道,在 Linux 系统中,内存空间分为两部分:
用户空间:运行着应用程序
内核空间:运行着系统内核和驱动
用户空间中的进程无法直接访问内核空间,需要通过上图中的 System Call Interface (系统调用接口),通过这个统一入口,所有资源访问都是在内核的控制下执行,这样可以避免用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。
同样的,用户空间中的进程也不可以直接访问数据,需要通过内核空间进行中转。
在 Binder 机制中,由 Binder 驱动负责完成这个中转操作,主要过程如下:
当 Client 向 Server 发起 IPC 请求时,Client 会先将请求数据从用户空间拷贝到内核空间
数据被拷贝到内核空间之后,驱动程序将内核空间中的数据拷贝到 Server 位于用户空间的缓存中
这样,就成功的将 Client 进程中的请求数据传递到了 Server 进程中。
实际上,Binder 驱动是整个 Binder 机制的核心。除了实现数据传输之外,Binder 驱动还是实现线程控制(通过中断等待队列实现线程的等待/唤醒),以及 UID/PID 等安全机制的保证。
http://wangkuiwu.github.io/2014/09/01/Binder-Introduce/
Service Manager
ServiceManager 运行在用户空间,它负责管理 Service 注册与查询。
看下 ServiceManager 的代码:
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static IServiceManager sServiceManager;
private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
/**
* 根据 Service 名称获取 Service
*/
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
//如果不存在就去 IServiceManager 中找,这时可能会阻塞
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
/**
* 添加一个 Service 到 Manager 中
*/
public static void addService(String name, IBinder service) {
try {
getIServiceManager().addService(name, service, false);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
/**
* 添加一个 Service 到 Manager 中,如果 allowIsolated 为 true 表示运行在沙盒中的进程也可以访问这个 Service
*/
public static void addService(String name, IBinder service, boolean allowIsolated) {
try {
getIServiceManager().addService(name, service, allowIsolated);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
/**
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
*/
public static IBinder checkService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().checkService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in checkService", e);
return null;
}
}
/**
* 获取 Service 列表
*/
public static String[] listServices() {
try {
return getIServiceManager().listServices();
} catch (RemoteException e) {
Log.e(TAG, "error in listServices", e);
return null;
}
}
/**
* 当前进程首次被 activity manager 创建时调用这个方法
*/
public static void initServiceCache(Map<String, IBinder> cache) {
if (sCache.size() != 0) {
throw new IllegalStateException("setServiceCache may only be called once");
}
sCache.putAll(cache);
}
}
可以看到 ServiceManager 提供了 Service 的添加和查询,其中主要操作都是通过 IServiceManager,它是何方神圣?
public interface IServiceManager extends IInterface
{
/**
* 获取一个 Service,不存在就会阻塞几秒
*/
public IBinder getService(String name) throws RemoteException;
/**
* 不阻塞的获取 Service
*/
public IBinder checkService(String name) throws RemoteException;
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException;
public String[] listServices() throws RemoteException;
/**
* 为 Service Manager 添加权限,具体作用暂不追究
*/
public void setPermissionController(IPermissionController controller)
throws RemoteException;
static final String descriptor = "android.os.IServiceManager";
//定义了一些用于调用 transact() 方法的 code
int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
}
可以看到 IServiceManager 是一个接口,它定义了管理 Service 的一些方法,同时继承了 IInterface。最常见的实现是 BnServiceManager.getDefault()。
Binder设计框架
上图简单介绍(节选自 http://wangkuiwu.github.io/2014/09/01/Binder-Introduce/):
Binder实体
Binder 实体实际上是内核中 binder_node 结构体的对象,它的作用是在内核中保存 Server 和ServiceManager 的信息(例如,Binder 实体中保存了 Server 对象在用户空间的地址)
Binder 实体是 Server 在 Binder 驱动中的存在形式,内核通过 Binder 实体可以找到用户空间的Server对象
在上图中,Server 和 ServiceManager 在 Binder 驱动中都对应的存在一个 Binder 实体
Binder 引用
Binder引用实际上是内核中 binder_ref 结构体的对象,是某一个 Binder 实体的引用,通过Binder 引用可以在内核中找到对应的 Binder 实体
如果将 Server 看作是 Binder 实体的话,那么 Client 就好比 Binder 引用,Client 通过保存一个Server 对象的 Binder 引用,再通过该 Binder 引用在内核中找到对应的 Binder 实体,进而找到Server 对象,然后将通信内容发送给 Server 对象
远程服务
本地服务的代理,通过调用远程服务可以间接调用本地服务
1.Client、Server 和 ServiceManager 处于用户空间的不同进程。
2.Binder 实体和 Binder 引用都是内核(即 Binder 驱动)中的数据结构。
它们的关系如下:
https://img-blog.youkuaiyun.com/20170529114829736?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTI0MDg3Nw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
每一个 Server 在内核中就表现为一个 Binder 实体,而每一个 Client 则表现为一个 Binder 引用。这样,每个 Binder 引用都对应一个 Binder 实体,而每个 Binder 实体则可以多个 Binder 引用。
Binder 跨进程通讯流程主要为如下 4 步:
ServiceManager 初始化
当该应用程序启动时,ServiceManager 会和 Binder 驱动进行通信,告诉 Binder 驱动它是服务管理者
Binder 驱动新建 ServiceManager 对应的 Binder 实体
Server 向 ServiceManager 注册自己 (AIDL中的attachInterface()完成)
Server 向 Binder 驱动发起注册请求,Binder 为它创建 Binder 实体)(AIDL中的attachInterface()完成())
然后如果 ServiceManager 中没有这个 Server 时就添加 Server 名称与 Binder 引用到它的 Binder 引用表
Client 获取远程服务
Client 首先会向 Binder 驱动发起获取服务的请求,传递要获取的服务名称(AIDL中的asInterface())
Binder 驱动将该请求转发给 ServiceManager 进程
ServiceManager 查找到 Client 需要的 Server 对应的 Binder 实体的 Binder 引用信息,然后通过 Binder 驱动反馈给 Client
(AIDL中的queryLocalInterface())
Client 收到 Server 对应的 Binder 引用后,会创建一个 Server 对应的远程服务(即 Server 在当前进程的代理)(AIDL中的new xxxProxy())
Client 通过代理调用 Server
Client 调用远程服务,远程服务收到 Client 请求之后,会和 Binder 驱动通信(AIDL中的Proxy复写的add()中和mRemote通信)
因为远程服务中有 Server 的 Binder 引用信息,因此驱动就能轻易的找到对应的 Server,进而将Client 的请求内容发送 Server(AIDL中调用mRemote的transact())