Skip to content

open_driver流程

深入追踪 libbinder open_driver 的 fd 获取、协议版本协商、线程上限、可选特性和错误收束。

基于android-17.0.0_r1
AndroidBinderopen_driverNative框架源码阅读

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()

cpp
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 成功后ProcessStatefd + VM 映射mDriverFD/mVMStart
mmap 失败后无fd 被 reset构造函数错误策略

2. 打开设备 ​

2.1 open参数 ​

cpp
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

cpp
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif

open_driver() 本身不选择默认设备;它只接受调用者传入的路径。默认路径由 ProcessState::self() 和构建宏决定,显式 initWithDriver() 可以改变输入,但受单例一致性检查约束。

3. 协议校验 ​

3.1 版本读取 ​

源码文件:frameworks/native/libs/binder/ProcessState.cpp

相关函数:open_driver()

cpp
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

c
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 内核上限 ​

cpp
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检测 ​

cpp
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()

cpp
#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 ​

cpp
#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());
}
#endif

EXPECT_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 可执行阅读 ​

bash
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 之前。