先来一张图熟悉下各进程之间的关系

一、ServiceManager 启动
解析 servicemanager.rc
servicemanager 是 Android 系统中最早启动的核心守护进程之一。它的生命周期由 init 进程直接管理。 当 Android 内核启动完毕后,会启动用户空间的第一个进程 init。init 进程会去解析一系列的 .rc 配置文件,就包括 servicemanager.rc。
frameworks/native/cmds/servicemanager/servicemanager.rc
c
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart apexd
onrestart restart audioserver
onrestart restart gatekeeperd
onrestart class_restart main
onrestart class_restart hal
onrestart class_restart early_hal
writepid /dev/cpuset/system-background/tasks
shutdown critical
当 init 解析到这里时,会将 servicemanager 归类为 core 级的服务。 在 init 阶段的后期,会通过 class_start core 命令通过 fork + execve 正式拉起 /system/bin/servicemanager 进程。
启动 servicemanager
打开Binder驱动 、 成为Context Manager 进程拉起后,直接进入 servicemanager 的 main 函数。
frameworks/native/cmds/servicemanager/main.cpp
c
int main(int argc, char** argv) {
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
}
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
// 打开 Binder 驱动,并将自己映射到内存空间
sp<ProcessState> ps = ProcessState::initWithDriver(driver);
// 因为 servicemanager 采用了 Looper 的事件循环机制,不需要 Binder 线程池
// 这里设置为单线程
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
}
IPCThreadState::self()->setTheContextObject(manager);
// 核心!通过 ioctl(BINDER_SET_CONTEXT_MGR) 告诉驱动我是老大(Handle为0)
ps->becomeContextManager();
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
// 将 Binder 驱动的 file descriptor 加入 epoll 监听
BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);
while(true) {
// 阻塞等待客户端(如 system_server)发来请求
looper->pollAll(-1);
}
// should not be reached
return EXIT_FAILURE;
}
至此,servicemanager 启动完毕,静静等待其他进程(如注册服务、查询服务)的打扰。
二、打开 binder 驱动
frameworks/native/libs/binder/ProcessState.cpp
ProcessState 是用户空间进程与 Binder 驱动沟通的桥梁。它是一个 进程单例,主要负责打开 Binder 驱动、进行内存映射(mmap)以及管理该进程的全局 Binder 状态。
c
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
...
// 构造函数
ProcessState::ProcessState(const char* driver)
: mDriverFD(open_driver(driver)) // 1. 打开驱动
, mVMStart(MAP_FAILED) // 2. 内存映射的起始地址
, ...
{
if (mDriverFD >= 0) {
// 3. 执行 mmap,将驱动的虚拟内存映射到当前进程的空间
// BINDER_VM_SIZE 在普通进程中通常是 (1MB - 2个页面),servicemanager 为 128KB
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ,
MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
close(mDriverFD);
mDriverFD = -1;
}
}
}
2.1 open_driver()
c
int fd = open(driver, O_RDWR | O_CLOEXEC);
这里以读写模式(O_RDWR)打开 /dev/binder 设备文件。O_CLOEXEC 确保该进程如果 fork 出子进程并执行 exec 时,该文件描述符会自动关闭,防止安全泄漏。
2.2 校验版本
c
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
// 版本不匹配则报错关闭
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
通过 ioctl 的 BINDER_VERSION 命令读取内核驱动的 Binder 版本,确保用户空间的 libbinder 和内核驱动的协议版本完全一致。
2.3 设置最大线程数
c
#define DEFAULT_MAX_BINDER_THREADS 15
...
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
通过 BINDER_SET_MAX_THREADS 告知内核驱动,该进程的 Binder 线程池最多可以自动创建多少个线程来处理并发请求。
2.4 开启泛洪攻击检测
c
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
这是 Android 为防止 Binder 异步调用被滥用而设置的一道内核级安全阀门。
完整流程如下所示:
c
open_driver()
│
├── open("/dev/binder")
│ │
│ └── 打开Binder设备
│
├── ioctl(BINDER_VERSION)
│ │
│ └── 检查驱动版本是否匹配
│
├── ioctl(BINDER_SET_MAX_THREADS)
│ │
│ └── 设置Binder线程池最大线程数
│
└── ioctl(BINDER_ENABLE_ONEWAY_SPAM_DETECTION)
│
└── 开启oneway事务洪泛检测
三、成为上下文管理者 becomeContextManager
只有 servicemanager 进程有资格成为上下文管理者。在 ProcessState.cpp 中,该功能的实现极其简洁,但分量极重:
c
bool ProcessState::becomeContextManager()
{
AutoMutex _l(mLock);
// 构造一个 flat_binder_object 结构体
flat_binder_object obj;
memset(&obj, 0, sizeof(obj));
obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; // 开启安全上下文传输检查
// Android 12 核心系统调用
int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
// 如果内核不支持带扩展参数的命令,则回退到传统命令
if (result != 0) {
android_errorWriteLog(0x534e4554, "121035042");
int dummy = 0;
result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
}
return result == 0;
}
当 BINDER_SET_CONTEXT_MGR_EXT 被调用时,内核会:
- 验证调用者是否具有 binder:set_context_mgr SELinux 权限
- 将该进程的 binder_proc 标记为 context manager
- 此后所有 BINDER_TYPE_HANDLE 的服务注册/查找请求都路由到该进程
创建 0 号句柄:内核会为当前进程(即 servicemanager)专门创建一个特殊的内核 Binder 实体节点。所有其他进程在尝试获取"Handle = 0"的 Binder 引用时,驱动都会自动将请求路由到这个节点。
四、 进入循环等待消息到来
在打开驱动、做好映射、确立身份后,进程必须进入一个无限循环,等待并处理来自驱动的 IPC 事务。 对于普通的系统服务或 App 进程,它们使用的是 IPCThreadState 机制;而对 servicemanager 而言,Android 12 使用了更为现代的 Looper (基于 Linux epoll)。但无论哪种,它们底层的核心逻辑都是一致的:阻塞在驱动的读操作上。
c
sp<Looper> looper = Looper::prepare(false);
// ① Binder 事务(服务注册/查询)
BinderCallback::setupTo(looper);
// ② 客户端死亡通知 + 超时检测等非Binder事件
ClientCallbackCallback::setupTo(looper, manager);
while(true) {
looper->pollAll(-1); // 统一等待两类事件
}
BinderCallback 在 frameworks/native/cmds/servicemanager/main.cpp 中
c
class BinderCallback : public LooperCallback {
public:
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
sp<BinderCallback> cb = sp<BinderCallback>::make();
int binder_fd = -1;
IPCThreadState::self()->setupPolling(&binder_fd);
LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
// 【核心】将 binder fd 添加到 Looper 的 epoll 监听列表
// EVENT_INPUT = EPOLLIN,即监听"有数据可读"
int ret = looper->addFd(binder_fd, // binder fd
Looper::POLL_CALLBACK, // 使用回调模式
Looper::EVENT_INPUT, // 监听可读
cb, // 回调对象
nullptr /*data*/);
LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");
return cb;
}
int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
// 处理单次任务
IPCThreadState::self()->handlePolledCommands();
return 1; // Continue receiving callbacks.
}
};
c
status_t IPCThreadState::setupPolling(int* fd)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
// 向内核声明当前线程进入 Looper 模式
mOut.writeInt32(BC_ENTER_LOOPER);
// 立即将 BC_ENTER_LOOPER 写入内核
flushCommands();
// 通过出参返回 binder fd,供 Looper::addFd 使用
*fd = mProcess->mDriverFD;
return 0;
}
status_t IPCThreadState::handlePolledCommands()
{
status_t result;
do {
// 批量消费所有已到达的命令
result = getAndExecuteCommand();
// 循环条件:只要 mIn 中还有未解析的数据就继续
} while (mIn.dataPosition() < mIn.dataSize());
// 处理延迟的引用计数操作
processPendingDerefs();
// 发送本批次产生的所有出站命令
flushCommands();
return result;
}
其中 mIn和 mOut 定义在下面文件中它们是 类中的成员变量,类型为Parcel
frameworks/native/libs/binder/include/binder/IPCThreadState.h
c
class IPCThreadState {
// ...
private:
Parcel mIn; // 入站缓冲区:存放从内核读取的 BR_* 命令及负载
Parcel mOut; // 出站缓冲区:存放待发送给内核的 BC_* 命令及负载
// ...
};
后面的talkWithDriver(false)就是将 mOut 的内容通过 ioctl 写入内核,同时将内核返回的数据填充到 mIn 中,并重置 mIn 的读游标到起始位置。
无论是添加服务还是查询服务,本质上都是一次 Binder Transaction (事务)。 数据的流动方向
- 发送端 (Client): 调用
IPCThreadState::transact()->writeTransactionData()-> 将请求打包成BC_TRANSACTION写入mOut->talkWithDriver()将数据发送给内核。 - 接收端 (Server / ServiceManager): 阻塞在
talkWithDriver()-> 收到数据,读取到BR_TRANSACTION->executeCommand()进行处理。
看一张图,加深一下印象:

