调用流程
1. sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
2. BinderInternal.getContextObject())
3. static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
4. ProcessState::self()
5. sp<ProcessState> ProcessState::self()
{
return init(kDefaultDriver, false /*requireDefault*/);
}
init
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
sp<ProcessState> ProcessState::init(const char* driver, bool requireDefault) {
if (driver == nullptr) { //1
std::lock_guard<std::mutex> l(gProcessMutex);
if (gProcess) {
verifyNotForked(gProcess->mForked);
}
return gProcess;
}
[[clang::no_destroy]] static std::once_flag gProcessOnce;
std::call_once(gProcessOnce, [&](){ //2
if (access(driver, R_OK) == -1) {
ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
driver = "/dev/binder";
}
if (0 == strcmp(driver, "/dev/vndbinder") && !isVndservicemanagerEnabled()) {
ALOGE("vndservicemanager is not started on this device, you can save resources/threads "
"by not initializing ProcessState with /dev/vndbinder.");
}
// we must install these before instantiating the gProcess object,
// otherwise this would race with creating it, and there could be the
// possibility of an invalid gProcess object forked by another thread
// before these are installed
// 3
int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
ProcessState::childPostFork);
LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
std::lock_guard<std::mutex> l(gProcessMutex);
gProcess = sp<ProcessState>::make(driver); //4
});
if (requireDefault) { //5
// Detect if we are trying to initialize with a different driver, and
// consider that an error. ProcessState will only be initialized once above.
LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,
"ProcessState was already initialized with %s,"
" can't initialize with %s.",
gProcess->getDriverName().c_str(), driver);
}
verifyNotForked(gProcess->mForked); //6
return gProcess;
}
一、单例模式与线程安全
1. 单例控制
当 driver == nullptr 时直接返回现有实例 gProcess,确保全局唯一性。若需要初始化新实例,通过 std::call_once 保证多线程环境下仅执行一次初始化。
2. 锁机制
使用 std::mutex 锁保护 gProcess 的访问,避免多线程竞争条件。例如,std::lock_guardstd::mutex l(gProcessMutex) 在关键代码段加锁。
二、驱动路径处理
1. 驱动可用性检查
通过 access(driver, R_OK) 验证指定驱动路径的可读性。若失败(如 /dev/vndbinder 不可用),自动回退到默认路径 /dev/binder,并记录错误日志。
2. vndbinder 的特殊处理
当尝试初始化 /dev/vndbinder 时,会额外检查 vndservicemanager 是否已启动。若未启动,输出警告日志提示资源浪费风险。
三、进程 Fork 处理
通过 pthread_atfork 注册以下回调函数,确保进程 fork 时 Binder 状态正确:
- onFork:fork 前执行,用于锁定资源。
- parentPostFork:父进程 fork 后恢复状态。
- childPostFork:子进程 fork 后重置 Binder 驱动连接(如关闭文件描述符)。
四、参数验证与错误处理
1. 驱动一致性校验
若 requireDefault 为 true,强制要求当前实例的驱动名称必须与传入的 driver 一致,否则触发致命错误(LOG_ALWAYS_FATAL_IF),防止重复初始化不同驱动。
2. Fork 状态检查
调用 verifyNotForked(gProcess->mForked) 确保当前进程未处于 fork 后的子进程中,避免跨进程状态污染。
五、关键对象创建
- 实例化 ProcessState
通过 sp::make(driver) 创建智能指针管理的 ProcessState 对象,其构造函数会执行以下操作:- 调用 open_driver() 打开 Binder 驱动设备(如 /dev/binder)。
- 使用 mmap 在内核空间映射内存区域(默认大小 1MB-8KB),用于 Binder 事务传输。
- 通过 ioctl 设置 Binder 版本和最大线程数。
总结
此函数是 Binder 通信的基石,负责:
1. 单例生命周期管理:确保进程内唯一的 ProcessState 实例。
2. 驱动兼容性适配:动态处理不同驱动路径(标准/VND Binder)。
3. 多进程安全:通过 fork 处理回调避免状态泄漏。
4. 资源初始化:完成驱动连接、内存映射等底层操作。
通过上述机制,ProcessState::init() 为 Android 跨进程通信提供了稳定的进程状态管理框架。
构造函数
// 构造函数参数为 Binder 驱动设备路径(如 "/dev/binder")
ProcessState::ProcessState(const char* driver)
: mDriverName(String8(driver)), // [1] 存储驱动设备名称
mDriverFD(-1), // [2] 初始化驱动文件描述符为无效值
mVMStart(MAP_FAILED), // [3] 内存映射起始地址初始化失败
mThreadCountLock(PTHREAD_MUTEX_INITIALIZER), // [4] 线程计数互斥锁初始化
mThreadCountDecrement(PTHREAD_COND_INITIALIZER), // [5] 条件变量初始化
mMaxThreads(DEFAULT_MAX_BINDER_THREADS), // [6] 设置 Binder 线程池最大线程数(默认15)
... // 其他成员变量初始化略
{
String8 error;
unique_fd opened = open_driver(driver, &error); // [7] 核心步骤:打开 Binder 驱动
if (opened.ok()) { // [8] 驱动打开成功
// [9] 内存映射:分配内核缓冲区(零拷贝核心实现)
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ,
MAP_PRIVATE | MAP_NORESERVE, opened.get(), 0);
if (mVMStart == MAP_FAILED) { // [10] 映射失败处理
ALOGE("Using %s failed: unable to mmap transaction memory.", driver);
opened.reset(); // 关闭驱动文件
mDriverName.clear(); // 清空设备名
}
}
#ifdef __ANDROID__ // [11] Android 环境下的致命错误检查
LOG_ALWAYS_FATAL_IF(!opened.ok(),
"Binder driver '%s' could not be opened. Error: %s. Terminating.",
error.c_str(), driver);
#endif
if (opened.ok()) { // [12] 最终初始化成功
mDriverFD = opened.release(); // [13] 转移文件描述符所有权
}
}
一、关键逻辑解析
- 驱动设备打开([7])
open_driver() 通过系统调用打开 /dev/binder 设备,返回文件描述符。此步骤对应 Binder 驱动的 binder_init() 初始化流程,驱动会创建 binder_proc 结构体记录进程信息。
驱动检查:若设备不可用(如权限不足),Android 环境会触发致命错误终止进程,确保 Binder 机制可靠性。 - 内存映射([9])
作用:通过 mmap 在内核空间分配 BINDER_VM_SIZE(通常为 1MB)的共享内存,实现用户态与内核态的零拷贝通信。
参数解析:
PROT_READ:用户空间仅需读权限,写操作由内核完成。
MAP_PRIVATE:映射私有副本,避免多进程冲突。
Binder 驱动:通过此映射区域直接传递事务数据,省去传统 IPC 的数据拷贝开销。 - 错误处理([10][11])
映射失败:若 mmap 失败(如内存不足),会关闭驱动并清空设备名,确保后续操作不会使用无效资源。
Android 强约束:在 Android 环境下,驱动打开失败直接终止进程(LOG_ALWAYS_FATAL_IF),因为 Binder 是系统核心组件。 - 成员变量初始化
mDriverFD:保存驱动文件描述符,用于后续 ioctl 调用(如 BINDER_WRITE_READ 命令)。
mMaxThreads:控制 Binder 线程池大小,驱动根据此值管理线程创建与回收。
线程同步机制:通过互斥锁(mThreadCountLock)和条件变量(mThreadCountDecrement)管理线程池并发。
二、与 Binder 驱动的交互流程
- 驱动初始化:内核启动时执行 binder_init(),注册 /dev/binder 设备并初始化调试节点(如 /sys/kernel/debug/binder)。
- 进程绑定:用户态调用 open() 时,驱动创建 binder_proc 结构体,加入全局链表 binder_procs。
- 内存管理:mmap 映射的内存区域由驱动管理,用于事务数据传输(如 binder_transaction_data 结构)。
三、总结
ProcessState 构造函数是 Android Binder 通信的起点,其通过打开驱动、内存映射等操作建立用户态与内核态的桥梁。理解其实现有助于深入掌握 Binder 的零拷贝机制与多线程模型。后续可通过分析 IPCThreadState 了解事务处理流程,或结合 ServiceManager 启动过程 研究服务的注册与发现机制。
open_driver
static unique_fd open_driver(const char* driver, String8* error) {
// 步骤1:尝试以读写模式打开Binder驱动设备(如/dev/binder)
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 {};
}
// 步骤2:检查驱动协议版本是否匹配
int vers = 0;
int result = ioctl(fd.get(), BINDER_VERSION, &vers);
if (result == -1) { // ioctl失败处理
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 {};
}
// 步骤3:设置Binder线程池最大线程数(默认15)
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));
}
// 步骤4:启用单向调用滥用检测(Android高版本特性)
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));
}
return fd; // 返回已配置的驱动文件描述符
}
一、关键逻辑解析
- 驱动设备打开(open())
- 作用:通过系统调用 open() 打开 Binder 设备文件(如 /dev/binder),返回文件描述符。
- 驱动交互:触发内核中 binder_open() 函数,为进程创建 binder_proc 结构体,记录进程上下文信息。
- 错误处理:若设备不存在或权限不足,记录错误并返回空文件描述符。
- 协议版本验证(BINDER_VERSION)
- 必要性:确保用户空间与内核驱动的协议兼容性,避免因版本差异导致通信异常。
- 实现机制:通过 ioctl 发送 BINDER_VERSION 命令,内核返回当前协议版本号。若版本不匹配,进程无法继续使用 Binder。
- 线程池配置(BINDER_SET_MAX_THREADS)
- 默认值:DEFAULT_MAX_BINDER_THREADS 通常为 15,限制进程可创建的 Binder 线程数量。
- 内核交互:驱动将用户空间传入的 maxThreads 值写入 binder_proc->max_threads,用于后续线程调度。
- 容错处理:即使设置失败(如驱动不支持),进程仍可继续运行,但可能导致线程池容量不足。
- 单向调用防护(BINDER_ENABLE_ONEWAY_SPAM_DETECTION)
- 功能背景:防止恶意进程通过单向调用(oneway)耗尽服务端资源,Android 12+ 引入的防护机制。
- 实现逻辑:驱动监控单向调用的频率,超过阈值时触发限制策略(如丢弃请求或记录日志)。
二、与 Binder 驱动的交互流程
- 设备初始化:用户空间调用 open() 后,内核通过 binder_open() 创建 binder_proc 结构体,并加入全局链表 binder_procs。
- 版本协商:BINDER_VERSION 命令通过 binder_ioctl() 处理,直接返回内核协议版本。
- 线程池管理:BINDER_SET_MAX_THREADS 命令将用户空间参数拷贝至内核的 binder_proc->max_threads。
- 安全增强:BINDER_ENABLE_ONEWAY_SPAM_DETECTION 启用后,驱动在事务处理中增加频率检测逻辑。
三、错误处理策略
- 驱动打开失败:直接终止进程(Android 环境下)或记录错误(非 Android 环境)。
- 版本不匹配:视为致命错误,终止进程以避免通信异常。
- 线程配置失败:仅记录日志,不影响后续操作(但可能导致性能问题)。
四、总结
open_driver 是 Binder 通信初始化的核心函数,通过四个关键步骤确保驱动可用性、协议兼容性及资源可控性。其实现紧密结合 Binder 驱动机制,体现了 Android IPC 的高效性与安全性设计。后续可通过分析 mmap 和 IPCThreadState 进一步理解事务传输与线程调度机制。