湖畔镇

Binder机制

Binder是Android的一种安全且高效的进程间通信机制,安全是因为其发起通信时会写入PID/UID信息,高效是因为传输过程只需要一次内存拷贝

Binder机制

总结

Binder通信模型包含四个角色Client,Service,ServiceManager和Binder驱动,通信过程为:

  1. Server进程需要先向ServiceManager进程注册服务,该过程本身是跨进程的,首先获得ServiceManager服务,然后调用注册方法
  2. Client进程使用服务时需要向ServiceManager获得对应Service
  3. 调用服务中提供的方法

整个过程类似于从电话本上查到对应名字的电话并拨打过去……

基础知识

进程是CPU上运行的单个任务,Linux系统是多进程的,使用虚拟内存实现了进程的隔离,进程都认为独占了整个系统,进程之间数据不共享,需要借助某种机制进行进程间通信

Linux将内存划分为内核空间和用户空间,内核空间不允许应用程序随便访问,应用程序可以通过系统调用进入内核态访问内核空间

一个进程的用户空间如果想要访问别的进程的用户空间,需要借助进程间通信机制,如Linux的Socket,管道,共享内存等,Android则使用了Binder机制,通过Binder驱动实现

Binder跨进程通信原理

Android系统使用代理模式完成Binder通信,Client进程持有Server端的代理,代理对象协助驱动完成了跨进程通信

Java层数据结构

  • IBinder 代表跨进程传输能力的接口,驱动会识别IBinder类型的数据,完成本地对象和代理对象的转换
  • IInterface 代表远程服务能力的接口
  • Binder 代表Binder本地对象,BinderProxy是Binder的内部类,是Binder的本地代理,它们都实现了IBinder,Binder驱动会完成这两种对象的转换
  • Stub 使用AIDL的时候会自动生成Stub类,它继承了Binder,实现了IInterface,是一个抽象类,需要被具体实现

AIDL生成的代码可以看到这几个结构,Android的很多服务基本都是这个样子,比如ActivityManagerService

IActivityManager是具有Activity管理能力的远程接口,ActivityManagerNative实现了该接口,它是一个Binder本地对象,它的内部类ActivityManagerProxy是Binder代理对象,ActivityManagerService继承了ActivityManagerNative,是服务的具体实现类

以ActivityManagerService为例的原理分析

startActivity()为例

Instrumentation.java

1
ActivityManagerNative.getDefault().startActivity()

首先获得ActivityManager服务,然后调用startActivity()

ActivityManagerNative.java

1
2
3
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;

通过ServiceManager获得名为activity的服务,它是一个IBinder

通过asInterface()方法转化成IActivityManager接口,这个对象具有Activity管理能力,显然在应用进程里它应该是一个Binder代理对象

ActivityManagerNative.java

1
2
3
4
5
6
7
8
9
10
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in = (IActivityManager) obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}

通过queryLocalInterface()获取本地接口,如果获取不到则用此Binder创建一个代理对象

Binder.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}

final class BinderProxy implements IBinder {
......
public IInterface queryLocalInterface(String descriptor) {
return null;
}
}

这个方法在BinderBinderProxy中都有实现,Binder中返回了本地对象,而BinderProxy中返回了null,所以在服务端和客户端拿到的IBinder不同

获得IActivityManager之后就可以调用startActivity() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}

按顺序填入参数,然后调用mRemotetransact()方法,这个mRemote就是一个IBinder,最后等待返回值

服务端在onTransact()里面收到客户端发来的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0 ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null;
int result = startActivity(app, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
......
}
return super.onTransact(code, data, reply, flags);
}

根据命令号走对应的条件分支,取出参数,调用服务端中实际的startActivity()方法,最后写回返回值

ServiceManager

ServiceManager是整个Binder机制的守护进程,来管理各种Server,并像Client提供查询Server远程接口的功能

ServiceManager做了三件事:

1.打开Binder设备文件并建立内存映射

2.告诉Binder驱动自己是上下文管理者即守护进程

3.进入无限循环,等待Client的请求

ServiceManager也是一个Server,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过ServiceManager远程接口提供的getService接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于ServiceManager这个Server来说,Client如果想要获得ServiceManager远程接口,却不必通过进程间通信机制来获得,因为ServiceManager远程接口是一个特殊的Binder引用,它的引用句柄一定是0

分享