4.1 getAndExecuteCommand
c
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver(); // 1. 阻塞等待驱动的数据
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32(); // 2. 读取命令字 (例如 BR_TRANSACTION)
// ... 省略线程池管理代码 ...
result = executeCommand(cmd); // 3. 执行具体的命令逻辑
// ...
}
return result;
}
4.2 talkWithDriver
talkWithDriver(bool doReceive) 的核心职责是构建 binder_write_read 结构体,并通过 ioctl 系统调用与 Binder 驱动进行双向数据交换。
c
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
...
binder_write_read bwr;
// 检查输入缓冲区 mIn 是否已经读空
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// 确定写出大小:如果不需要接收新数据(doReceive为false),或者需要接收新数据且输入缓冲区已空,才把 mOut 的数据发出去
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
// 发送缓冲区的数据指针,里面存放着 BC_ 协议指令
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data(); // 指定驱动把数据写到 mIn 的这段内存中
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != 0) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
}
// 如果读写 size 都为 0,直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(__ANDROID__)
// 核心阻塞点:执行 BINDER_WRITE_READ。线程在此陷入内核空间。
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);// 被信号中断则重试
// 对于 ServiceManager 来说,如果没有客户端发起请求,ioctl 就会在驱动层将当前线程挂起阻塞。
// 当 ioctl 返回时,说明驱动已经处理了 mOut 中的数据,或者向 mIn 中写入了新的数据。
...
if (err >= NO_ERROR) {
// 如果驱动读取了用户空间的数据
if (bwr.write_consumed > 0) {
// 写缓存未完全消费,抛出异常
if (bwr.write_consumed < mOut.dataSize())
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
// 如果驱动向用户空间写入了数据
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);// 更新 mIn 的有效数据大小
mIn.setDataPosition(0);// 重置读指针到头部,准备解析
}
...
return NO_ERROR;
}
return err;
}
执行到这里,talkWithDriver 结束,mIn 缓冲区中已经装满了来自驱动的 BR_ 命令。
4.3 executeCommand
回到 getAndExecuteCommand 函数中,它会从 mIn 中读取一个 32 位的命令字(cmd),然后传递给 executeCommand(int32_t cmd) 函数进行解析。 对于 ServiceManager(以及所有服务端),最核心的指令是 BR_TRANSACTION:
解析事务数据与零拷贝
c
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
binder_transaction_data_secctx tr_secctx;
binder_transaction_data& tr = tr_secctx.transaction_data;
// 1. 读取事务元数据(包含发送方 PID/UID,调用方法 code,目标对象 target,以及数据内存地址)
if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
result = mIn.read(&tr_secctx, sizeof(tr_secctx));
} else {
result = mIn.read(&tr, sizeof(tr));
tr_secctx.secctx = 0;
}
Parcel buffer;
// 2. 【核心】直接利用驱动映射好的内存地址(tr.data.ptr.buffer),无需二次拷贝,直接关联给 Parcel 对象
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer);
保存并切换调用者身份
为了让业务层(比如 ServiceManager 的 SELinux 检查)知道是哪个进程发起的调用,IPCThreadState 必须将当前线程的调用者身份替换为发送方的身份:
c
// 备份当前的身份信息(压栈保存)
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
// ... 省略部分备份代码 ...
// 替换为来自驱动解析出的发送方 PID 和 UID (无法伪造)
mCallingPid = tr.sender_pid;
mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
路由并执行业务逻辑
这是 ServiceManager 接收消息的最关键分支:
c
Parcel reply;
status_t error;
if (tr.target.ptr) {
// 普通 Binder 服务处理分支
// 如果 target.ptr 有值,说明目标是一个具体的 Binder 实体节点 (BBinder)
if (reinterpret_cast<RefBase::weakref_type*>(tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
// ServiceManager 处理分支
// 驱动发往 Handle 0 的请求,tr.target.ptr 恒为空(0)
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
针对 ServiceManager: 因为它向驱动注册为 Context Manager(句柄为0),驱动在向其分发事务时,tr.target.ptr 为空。 因此,代码必定走入 else 分支。 the_context_object 是一个全局静态 sp<BBinder> 变量,它在 ServiceManager 进程启动时,通过 IPCThreadState::setTheContextObject() 函数被赋值为 ServiceManager 的本地实例。 于是,消息通过 the_context_object->transact(...) 完美跳转到了业务层的 ServiceManager::onTransact 方法中进行 addService 或 checkService 等逻辑。
发送回复并还原身份
业务处理完毕后,将结果发回给客户端,并还原线程身份:
c
if ((tr.flags & TF_ONE_WAY) == 0) {
// 如果不是 ONEWAY(异步)调用,则需要将 reply 中的数据返回给客户端
if (error < NO_ERROR) reply.setError(error);
constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
// 将答复数据写入 mOut,并最终通过 talkWithDriver 传给驱动
sendReply(reply, (tr.flags & kForwardReplyFlags));
} else {
// ONEWAY 调用,无需发送 reply
}
// 出栈:恢复原始的线程身份上下文
mCallingPid = origPid;
mCallingSid = origSid;
mCallingUid = origUid;
// ...
}
break;
小结
talkWithDriver 是物理通讯层:严格通过 binder_write_read 结构,将 mOut 刷入驱动,将驱动指令拉入 mIn,通过 ioctl(BINDER_WRITE_READ) 实现线程的阻塞与唤醒。 executeCommand 是协议解析层:从 mIn 读取指令,对于核心的 BR_TRANSACTION,它进行零拷贝 Parcel 组装,备份并切换 PID/UID。由于是 ServiceManager,它通过 tr.target.ptr == NULL 的判定,将事务精准路由到了静态绑定的 the_context_object,最后通过 sendReply 完成闭环。
4.4 添加服务/查询服务
由上面分析可知:
c
// 驱动发往 Handle 0 的请求,tr.target.ptr 恒为空(0)
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
由于 the_context_object 本质是一个指向 ServiceManager 实例的指针,它继承自 BBinder。因此,这里的 transact 调用会直接跳转到 BBinder 的成员函数中。 最终会经过:Binder.cpp->BnServiceManager::onTransact分发到 ServiceManager.cpp
c
// 1. 添加服务的终极执行点!
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder,
bool allowIsolated, int32_t dumpPriority) {
// 执行 SELinux 权限校验
if (!mAccess->canAdd(ctx, name)) return Status::fromExceptionCode(Status::EX_SECURITY);
// 【真正写入内存】把服务名和服务的引用装入 Service 结构,写进本地的 std::map 存储中!
mNameToService[name] = Service {
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
};
return Status::ok();
}
// 2. 查询服务的终极执行点!
Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
*outBinder = nullptr;
// 执行 SELinux 权限校验
if (!mAccess->canFind(ctx, name)) return Status::ok();
// 【真正读取内存】在 std::map 中通过 name 键值查找对应的服务
auto it = mNameToService.find(name);
if (it != mNameToService.end()) {
// 找到后,把底层服务的 Binder 引用赋值给传出参数 outBinder
*outBinder = it->second.binder;
}
return Status::ok();
}
在 Android 12 中,addService 中的 service 它在 C++ 代码层表现为 sp<IBinder>,在物理内存中表现为 BpBinder,在最底层的 Binder 协议层表现为一个 整型句柄值(Handle)。 在安卓 10 及之前版本 serviceManager 是用 service_manager.c C 语言写的,当时其他进程传进来的只是handle 裸数据:
c
// 旧版 C 语言 service_manager.c
struct svcinfo {
struct svcinfo *next;
uint32_t handle; // 【注意:这里直接存的就是一个 uint32_t 的数字!】
struct binder_death death;
size_t len;
uint16_t name[0];
};
五、疑惑点解析
5.1 线程单例 IPCThreadState
IPCThreadState是基于线程的一个单例,即每个线程都有一个独立的IPCThreadState,用户和 binder 驱动进行通信。 Thread-Local 绑定:不管是 system_server 的 Binder 线程、App 的主线程,还是 servicemanager 的主线程,只要它需要与 Binder 驱动交互,其线程内部就会通过 TLS 拥有一个独一无二的 IPCThreadState 实例。 对于内核驱动而言,它不在乎你是客户端还是服务端,它只在乎"当前这个线程是否要写数据(mOut)"以及"是否要读数据(mIn)"。
5.2 IPCThreadState::transact 和 BBinder::transact
IPCThreadState::transact(...)(客户端发送出口): 作用是把数据打包成 BC_TRANSACTION 写入 mOut 并通过 talkWithDriver 发给内核驱动。 BBinder::transact(...)(服务端本地入口): 因为 the_context_object 是一个 BBinder(在 servicemanager 进程中,它指向 ServiceManager 实例)。 所以,这里的 transact 是一次本地 C++ 对象的方法调用,绝对不涉及驱动。
5.3 BC_xxx 指令和 BR_xxx 指令有什么区别?

六、最后
通常我们认为 ioctl 会阻塞,那是因为在标准 Binder 线程池模式中,线程必须等到驱动有数据才能返回。 而在 ServiceManager 的 Looper 模式中:
- 驱动先通知:通过
epoll告知 FD 有数据。 - 我们再去拿:
talkWithDriver此时调用ioctl,本质上是去执行"把数据从驱动拷贝到用户空间"的操作。由于数据已经就绪,这个动作会瞬间完成。