open_driver流程
open_driver() 是 ProcessState 构造期间的驱动准备函数,但它并不负责完整初始化。它只拥有一条局部资源链:打开设备得到 unique_fd,用 BINDER_VERSION 确认用户态和驱动协议一致,设置内核线程上限,尝试启用 oneway spam detection,然后把 fd 交给调用方。mmap、Android/host 对失败的最终处理和成员字段写入属于 ProcessState 构造函数。
本文面向已经读过 ProcessState初始化、Binder-ioctl入口 和 Binder设备打开 的读者。本文回答每个 ioctl 何时执行、哪一种失败会阻止 fd 返回、unique_fd 如何防止中途泄漏,以及测试对 UAPI 错误输入覆盖到什么范围。不展开 mmap 页分配和线程池消费。
1. 资源入口
1.1 调用位置
源码文件:frameworks/native/libs/binder/ProcessState.cpp
相关函数:ProcessState::ProcessState()、open_driver()
String8 error;
unique_fd opened = open_driver(driver, &error);
if (opened.ok()) {
mVMStart = mmap(nullptr, BINDER_VM_SIZE,
PROT_READ,
MAP_PRIVATE | MAP_NORESERVE,
opened.get(), 0);
if (mVMStart == MAP_FAILED) {
ALOGE("Using %s failed: unable to mmap transaction memory.",
driver);
opened.reset();
mDriverName.clear();
}
}open_driver() 返回的是临时 fd。构造函数只有在 mmap 也成功后,才调用 opened.release() 把 fd 转交给 mDriverFD;任何早期失败都由 unique_fd 自动关闭。
1.2 资源所有权
| 阶段 | owner | 资源 | 失败后的消费者 |
|---|---|---|---|
open() 后 | unique_fd opened | 临时 fd | 析构自动 close |
| 协议 ioctl 后 | unique_fd opened | 已验证 fd | 继续配置 |
| mmap 成功后 | ProcessState | fd + VM 映射 | mDriverFD/mVMStart |
| mmap 失败后 | 无 | fd 被 reset | 构造函数错误策略 |
2. 打开设备
2.1 open参数
static unique_fd open_driver(const char* driver,
String8* error) {
auto fd = unique_fd(open(
driver, O_RDWR | O_CLOEXEC));
if (!fd.ok()) {
error->appendFormat(
"%d (%s) Opening '%s' failed",
errno, strerror(errno), driver);
return {};
}
...
}O_RDWR 允许后续 ioctl 和 Binder 读写使用同一个描述符;O_CLOEXEC 防止 exec 后把 Binder fd 泄漏到新程序。打开失败把 errno 文本追加到调用方提供的 String8,返回空 unique_fd,不在此处决定 fatal 还是仅记录日志。
2.2 driver选择
源码文件:frameworks/native/libs/binder/ProcessState.cpp
相关常量:kDefaultDriver
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endifopen_driver() 本身不选择默认设备;它只接受调用者传入的路径。默认路径由 ProcessState::self() 和构建宏决定,显式 initWithDriver() 可以改变输入,但受单例一致性检查约束。
3. 协议校验
3.1 版本读取
源码文件:frameworks/native/libs/binder/ProcessState.cpp
相关函数:open_driver()
int vers = 0;
int result = ioctl(fd.get(), BINDER_VERSION, &vers);
if (result == -1) {
error->appendFormat(
"%d (%s) Binder ioctl to obtain version failed",
errno, strerror(errno));
return {};
}
if (result != 0 ||
vers != BINDER_CURRENT_PROTOCOL_VERSION) {
error->appendFormat(
"Binder driver protocol(%d) does not match "
"user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
return {};
}BINDER_VERSION 同时是 UAPI 定义的读写 ioctl:驱动写回 protocol_version,用户态与 BINDER_CURRENT_PROTOCOL_VERSION 比较。ioctl 返回错误和版本值不匹配都阻止 fd 继续进入线程配置;这一步失败不是可选能力缺失,而是用户态无法证明协议兼容。
3.2 UAPI定义
源码文件:kernel/common/include/uapi/linux/android/binder.h
相关定义:BINDER_VERSION
struct binder_version {
__s32 protocol_version;
};
enum {
BINDER_VERSION = _IOWR('b', 9,
struct binder_version),
BINDER_SET_MAX_THREADS = _IOW('b', 5, __u32),
BINDER_ENABLE_ONEWAY_SPAM_DETECTION =
_IOW('b', 16, __u32),
};UAPI 命令号和结构体大小必须与用户态头文件一致;版本字段是协议不兼容变化的门槛,不是 Android API level。
4. 线程配置
4.1 内核上限
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd.get(), BINDER_SET_MAX_THREADS,
&maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s",
strerror(errno));
}Android 17 默认值为 DEFAULT_MAX_BINDER_THREADS,当前源码定义为 15。这里把“内核可以按需启动的线程上限”写入 driver;它不创建线程,也不等于用户态 startThreadPool() 已经调用。ioctl 失败只记录错误,open_driver() 仍返回有效 fd,后续程序可能继续以不完整的线程配置运行。
4.2 两层上限
ProcessState::mMaxThreads 是 libbinder 保存的线程配置,BINDER_SET_MAX_THREADS 是驱动侧上限;二者在初始化时使用同一个默认值,但后续调用 setThreadPoolMaxThreadCount() 还会重新通知驱动。理解这两个 owner,才能解释为什么“open_driver 设置 15”不等于“进程当前已有 15 个 Binder 线程”。
5. 可选特性
5.1 spam检测
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd.get(),
BINDER_ENABLE_ONEWAY_SPAM_DETECTION,
&enable);
if (result == -1) {
ALOGE_IF(ProcessState::isDriverFeatureEnabled(
ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
"Binder ioctl to enable oneway spam detection failed: %s",
strerror(errno));
}默认启用值为 1。ioctl 失败时,只有 binderfs feature 文件表明驱动支持该特性,才输出错误日志;不支持的旧驱动不会被当作协议不兼容。这个分支不关闭 fd,也不让 open_driver() 返回空。
5.2 特性文件
源码文件:frameworks/native/libs/binder/ProcessState.cpp
相关函数:ProcessState::isDriverFeatureEnabled()
#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
static bool enabled = readDriverFeatureFile(
DRIVER_FEATURES_PATH "oneway_spam_detection");feature 查询结果由静态变量缓存。它描述驱动暴露的能力,不是本次 ioctl 是否已经成功;因此“feature 文件存在”与“enable ioctl 返回成功”仍是两个观察点。
6. 错误收束
6.1 unique_fd语义
open_driver() 中任何 return {} 都会销毁局部 unique_fd。版本 ioctl 失败、版本不匹配或后续调用方 mmap 失败,都不会留下裸 fd;只有构造函数确认所有权转移后,mDriverFD 才接管描述符。
6.2 Android与host
#if defined(EXPECT_BINDER_OPEN_SUCCESS)
LOG_ALWAYS_FATAL_IF(!opened.ok(),
"Binder driver '%s' could not be opened. Error: %s.",
driver, error.c_str());
#else
if (!opened.ok()) {
ALOGE("Binder driver '%s' could not be opened. Error: %s.",
driver, error.c_str());
}
#endifEXPECT_BINDER_OPEN_SUCCESS 在 Android/Fuchsia 构建中定义,打开链失败会 fatal;host 构建只记录错误并保留 ProcessState 对象。这个构建条件改变的是上层错误策略,不改变 open_driver() 对协议和 fd 的返回语义。
6.3 mmap边界
即使 open_driver() 返回有效 fd,后续 mmap() 仍可能失败;这不是 open_driver() 的成功承诺。构造函数会 reset fd、清空 driver 名,并按构建条件决定是否终止。把“设备打开成功”写成“Binder 已可用”会跳过这个边界。
7. 测试验证
7.1 版本与线程
源码文件:frameworks/native/libs/binder/tests/binderDriverInterfaceTest.cpp
binderTestIoctl(BINDER_VERSION, &version) 验证版本 ioctl 的正常接口;binderTestIoctl(BINDER_SET_MAX_THREADS, &max_threads) 覆盖线程上限设置;错误测试以空指针输入断言 EFAULT 或 EINVAL,说明 UAPI 对用户指针错误有明确返回边界。
7.2 证明范围
这些测试直接操作 Binder driver 接口,但不调用私有 open_driver(),也不覆盖 unique_fd、mmap、EXPECT_BINDER_OPEN_SUCCESS 或 feature 文件缓存。因此它们反向验证 ioctl 契约,不能单独证明整个 ProcessState 构造成功。
7.3 可执行阅读
rg -n "static unique_fd open_driver|BINDER_VERSION|BINDER_SET_MAX_THREADS|BINDER_ENABLE_ONEWAY" \
frameworks/native/libs/binder/ProcessState.cpp
rg -n "binderTestIoctl|BINDER_VERSION|BINDER_SET_MAX_THREADS" \
frameworks/native/libs/binder/tests/binderDriverInterfaceTest.cpp
rg -n "EXPECT_BINDER_OPEN_SUCCESS|mmap|opened.reset|opened.release" \
frameworks/native/libs/binder/ProcessState.cpp遇到 Binder 初始化失败时,先区分 open、协议版本、线程 ioctl、可选特性和 mmap 五个阶段;只有前两类会让 open_driver() 返回空,线程和 spam ioctl 失败可能只留下日志,而 mmap 失败发生在调用方接管 fd 之前。
