IPCThreadState线程绑定
IPCThreadState 是每个参与 libbinder IPC 线程的状态 owner。它保存当前调用身份、输入输出 Parcel、事务栈、工作源和线程是否处于 looper;但对象并不是通过全局 map 按线程 id 查找,而是放在 pthread TLS 中。IPCThreadState::self() 第一次调用时创建 TLS key,再由构造函数把实例写入当前线程;线程退出时,TLS destructor 刷新命令、通知 Binder 驱动并删除对象。
本文面向已经读过 ProcessState初始化、open_driver流程 和 Binder线程管理 的读者。本文只讲线程本地实例如何建立和销毁,以及为什么 TLS 绑定不等于加入 Binder 线程池;事务循环、身份字段和 polling 的工作语义留给后续文章。
1. TLS入口
1.1 全局状态
源码文件:frameworks/native/libs/binder/IPCThreadState.cpp
相关变量:gTLSMutex、gHaveTLS、gTLS
static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static std::atomic<bool> gHaveTLS(false);
static pthread_key_t gTLS = 0;gTLS 是进程级 pthread key,key 本身只有一个;每个线程在这个 key 下保存不同的 IPCThreadState*。gHaveTLS 用于无锁快速判断 key 是否已经创建,mutex 只保护创建竞争。
1.2 self创建
IPCThreadState* IPCThreadState::self() {
if (gHaveTLS.load(std::memory_order_acquire)) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st =
static_cast<IPCThreadState*>(pthread_getspecific(k));
if (st) return st;
return new IPCThreadState;
}
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS.load(std::memory_order_relaxed)) {
int result = pthread_key_create(&gTLS, threadDestructor);
if (result != 0) {
pthread_mutex_unlock(&gTLSMutex);
ALOGW("IPCThreadState::self() unable to create TLS key");
return nullptr;
}
gHaveTLS.store(true, std::memory_order_release);
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}第一次并发调用只有一个线程创建 key;其他线程在 gHaveTLS 发布后重新读取 key。key 创建失败返回空指针,调用者若继续解引用会进入未定义边界;源码只记录 warning,并没有在这里抛出 C++ 异常。
1.3 只查询
IPCThreadState* IPCThreadState::selfOrNull() {
if (gHaveTLS.load(std::memory_order_acquire)) {
const pthread_key_t k = gTLS;
return static_cast<IPCThreadState*>(
pthread_getspecific(k));
}
return nullptr;
}selfOrNull() 不创建 key,也不创建当前线程实例。它适合诊断或清理代码判断“本线程是否已经进入 libbinder”,不能用来保证后续 Binder 调用一定有状态对象。
2. 实例构造
2.1 ProcessState依赖
源码文件:frameworks/native/libs/binder/IPCThreadState.cpp
相关函数:IPCThreadState::IPCThreadState()
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mServingStackPointer(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mIsLooper(false),
mIsFlushing(false),
mIsProcessingPostWriteDerefs(false),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0),
mCallRestriction(mProcess->mCallRestriction) {
pthread_setspecific(gTLS, this);
clearCaller();
mHasExplicitIdentity = false;
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}构造函数先取得进程级 ProcessState,再把自身写入当前线程 TLS。默认身份、Parcel 初始容量和 looper 标志都属于线程实例;它们不会写入 ProcessState 全局对象。
2.2 所有权层次
| 层次 | 对象 | 作用 | 数量 |
|---|---|---|---|
| 进程 | ProcessState | driver fd、mmap、handle 表 | 每进程一份 |
| 线程 | IPCThreadState | TLS、调用身份、Parcel、事务栈 | 每 IPC 线程一份 |
| 内核线程状态 | binder_thread | driver work 和 looper 状态 | 每进入驱动的线程 |
创建 IPCThreadState 会依赖 ProcessState::self(),但不会调用 joinThreadPool()、setupPolling() 或发送 BC_ENTER_LOOPER。
3. 线程退出
3.1 destructor注册
pthread_key_create(&gTLS, threadDestructor) 把 threadDestructor 绑定到 key。pthread 在线程退出时取出该线程的 TLS 值并调用 destructor;它不是进程退出时统一扫描所有 IPCThreadState。
3.2 清理顺序
源码文件:frameworks/native/libs/binder/IPCThreadState.cpp
相关函数:threadDestructor()
void IPCThreadState::threadDestructor(void* st) {
IPCThreadState* const self =
static_cast<IPCThreadState*>(st);
if (self) {
self->flushCommands();
#if defined(BINDER_WITH_KERNEL_IPC)
if (self->mProcess->mDriverFD >= 0) {
ioctl(self->mProcess->mDriverFD,
BINDER_THREAD_EXIT, 0);
}
#endif
delete self;
}
}清理顺序是 flush pending commands、通知 Binder 驱动线程退出、删除 C++ 对象。BINDER_THREAD_EXIT 只在 kernel IPC 构建中编译;flush 或 ioctl 的具体错误处理不在 destructor 中展开为异常。
3.3 不主动shutdown
源码保留的 IPCThreadState::shutdown() 注释说明,旧实现曾尝试删除当前 TLS 和 key,但线程池线程可能与进程销毁竞争,因此现在 key 永久保留。不要把 selfOrNull() 看到空值理解成全局 TLS 已被删除;通常只是当前线程尚未创建实例。
4. Looper边界
4.1 加入线程池
源码文件:frameworks/native/libs/binder/IPCThreadState.cpp
相关函数:joinThreadPool()
void IPCThreadState::joinThreadPool(bool isMain) {
mProcess->checkExpectingThreadPoolStart();
mProcess->mCurrentThreads++;
mOut.writeInt32(isMain ? BC_ENTER_LOOPER
: BC_REGISTER_LOOPER);
mIsLooper = true;
...
}joinThreadPool() 才把当前线程标记为 looper、增加线程计数并向驱动发送 looper 命令。IPCThreadState::self() 只创建状态对象,二者发生时机和消费者不同。
4.2 Polling路径
同样,setupPolling() 会检查 mProcess->mDriverFD、写入 BC_ENTER_LOOPER 并把 fd 返回给外部 Looper。因此 ServiceManager 使用的“TLS 实例 + Looper polling”与传统线程池是两种消费路径。
5. 失败边界
5.1 TLS创建失败
pthread_key_create() 失败时 self() 返回 nullptr;这不是“当前线程没有实例但稍后自动重试”的状态,因为本次调用在创建 key 前就返回。上层必须把空指针作为初始化失败处理。
5.2 ProcessState失败
构造 IPCThreadState 会调用 ProcessState::self()。如果 driver 打开或 mmap 失败,Android 构建可能在 ProcessState 构造阶段 fatal;host 构建可能留下无效对象。本文不把 TLS 成功外推为 driver 已可用。
5.3 线程退出竞态
线程退出时 destructor 可能刷新命令并访问 ProcessState fd;fork 后 ProcessState::childPostFork() 会关闭 fd,因而 fork 后继续使用 IPCThreadState 本身已越过 libbinder 的使用边界。
6. 源码验证
6.1 现有测试
源码文件:frameworks/native/libs/binder/tests/binderIPCThreadStateUnitTest.cpp
固定源码范围的该单元测试主要覆盖 IPCThreadState 与 PCC audit、FakeServiceManager 的交互,并在测试中显式取得 ProcessState::self();它没有把 TLS key 创建、线程退出 destructor 或多线程 key 竞争作为独立测试目标。因此本文对 TLS 创建和退出顺序依据源码控制流,不声称已有测试覆盖全部生命周期。
6.2 可执行阅读
rg -n "gTLSMutex|gHaveTLS|pthread_key_create|IPCThreadState::self|selfOrNull" \
frameworks/native/libs/binder/IPCThreadState.cpp
rg -n "IPCThreadState::IPCThreadState|pthread_setspecific|threadDestructor|BINDER_THREAD_EXIT" \
frameworks/native/libs/binder/IPCThreadState.cpp
rg -n "joinThreadPool|setupPolling|BC_ENTER_LOOPER|BC_REGISTER_LOOPER" \
frameworks/native/libs/binder/IPCThreadState.cpp读者应能复述这条边界:TLS key 是进程级一次创建,实例是线程级按需创建,实例依赖进程级 ProcessState,线程退出由 pthread destructor 清理,而加入线程池或 polling 是之后独立发生的动作。
