由于Android系统保护机制(沙箱机制),两个进程是各自运行在自己的进程空间之中的,相互之间进行隔离并不能够直接进行通讯(确保一个进程挂掉了,不会影响另外一个进程的运行)。
一、为什么使用Binder机制
Android系统是基于Linux系统的,我们知道Linux 系统之中常见的进程之间的通讯就有共享内存、消息队列、管道、Socket等。那为什么Android 系统不直接采用Linux 的进程之间的通讯方式,而是采用Binder机制,C/S模式来实现进程之间的通讯呢?
我想主要有以下三个方面的原因。
- C/S架构模式,Binder能够很好的支持Client-Server模式,相比只有Socket能够提供C/S模式,但是Socket主要是用于网络之间的通讯以及本地进程之间的低速通讯,效率太低。
- 安全考虑, Android 系统为每一个应用程序都分配了唯一的一个UID,且Android系统安全权限管理很严格,Server端会根据权限控制策略,判断UID/PID是否满足访问权限。
- 性能考虑, 传统的消息队列、管道、Socke都需要通过2次拷贝操作,才能实现从用户态空间到内核空间的数据拷贝。而共享内存实现方式复杂,没有客户与服务端之别, 需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题。而Binder只需要一次拷贝操作就可以(从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,因此只需要1次拷贝即可)。
二、几个重要的概念
- Binder实体,其实就是Server在内核中的binder_node结构体的对象,保存着Server对象在用户空间的地址信息。通过Binder实体可以找到用户空间的Server的对象。
- Binder引用,其实就是是内核中binder_ref结构体的对象,它的作用是在表示"Binder实体"的引用。简单说是每一个Binder引用都是某一个Binder实体的引用,通过Binder引用可以在内核中找到它对应的Binder实体。
- 远程服务,Server都是以服务的形式注册到ServiceManager中进行管理的,可以理解就是Server提供的服务。
- ServiceManager,是用户空间的守护进程,由init进程负责启动,之后会打开/dev/binder设备,建立128K虚拟内存映射Binder 驱动,下发BINDER_SET_CONTEXT_MGR的command,声明自己成为上下文管理者,进入binder消息轮询,等待client消息到来。
- Server注册服务,Server首先会向Binder驱动发起注册服务请求,Binder驱动会新建与该Server对应的Binder实体,在ServiceManager的保存Binder引用的红黑树中查找Server的Binder引用如果不存在则会新建一个与该Server对应的Binder引用。并将其添加到ServiceManager的保存Binder引用的红黑树之中。
- Client获取远程服务,Client携带Server的服务名向Binder驱动获取远程服务,Binder驱动会转发会给ServiceManager进程,且有ServiceManager返回Server对应的Binder实体的Binder引用信息,Client根据这个信息创建Server的远程服务,该远程服务会对应的通过Binder驱动和真正的Server进行交互,从而执行相应的动作。
三、AIDL 示例
在Android开发过程中,我们一般是采用编写AIDL文件的形式来描述服务器提供哪些接口。
IDataManager.aidl 文件
// 无论应用的类是否和aidl文件在同一包下,都需要显示import
import org.github.lion.aidl_demo.Data;
interface IDataManager {
/** AIDL 支持的数据类型划分为四类
* 第一类是 Java 编程语言中的基本类型
* 第二类包括 String、List、Map 和 CharSequence
* 第三类是其他 AIDL 生成的 interface
* 第四类是实现了 Parcelable protocol 的自定义类
*/
void basicTypes(int anInt, long aLong, boolean aBoolean
, float aFloat, double aDouble, String aString);
int getDataTypeCount();
List<Data> getData();
String getUrlContent(String url);
}
自定义实现Parcelable接口类型
/** 必须实现Parcelable接口
* 1. 定义CREATOR对象
*/
public class Data implements Parcelable {
...
protected Data(Parcel in) {
...
}
public static final Creator<Data> CREATOR = new Creator<Data>() {
@Override
public Data createFromParcel(Parcel in) {
return new Data(in);
}
@Override
public Data[] newArray(int size) {
return new Data[size];
}
};
}
服务端的实现
private static final IDataManager.Stub mBinder = new IDataManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean
, float aFloat, double aDouble, String aString)
throws RemoteException {
}
@Override
public int getDataTypeCount() throws RemoteException {
// todo return some data
return 0;
}
@Override
public List<Data> getData() throws RemoteException {
// todo return some data
return null;
}
@Override
public String getUrlContent(String url) throws RemoteException {
// todo return some data
return null;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
客户端实现
private IDataManager dataManagerService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// 绑定服务
bindService(new Intent(this, DataManagerService.class), dataServiceConnection,
Context.BIND_AUTO_CREATE);
}
private ServiceConnection dataServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 返回IBinder 对象,封装为代理类
dataManagerService = IDataManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
dataManagerService = null;
}
};
接下来我们看看Android Studio帮我们自动生成的Java文件里面的内容。
// IDataManager2 直接继承了IInterface
public interface IDataManager2 extends IInterface {
// 返回值为基本数据类型,定义接口时不需要做特殊处理
int getDataCount() throws RemoteException;
// 自定义的返回数据类型需要实现Parcelable接口,进程间通信不能直接共享内存,需要将对象持久化。
// 所以自定义的类需要实现Parcelable接口
List<Data2> getData() throws RemoteException;
}
//内部抽象类集成Binder实现了IDataManager2(Stub)接口
public abstract class DataManagerNative extends Binder implements IDataManager2 {
// Binder描述符,唯一标识符
private static final String DESCRIPTOR = "com.github.onlynight.aidl_demo2.aidl.IDataManager2";
// 每个方法对应的ID
private static final int TRANSACTION_getDataCount = IBinder.FIRST_CALL_TRANSACTION;
private static final int TRANSACTION_getData = IBinder.FIRST_CALL_TRANSACTION + 1;
public DataManagerNative() {
attachInterface(this, DESCRIPTOR);
}
/**
* 将Binder转化为IInterface接口
*
* @param binder
* @return
*/
public static IDataManager2 asInterface(IBinder binder) {
if (binder == null) {
return null;
}
//同一进程内直接返回
IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
if ((iin != null) && (iin instanceof IDataManager2)) {
return (IDataManager2) iin;
}
//不在同一进程使用代理获取远程服务
return new Proxy(binder);
}
@Override
public IBinder asBinder() {
return this;
}
/**
* 我们查看Binder的源码就可以看出实际上transact方法真正的执行体
* 是这个onTransact方法。
*
* @param code 服务器回掉的方法ID,每一个方法都有一个唯一id,
* 这样方法回调时可通过id判断回调的方法。
* @param data 输入的参数,传递给服务端的参数
* @param reply 输出的参数,服务器返回的数据
* @param flags 默认传入0
* @return
* @throws RemoteException 远端服务器无响应抛出该错误。
*/
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case TRANSACTION_getDataCount: {
data.enforceInterface(DESCRIPTOR);
int _result = this.getDataCount();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getData: {
data.enforceInterface(DESCRIPTOR);
List<Data2> _result = this.getData();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 代理类,调用transact方法。
*/
private static class Proxy implements IDataManager2 {
private IBinder remote;
Proxy(IBinder remote) {
this.remote = remote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getDataCount() throws RemoteException {
// 输入参数
Parcel _data = Parcel.obtain();
//输出参数
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
remote.transact(TRANSACTION_getDataCount, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public List<Data2> getData() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
List<Data2> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
remote.transact(TRANSACTION_getData, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(Data2.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public IBinder asBinder() {
return remote;
}
}
}
参考博客:
1. binder守护进程servicemanager简介
2. Android Binder机制(一) Binder的设计和框架
3. 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制