Skip to content

IPCThreadState线程绑定

追踪 IPCThreadState 的 pthread TLS 创建、线程实例绑定、退出清理和 ProcessState 依赖边界。

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

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

cpp
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创建 ​

cpp
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 只查询 ​

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

cpp
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 所有权层次 ​

层次对象作用数量
进程ProcessStatedriver fd、mmap、handle 表每进程一份
线程IPCThreadStateTLS、调用身份、Parcel、事务栈每 IPC 线程一份
内核线程状态binder_threaddriver 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()

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

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

bash
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 是之后独立发生的动作。