Binder 是 Android 系统进程间通信(IPC)方式之一,它是基于开源的 OpenBinder 实现的。
基础
Binder 架构简图

所谓 Binder 通信机制:进程 A 和进程 B 分别直接和 Binder Driver 交互,Driver 来负责数据转发,从而间接实现进程 A 和进程 B 之间的数据交互。Binder 架构中通信过程包含四个角色: Client, Server, ServiceManager, Driver。可以从图中看到 Client, Server, ServiceManager 与 Driver 之间都是实线,他们通过 ioctl 直接交互。而 Client, Server, ServiceManager 分属于三个不同的进程,三者交互都是虚线,它们之间是通过 Binder Driver 串起来实现通信的,也就是使用了 Binder 的通信机制。
ServiceManager
中间人,对应一个service_manager开启的守护进程,维护所有服务的列表。Server
服务端进程通过ServiceManager注册服务。服务端进程将服务名和IBinder写入到ServiceManager守护进程维护的服务列表中,是一次进程间通信。Client
客户端进程通过ServiceManager查询服务,即Client进程和ServiceManager守护进程间的通信。查询服务拿到服务端IBinder后,实现Client/Server进程间通信。Driver
实现数据转发。上面三次进程间通信都是Binder通信机制实现的,也就是三个进程都直接和Driver交互,来实现数据转发。
Binder 详细架构图

ServiceManager
具有双重属性,细分为ServiceManager/service_manager。ServiceManager在和Client/Server交互时作为服务端;在和service_manager交互时作为客户端,此时service_manager守护进程为服务端,维护着一个服务链表。Server
服务端通过Java或者CPP代码形式都可以注册。不管什么方式,都是通过的Native中BBinder向service_manager守护进程注册的,并写入守护进程维护的服务列表。Client
客户端也可以通过Java或者CPP代码形式查询服务,最终都是通过Native中BpBinder从service_manager守护进程查询,并返回IBinder。DriverServer, Client, ServiceManager运行于用户空间,Driver属于内核空间,他们都是通过IBinder来通信的。Driver的作用就是用来转发数据:
A:Client持有IBinder,通过它来实现和Driver通信
B:Server本身就是IBinder,直接和Driver通信
C:service_manager守护进程可以直接下发ioctl和Driver通信;这四个角色的关系和互联网类比:Server是服务器,Client是客户终端,ServiceManager是域名服务器(DNS),Driver是路由器。
Binder 机制特点
service_manager维护一个链表,用来添加或查询服务Binder Driver实现进程间的数据交互
Android Binder 机制在 Android 系统中江湖地位非常之高。在 Zygote 孵化出 system_server 进程后,system_server 进程会初始化支撑整个 Android Framework 的各种各样的 Service,另外在 init.rc 中也会启动很多 Service,这些服务几乎都是基于 Binder IPC 机制。
三个基本概念
IBinder
表示拥有被跨进程传输的能力。IBinder是远程对象的基本接口,定义了与远程对象交互的协议。IBinder是一种传输方式(类比Socket),代表Binder通信机制,只有它的对象才能通过Binder机制跨进程通信;也可以认为IBinder是一个数据类型(类比Object, String等),它能被写入Parcel中。IInterface
定义远程接口,表示服务端拥有什么能力,能提供哪些服务,并提供了转换为IBinder的方法。Parcel
是一个缓冲区,除了存储基本数据类型,Parcelable数据类型等,还可以传递IBinder对象。区别于Java中Serializable可以将数据保存到存储介质上,Parcel仅存储在内存中,属于轻量级序列化机制。Binder通信机制跨进程传输的数据,是存储在Parcel中的。
Client/Server 两个角色在使用过程中并不用关心 Binder 的通信过程,这些是 Android 系统已经实现了的。Client/Server 只需要按照 Binder 机制中规定实现相应的 IBinder/IInterface,系统将完成这个通信过程。
源码目录结构速查表
整个 Binder 框架目录结构
1 | frameworks/base/core/java/ (Java) |
Java Framework
1 | frameworks/base/core/java/android/os/ |
Native Framework
1 | frameworks/native/libs/binder |
kernel Driver
1 | kernel/drivers/staging/android/ |
Binder Java 类图

通常来讲,对于 Server 进程,Binder 指的是 Binder 本地对象;对于 Client 进程,Binder 指的是 BinderProxy 对象,它只是 Binder 本地对象的一个远程代理。对 BinderProxy 对象的操作,会通过驱动最终转发到 Binder 本地对象上去完成。对于一个拥有 Binder 对象的使用者而言,它无须关心这是一个 BinderProxy 对象还是 Binder 本地对象,对于代理对象的操作和对本地对象的操作对它来说没有区别。
在驱动中,Binder 本地对象的代表是一个叫做 binder_node 的数据结构,BinderProxy 对象是用 binder_ref 代表的。有的地方把 Binder 本地对象直接称作 Binder 实体,把 BinderProxy 对象直接称作 Binder 引用(句柄),其实指的是 Binder 对象在驱动里面的表现形式。
类和接口对应文件
1 | IInterface.java: IInterface |
BinderProxy
Client 持有,也可以理解为远程端,下发命令。
transact发送命令mObject保存BpBinder的引用
Binder
Server 持有,也可以理解为本地服务端,响应命令。
Binder.onTransact响应命令并处理mObject保存JavaBBinderHolder的引用
AIDL 文件
自定义的 AIDL 文件,编译时会自动生成对应的 ICustomAIDLInterface.java 文件,这个文件包含 ICustomAIDLInterface, Stub, Proxy 三个类或接口。
Stub和Proxy都实现了ICustomAIDLInterfaceClient拥有ICustomAIDLInterface对象,实际是ProxyServer拥有Stub对象,并实现CustomAIDLInterface抽象方法
使用模板:
1 | // Client |
没有 ServiceManager 的参与,是因为所有的动作都是在 ActivityManager 中实现的。而 ActivityManager 完成了服务的注册和查询,它也是一次 Binder 通信。
Stub
客户辅助对象,常译为“桩”。它是 ICustomAIDLInterface 的内部抽象类。
- 和
IBinder的关系是is-a,继承了Binder asBinder返回的是this,即Binder对象asInterface返回是Proxy,引用了BinderProxy对象
Stub同时实现了IInterface和IBinder,所以它是整个Binder Java框架的中转站,通过asInterface/asBinder转换为需要的接口。
Proxy
Stub 的私有内部类。
- 和
IBinder的关系是has-a,引用了BinderProxy对象 mRemote指向BinderProxy对象asBinder()返回mRemote
IInterface
1 | public interface IInterface { |
该接口只包含一个方法:asBinder,即将 IInterface 转换为 IBinder。客户端只有 IInterface 实例,需要转换为 IBinder 后才能跨进程通信。
IBinder
FLAG_ONEWAYBinder机制中客户端和服务端通信默认是阻塞式的,但如果设置了FLAG_ONEWAY,将成为非阻塞的调用,客户端能立即返回,服务端采用回调方式来通知客户端完成情况。DeathDecipient
死亡通知,是一个回调接口。当进程不再持有IBinder时,会通过这个回调来通知。IBinder通过linkToDeath/unlinkToDeath来绑定和解绑。
BinderInternal
getContextObject
静态方法:BinderInternal.getContextObject(),返回IBinder,专供ServiceManager拿到IServiceManager的引用。GcWatcher
内部类,用于处理和调试与Binder相关的垃圾回收。
Binder CPP 类图

Client 端持有 ICustomServiceInterface,实际对应的是 BpCustomServiceInterface,它会通过 BpRefBase.mRemote 指向的 BpBinder 拿到 mHandle,而这个 mHandle 句柄指向 BBinder。也就是 mHandle 将 Client端和 Server 端连接起来。Server 端继承 BnCustomServiceInterface,它继承 BBinder,直接注册服务。
类和接口对应文件
1 | IBinder.h: IBinder |
命名规则
Bp***Binder proxy表示代理,是客户端持有的一个代理对象。Bn***Binder native与Bp相对表示本地,是本地对象。但BBinder是一个特例,有点命名混乱的感觉。
BpBinder
transact
客户端持有后,BpBinder.transact()用于发送命令。mHandle
在构造函数中初始化,表示连接的BBinder的句柄(句柄:操作系统在进程的地址空间会存储一张句柄表,每个编号内都存储一个地址,这个地址指向实际的对象,而句柄就是这个编号。这么做系统不用暴露对象的实际地址给其他进程,可以认为句柄为指针的指针,但是句柄只能由系统来解析)。所以mHandle是Driver生成的,仅在Driver中有用。Binder Driver转发数据时,通过它能找到BpBinder/BBinder对象。BpBinder* remoteBinder();
实现该方法,返回this。
BBinder
onTransact
本地服务端,BBinder.onTransact()用于响应命令并处理。BBinder* localBinder();
实现该方法,返回this。
IBinder 通过 remoteBinder/localBinder 来区分具体是代理还是实体实例。
BpRefBase
mRemote 指针指向 IBinder,具体是 BpBinder 对象。
IInterface 及重要的宏
asBinder
返回IBinder的强指针。BpInterface
模板类,同时继承了ICustomServiceInterface和BpRefBase。onAsBinder返回mRemote,它指向了BpBinder。BnInterface
模板类,同时继承了ICustomServiceInterface和BBinder。onAsBinder返回this,即BBinder本身。DECLARE_META_INTERFACE宏
定义了asInterface和getInterfaceDescriptor,以及构造和析构函数,在ICustomServiceInterface.h文件中调用。IMPLEMENT_META_INTERFACE宏
实现了asInterface和getInterfaceDescriptor,以及构造和析构函数,在ICustomServiceInterface.cpp文件中调用。asInterface
即上面两个宏实现的函数,将IBinder(BpBinder)转换为BpCustomServiceInterface。interface_cast
模板函数,调用了上面宏定义的asInterface,即将IBinder转换为ICustomServiceInterface。
ICustomServiceInterface
客户自定义的接口类,继承了 IInterface。注意:需要在 .h 文件中调用宏 DECLARE_META_INTERFACE,在 cpp 文件中调用宏 IMPLEMENT_META_INTERFACE,实现 asInterface 函数。
BpCustomServiceInterfaceBpInterface的具体实现,功能对应Java中的Proxy,在cpp文件中定义,实现接口文件中的具体方法,通过BpBinder.transact下发命令。BnCustomServiceInterfaceBnInterface的具体实现,功能对应Java中的Stub,在h文件中定义,申明onTransact响应并处理命令。
BnCustomServiceInterface同时继承了IInterface和IBinder,同理它是Binder CPP的中转站,通过onAsBinder/asInterface来转换。
Binder Java/CPP 转换对应类图

Binder Java 最终都会转换为 Binder CPP 来实现整个 Binder 通信机制。
JavaBBinderHolder
用来管理 JavaBBinder 的实例,使用弱指针指向了该实例。
JavaBinder
mObject
保存了服务端注册服务时的IBinder引用,也就是说实际指向的是ICustomAIDLInterface.Stub(可以查看 server_init 序列图)。
android_util_Binder.cpp
Java/CPP 衔接文件:android_util_Binder.cpp: JavaBBinder, JavaBBinderHolder, JavaDeathRecipient,仅在通过 Java 代码注册服务时才会使用到。Android Runtime 在开启时,注册了 REG_JNI(register_android_os_Binder),而 android_util_Binder::register_android_os_Binder 实现了对 Binder Java/CPP 的关联,即对相关 mObject 赋值,以及 Java native 代码的映射。
1 | // android_util_Binder.cpp |
Binder 机制中的设计模式
代理模式

先看代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。代理模式中,代理和被代理对象继承相同的接口,实现相同的方法。控制被代理对象的访问权限或者隐藏被代理对象的远程操作等等。代理模式类似经纪人角色,可以起到保护明星的功能。
整个 Binder 通信机制都是基于代理模式,远程代理就好比“远程对象的本地代表”,所以跨进程交互或者说 C/S 结构,非常适合使用代理模式。因为是跨进程通信,客户端进程并不能直接拿到服务端的实例对象,只能通过远程代理(BpBinder)来访问服务端(BBinder),这样相互通信看起来像是两个本地对象在交互,而远程代理在幕后默默的和服务端通信,客户端并不清楚这个过程。另外,通过代理模式,Binder 机制能够控制访问权限,大大提供安全性。
单例模式
ProcessState, IPCThreadState, IServiceManager 都是使用的单例模式。
1 | // ProcessState.cpp |
桥接模式

桥接模式连接着不同分类的两端,比如 Proxy 连接了 IInterface, IBinder。
1 | private static class Proxy implements com.***.ICustomAIDLInterface { |
Parcel 在 Binder 机制中的作用
定义
先看一段 Parcel.java 中的注释:
1 | * Container for a message (data and object references) that can |
Parcel 是一个容器包含了数据或对象的引用,它能够通过 IBinder 来传输。Parcel 能够包含序列化的数据,这些数据可以被 IPC 通信的另一端反序列化(通过各种 write 方法或者 Parcelable 接口);并且可以包含一个 IBinder 对象的引用,这个引用会让对方接受到一个和该 IBinder 对象已经连接好的代理。Parcel 是整个 Binder 机制中,数据传输的载体,存储了所有需要跨进程通信的数据,包含 IBinder 也可存储到 Parcel 中。这个读写都是基于内存的,所以效率会比 Java Serializable 基于外部存储的要高。
文件路径
1 | frameworks/base/core/java/android/os/Parcel.java |
通过 jni 实现 native 的方法,jni 是在 AndroidRuntime 运行时初始化。
Binder 相关 API
1 | // Parcel.java |
Parcel 数据模型

Parcel 的数据区域分两个部分:mData 和 mObjects,所有的数据不管是基础数据类型还是对象实体,全都追加到 mData 里,mObjects 是一个偏移量数组,记录所有存放在 mData 中的 flat_binder_object 实体的偏移量。

offsets_size, data.offsets 两个成员是 Binder 通信有别于其它 IPC 的地方。Binder 采用面向对象的设计思想,一个 Binder 实体可以发送给其它进程从而建立许多跨进程的引用;另外这些引用也可以在进程之间传递,就象 Java 里将一个引用赋给另一个引用一样。为 Binder 在不同进程中建立引用必须有驱动的参与,由驱动在内核创建并注册相关的数据结构后接收方才能使用该引用。而且这些引用可以是强类型,需要驱动为其维护引用计数。然而这些跨进程传递的 Binder 混杂在应用程序发送的数据包里,数据格式由用户定义,如果不把它们一一标记出来告知驱动,驱动将无法从数据中将它们提取出来。于是就使用数组 data.offsets 存放用户数据中每个 Binder 相对 data.buffer 的偏移量,用 offsets_size 表示这个数组的大小。驱动在发送数据包时会根据 data.offsets 和 offset_size 将散落于 data.buffer 中的 Binder 找出来并一一为它们创建相关的数据结构。在数据包中传输的 Binder 是类型为 struct flat_binder_object 的结构体。对于接收方来说,该结构只相当于一个定长的消息头,真正的用户数据存放在 data.buffer 所指向的缓存区中。如果发送方在数据中内嵌了一个或多个 Binder ,接收到的数据包中同样会用 data.offsets, offset_size 指出每个 Binder 的位置和总个数。不过通常接收方可以忽略这些信息,因为接收方是知道数据格式的,参考双方约定的格式定义就能知道这些 Binder 在什么位置。
Binder 进程和线程管理
文件路径
1 | frameworks/native/libs/binder/ProcessState.cpp |
概述
Android 系统特别为程序进程使用 Binder 机制封装了两个实现类,即 ProcessState/IPCThreadState。
ProcessState
是进程相关的,负责打开Binder驱动设备,进行mmap()等准备工作。IPCThreadState
是线程相关的,负责与Binder驱动进行具体的命令通信。
ProcessState.cpp
单例模式特性
只能通过单例模式获取ProcessState对象,用于创建Binder线程:sp<ProcessState> proc = ProcessState::self();。而构造函数中会打开Binder设备,单例模式的设计可以确保每个进程的Binder设备只会被打开一次。1
2
3
4
5
6
7
8
9
10
11// 单例模式
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
// gProcess在 Static.cpp 中定义的全局变量
gProcess = new ProcessState;
return gProcess;
}线程数
每个APP在启动时都会创建名称为Binder_X的线程,最少会创建 2 个(Binder主线程和当前加入的线程),最多会创建 15 个,可以通过命令查看:
命令:adb shell; ps -t | grep -irs "binder*"1
2
3
4
5
6
7
8
9
10
11
12#define DEFAULT_MAX_BINDER_THREADS 15
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
if (fd >= 0) {
...
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
...
}
return fd;
}创建线程
使用ProcessState来创建线程池,并且确保每个进程的线程池只会被创建一次,并且会创建第一个PoolThread主线程。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20proc->startThreadPool(); //或者
ProcessState::self()->startThreadPool();
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}PoolThread
线程池在开启时,会创建一个主线程PoolThread。这个类很简单,仅仅是作为主线程加入了线程池:IPCThreadState::self()->joinThreadPool(mIsMain);。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
Binder 进程大小不超过 1M
Binder 是轻量级进程间通信机制,传输的数据大小不能超过 1M。
1 | // ProcessState.cpp |
ProcessState 常用 API
1 | // 单例,获取对象 |
IPCThreadState.cpp
万众归一
joinThreadPool
可以看到不管是ProcessState创建的线程,还是其他应用线程,最终都是通过joinThreadPool来加入Binder线程池的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 头文件定义,默认为 true
void joinThreadPool(bool isMain = true);
void IPCThreadState::joinThreadPool(bool isMain)
{
...
// 主线程和其他线程 BC 码不一样
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
...
// 如果是主线程将进入无限循环,处理请求信息
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
...
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
...
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}两个重要数据存储
mIn, mOut:mIn用来接收来自Binder Driver的数据,mOut用来存储发往Binder Driver的数据。请求码和响应码
BINDER_COMMAND_PROTOCOL:请求码,以BC_开头,简称BC码,请求命令用于用户空间向内核空间发出请求。BINDER_RETURN_PROTOCOL:响应码,以BR_开头,简称BR码,用于响应返回命令,内核空间向用户空间返回响应。向驱动发送请求码
IPCThreadState各个API会将请求码写入mOut,最终都会通过talkWithDriver写入Binder Driver。处理驱动返回的响应码
响应信息都会通过mIn传递回Native层。1
2
3status_t IPCThreadState::executeCommand(int32_t cmd)
status_t IPCThreadState::waitForResponse(Parcel *reply,
status_t *acquireResult)AIDL中的oneway关键字处理AIDL中是否定义oneway关键字,主要是在传递的过程中会体现:1
2
3
4// 没有使用 oneway
mRemote.transact(***, _data, null, 0);
// 使用了 oneway
mRemote.transact(***, _data, null, android.os.IBinder.FLAG_ONEWAY);
而这个标记最终会在这里解析:
1 | status_t IPCThreadState::transact(int32_t handle, |
代码中可以看到,oneway 关键字决定了是否阻塞等待 waitForResponse 以及响应时是否发送回执 sendReply。
Binder 机制驱动交互
真正与 Binder Driver 交互的地方是 talkWithDriver 中的 ioctl(),通过它 BINDER_WRITE_READ 命令写入 Binder Driver。
1 | status_t IPCThreadState::talkWithDriver(bool doReceive) |
IPCThreadState 常用 API
1 | // 加入 Binder 线程池 |
至少 2 个 Binder 线程
在所有使用 Binder 机制的示例中,都能看到初始化时至少会执行如下两句:
1 | int main(...){ |
从前面的分析可以看到:
ProcessState::self()->startThreadPool();
开启线程池,也就是新建一个Binder主线程,名称为Binder_1。IPCThreadState::self()->joinThreadPool();
当前线程加入线程池,也就是将当前线程变为Binder线程。
我们在分析 startThreadPool() 时可以看到,新建了一个 PoolThread 异步调用 joinThreadPool(),同时应用主线程同步调用了 joinThreadPool,阻塞等待。代码中可以看出,这两个都是 Binder 主线程,但是线程名不一样,同步调用 joinThreadPool() 的目的之一是确保 startThreadPool 异步产生的线程不会因为执行到了 main 函数结尾而被迫退出;目的之二可能是为了提高 Binder 线程处理的吞吐量,都可以等待并处理请求。
Binder 线程总结
Binder 系统中可分为 3 类线程:
Binder主线程ProcessState::self()->startThreadPool();创建Binder主线程。编号从 1 开始,即主线程名为Binder_1,并且主线程是不会退出的。Binder普通线程
由Binder Driver来决定是否创建Binder线程,发回消息BR_SPAWN_LOOPER后回调spawnPooledThread(false)创建普通线程,该线程名格式为Binder_X。Binder其他线程
其他线程是指并没有调用spawnPooledThread方法,而是直接调用IPCThreadState::self()->joinThreadPool,将当前线程直接加入Binder线程队列。
ServiceManager
双重属性
ServiceManager 它既是客户端也是服务端。
- 作为服务端
IServiceManager.java/IServiceManager.cpp:其他进程都是通过它们来查询或注册服务的。不过在Java代码中,ServiceManager.java是对IServiceManager.java的一个封装,同时保存了一个Cache,即Java层通常是通过ServiceManager.java来访问的,而不是直接调用IServiceManager.java。 - 作为客户端
service_manager.c:手机开机时init.rc会开启一个名称是小写的servicemanager服务,它是由service_manager.c实现的守护进程,为了做区分本文将守护进程服务命名重命名为service_manager。守护进程开启后会进入无限循环,只有两个功能:注册服务和查询服务。IServiceManager.cpp和service_manager.c是一个完整的Binder通信流程。ServiceManager可以看做客户端,service_manager守护进程可以看做是服务端。这部分的通信过程是系统实现的,可以认为对用户透明,所以通常将ServiceManager和service_manager合二为一,统称为ServiceManager。
ServiceManager 存在的意义
在 Android 系统中,所有 Service 都需要加入到 ServiceManager 来集中管理。这样客户端可以很方便的通过服务名称从系统查询服务,同时 ServiceManager 会向客户端提供服务端的 IBinder,用于客户端和服务端的 Binder 通信。而且这个过程都是系统自动完成,系统屏蔽了整个通信机制,只开放两个接口:
1 | public static void addService(String name, IBinder service) {...} |
C/S 模型
- 注册服务
addServiceServer进程向ServiceManager注册服务。该过程:Server是客户端,ServiceManager是服务端。 - 获取服务
getServiceClient进程向ServiceManager获取相应的服务。该过程:Client是客户端,ServiceManager是服务端。 - 使用服务
Client得到服务的IBinder与Server进程通信,然后就可以通过Binder Driver交互数据。该过程:Client是客户端,Server是服务端。
Java 层的类图

ServiceManagerProxy
其成员变量mRemote指向BinderProxy对象,ServiceManagerProxy:addService, getService方法最终是交由mRemote来完成。ServiceManager
通过getIServiceManager方法获取的是ServiceManagerProxy对象。ServiceManager:addService, getService实际工作都交由ServiceManagerProxy的相应方法来处理。ServiceManagerNativeasInterface()返回的是ServiceManagerProxy对象,ServiceManager是通过ServiceManagerNative类来找到ServiceManagerProxy的。
CPP 层的类图

BpServiceManager
同时继承了IServiceManager, BpInterface,其中BpInterface继承BpRefBase,而BpRefBase.mRemote指向了BpBinder。BpBinder.mHandle为指向BBinder的句柄,通过这个句柄实现Binder间的通信。IServiceManager
单例模式IServiceManager::defaultServiceManager获取到BpServiceManager实例。
对比 Binder_CPP 核心类图,缺失了 BnServiceManager 这个类。那谁来充当 onTransact 的调度工作呢?它就是 service_manager.c 守护进程!
IServiceManager::defaultServiceManager
从类图中可以看到,IServiceManager 并没有对应的注册服务,只提供了查询即 defaultServiceManager。得到 handle 句柄为 0 的 BpBinder,而 0 号句柄对应的 BBinder 实际为 service_manager 守护进程。
1 | // Static.cpp 中定义 |
时序图:
总结:
defaultServiceManager等价于new BpServiceManager(new BpBinder(0));handle为 0 的句柄,代表ServiceManager所对应的BBinder
示例:
1 | //获取service manager引用 |
service_manager 守护进程
文件路径
1 | frameworks/native/cmds/servicemanager/servicemanager.rc |
守护进程
由 init.rc 开启的守护进程,对应 service_manager.c 文件。
1 | // 对应 rc 文件:Servicemanager.rc |
主程序
1 | // service_manager.c |
主程序逻辑很简单:
- 打开
Binder Driver,申请 128k 字节大小的内存空间 - 注册成为
Binder服务的大管家,也就是对应BBinder句柄为 0 - 进入无限循环,处理客户端发来的请求
服务链表
无论调用 Java/CPP API,每个服务最终加入 svclist 单向链表中保存。我们也可以看到 svcinfo 这个结构体实际只保存了服务的名称和句柄(这个句柄就是 BpBinder.mHandle)。

查看系统已经注册了的所有服务:
adb shell service list
1 | struct svcinfo |
守护进程注册为大管家
binder_become_context_manager 在 Native 层,很简单仅仅是下发了 BINDER_SET_CONTEXT_MGR 的 ioctl 命令,具体见 Driver 部分分析。
1 | int binder_become_context_manager(struct binder_state *bs) |
这个命令在驱动中实现了如下功能:
- 告诉驱动,当前进程即
Binder上下文管理者 - 新建对应于
Context Manager的binder_node(即BBinder对应的驱动结构体) - 新建
binder_ref,设置句柄为 0,并设置引用地址为上面这个Binder实体
核心工作
service_manager 会无限循环读取和处理:服务注册或查询请求(由 IServiceManager 发出),和 IPCThreadState::talkWithDriver 一样,向驱动下发 BINDER_WRITE_READ 命令,读取并解析驱动返回的信息。
1 | void binder_loop(struct binder_state *bs, binder_handler func) |
服务注册
系统所有服务,最终会在这里实现注册。从 svcmgr_handler 可以看到,服务注册调用的是 do_add_service,新建一个 svcinfo 保存基本的名称和句柄,并加入链表。句柄是驱动创建 Binder 实体对象时生成,同时还会生成一个 Binder 引用对象指向它。
1 | int do_add_service(struct binder_state *bs, |
服务查询
系统中查询对应的服务,从 svcmgr_handler 可以看到,服务查询和检查都是调用的 do_find_service,通过服务的名称来匹配,并返回句柄。为什么只需要返回句柄就可以了?从后面的驱动分析中可以了解到,驱动通过句柄可以找到相应的 Binder 引用对象,而 Binder 引用对象的结构体中保存了 Binder 实体对象。也就是说通过句柄能同时找到 Binder 的引用和实体对象。
1 | uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid) |
IServiceManager.cpp/service_manager.c 通信流程
在前面的分析中,IServiceManager.cpp 只对应生成了 BpServiceManager类,而没有 BnServiceManager 类的存在,也就是说在 IServiceManager 中并没有注册服务,只提供了查询服务 defaultServiceManager。而守护进程 service_manager.c 只注册成为了上下文大管家,并在驱动中新建了 binder_node 并赋值给变量 binder_context_mgr_node。IServiceManager.cpp/service_manager.c 之间是如果串起来的呢?也就是 service_manager.c 如何完成了 BnServiceManager 的功能?这些都是在 Binder Driver 中实现的,下面先做个简要分析。在 Binder 通信机制中,BpBinder.mHandle 找到对应的 BBinder,是在 Binder Driver 的 binder_transaction 中实现的。
路由逻辑是:如果 handle 为真,则通过 handle 在红黑树中找到 bind_ref(即 Native 层中的 BpBinder),而这个结构体中保存了通信对应的 binder_node(即 Native 层中的 BBinder);如果 handle 不为真,即句柄为 0,则返回 binder_context_mgr_node。
也就是说句柄为 0 时,对应的就是和 service_manager 通信,而 IServiceManager::defaultServiceManager 查询服务时,也就明白为什么要直接赋值句柄为 0 了。
1 | driver: binder.c |
Binder Driver 驱动
Binder Driver 是整个 Binder 通信机制的核心,它工作于内核态,负责进程之间通信的建立,数据在进程之间转换和传递,每个进程中最大线程数为 15 个。
文件路径
1 | ./drivers/staging/android/binder.h |
在 kernel 3.19 之后,默认已经合入到 kernel master 分支中了。
1 | ./drivers/android/binder_alloc.h |
数据结构
binder_proc:Binder进程
对应于用户空间的ProcessState,每个进程调用open()打开Binder驱动都会创建该结构体,用于管理IPC所需的各种信息。binder_thread:Binder线程
对应于上层的Binder线程。binder_node:Binder实体
对应于BBinder对象,记录BBinder的进程、指针、引用计数等。binder_ref:Binder引用binder_node实体对象的引用,对应于BpBinder对象,记录BpBinder的引用计数、死亡通知、BBinder指针等。binder_ref_death:Binder死亡引用
记录Binder死亡的引用信息。flat_binder_object:IBinder扁平对象IBinder对象在两个进程间传递的扁平结构。
Binder 对象之间的引用关系

BBinder被binder_node引用binder_node被binder_ref引用binder_ref被BpBinder引用BBinder和BpBinder运行在用户空间binder_node和binder_ref运行在内核空间
调用顺序:Client -> handle -> binder_ref -> binder_node -> Service。
Binder 通信机制高效原理
- 用户空间和内核空间简介
Linux操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中。用户空间的内存映射采用段页式,而内核空间有自己的规则。 - 虚拟进程空间
通常 32 位Linux内核虚拟地址空间总共为 4G:划分 03G 为用户空间,34G 为内核空间(注意,内核可以使用的线性地址只有 1G)。注意这里是 32 位内核地址空间划分,64 位内核地址空间划分是不同的。也就是说每个进程可以使用 4G 的虚拟内存,但是实际物理内存可能只用了几兆。 - 内核和用户虚拟内存空间映射
首先在内核虚拟地址空间,申请一块与用户虚拟内存相同大小的内存;然后申请 1 个页大小的物理内存,再将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,从而实现了用户空间的和内核空间的Buffer同步操作的功能。而这种同时映射的方法,使得用户空间和内核空间将不需要做数据拷贝了。就是Binder进程间通信机制的精髓所在了,Server进程内核空间会将Client进程的数据从用户空间拷贝到内核空间,进程间仅仅需要一次数据拷贝,大大提高了通信效率。

1 | // ProcessState.cpp |
handle 句柄的生成
服务注册时(addService),在驱动中生成对应的 binder_node 实体对象,以及 binder_ref 引用对象,此时会根据红黑树来生成对应的 handle 值。

1 | // 用户调用到驱动的流程 |
这里我们也可以看到,当
binder_node节点为上下文大管家对象binder_context_mgr_node时,句柄赋值为 0 时。也就解释了为什么IServiceManager::defaultServiceManager对应 0 的问题了。
查询服务时(getService),得到的是句柄,在 IServiceManager::defaultServiceManager 的分析中,可以看到 ProcessState::getStrongProxyForHandle 会通过句柄初始化一个 BpBinder 返回给客户端。