Skip to content

Binder线程状态模型

追踪 Binder 线程池启动、TLS、looper 注册、waiting_threads、work 选择、动态扩容、嵌套事务与退出状态。

基于android-17.0.0_r1
AndroidBinder线程池并发源码阅读

Binder线程状态模型 ​

Binder 线程池不是“固定 N 个线程等待请求”。当前源码允许 ProcessState 启动一个主池线程, 驱动按需请求更多线程,调用者直接 joinThreadPool,或使用 setupPolling 把 Binder fd 接入自己的 epoll。驱动还要区分空闲线程、正在处理嵌套事务的线程和只能消费 thread.todo 的线程。

本文面向已经读过 Binder协议状态机 和 Binder的C/S模型 的读者,专门回答线程从哪里创建、如何注册、何时 进入 waiting_threads、事务如何选线程、BR_SPAWN_LOOPER 如何闭环、嵌套同步调用为何可能回到 原线程,以及退出和饥饿如何观测。

本文不把默认 maxThreads 当成设备通用线程总数,也不展开 Java Binder 主线程、system_server 每个 ServiceThread 或完整优先级继承算法。

1. 四种入口 ​

PoolThread ​

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

cpp
class PoolThread : public Thread {
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain) {}

protected:
    bool threadLoop() override {
        IPCThreadState::self()
                ->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

PoolThread 只是线程载体;真正的 Binder 循环在当前线程的 IPCThreadState 中。一个 ProcessState 对应进程级驱动 fd,但每个线程拥有独立 TLS IPCThreadState 和 mIn/mOut。

入口对照 ​

入口注册命令owner典型用途
startThreadPool主 PoolThread 发送 BC_ENTER_LOOPERProcessState标准线程池
BR_SPAWN_LOOPER新 PoolThread 发送 BC_REGISTER_LOOPER驱动请求/ProcessState 创建动态扩容
直接 joinThreadPool参数决定 ENTER/REGISTER调用线程自定义服务主线程
setupPollingBC_ENTER_LOOPER外部 event loopepoll 集成

线程池总量不能简单写成 maxThreads+1,因为直接 join 和 polling 线程也可能存在。

2. TLS状态 ​

self入口 ​

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

cpp
IPCThreadState* IPCThreadState::self() {
    if (gHaveTLS.load(
            std::memory_order_acquire)) {
restart:
        const pthread_key_t key = gTLS;
        IPCThreadState* state =
                static_cast<IPCThreadState*>(
                        pthread_getspecific(key));
        if (state)
            return state;
        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);
            return nullptr;
        }
        gHaveTLS.store(
                true,
                std::memory_order_release);
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

TLS key 是进程共享的,但 value 属于线程。一个线程的 reply wait、calling identity、pending deref 和事务输入不能被另一个线程直接替代。

Thread状态 ​

驱动中的 binder_thread 保存 pid、looper bits、transaction_stack、thread todo、wait queue 和 错误状态。用户态 IPCThreadState 与内核 binder_thread 通过“当前调用线程 + 同一个驱动 fd” 对应,不是通过 Java Thread 对象引用连接。

3. 启动线程池 ​

startThreadPool ​

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

cpp
void ProcessState::startThreadPool() {
    std::unique_lock<std::mutex> lock(mLock);
    if (!mThreadPoolStarted) {
        if (mMaxThreads == 0) {
            ALOGW("Extra binder thread started, "
                  "but 0 threads requested.");
        }
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

启动是幂等的,首次调用创建 isMain=true 的 PoolThread。它不代表调用 startThreadPool 的原线程 加入池;新建的 PoolThread 才调用 joinThreadPool。

动态创建 ​

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

cpp
void ProcessState::spawnPooledThread(
        bool isMain) {
    if (mThreadPoolStarted) {
        String8 name =
                makeBinderThreadName();
        sp<Thread> thread =
                sp<PoolThread>::make(isMain);
        thread->run(name.c_str());
        mKernelStartedThreads++;
    }
}

函数名中的 pooled 并不表示内核直接创建 pthread;驱动只返回 BR_SPAWN_LOOPER,libbinder 再 创建 PoolThread。

最大线程配置 ​

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

cpp
status_t ProcessState::
setThreadPoolMaxThreadCount(
        size_t maxThreads) {
    LOG_ALWAYS_FATAL_IF(
            mThreadPoolStarted &&
            maxThreads < mMaxThreads,
            "Binder threadpool cannot be shrunk "
            "after starting");

    if (ioctl(mDriverFD,
            BINDER_SET_MAX_THREADS,
            &maxThreads) != -1) {
        mMaxThreads = maxThreads;
        return NO_ERROR;
    }
    return -errno;
}

线程池启动后不能缩小用户态配置。驱动 max_threads 约束的是驱动请求启动的线程,不自动统计 所有直接 join 或 polling 线程。

4. 注册状态 ​

join循环 ​

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

cpp
void IPCThreadState::joinThreadPool(
        bool isMain) {
    mProcess->checkExpectingThreadPoolStart();
    mProcess->mCurrentThreads++;

    mOut.writeInt32(
            isMain
            ? BC_ENTER_LOOPER
            : BC_REGISTER_LOOPER);
    mIsLooper = true;

    status_t result;
    do {
        processPendingDerefs();
        result = getAndExecuteCommand();

        if (result == TIMED_OUT &&
                !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED &&
            result != -EBADF);

    mOut.writeInt32(BC_EXIT_LOOPER);
    mIsLooper = false;
    talkWithDriver(false);
    mProcess->mCurrentThreads--;
}

主 PoolThread 发送 ENTER,驱动请求创建的 PoolThread 发送 REGISTER。非主线程只有收到 TIMED_OUT 才可从循环退出;实际是否产生该返回取决于驱动命令和当前实现,不能写成固定空闲 超时。

驱动校验 ​

源码文件:kernel/common/drivers/android/binder.c

c
case BC_REGISTER_LOOPER:
    binder_inner_proc_lock(proc);
    if (thread->looper &
            BINDER_LOOPER_STATE_ENTERED) {
        thread->looper |=
                BINDER_LOOPER_STATE_INVALID;
    } else if (proc->requested_threads == 0) {
        thread->looper |=
                BINDER_LOOPER_STATE_INVALID;
    } else {
        proc->requested_threads--;
        proc->requested_threads_started++;
    }
    thread->looper |=
            BINDER_LOOPER_STATE_REGISTERED;
    binder_inner_proc_unlock(proc);
    break;

case BC_ENTER_LOOPER:
    if (thread->looper &
            BINDER_LOOPER_STATE_REGISTERED) {
        thread->looper |=
                BINDER_LOOPER_STATE_INVALID;
    }
    thread->looper |=
            BINDER_LOOPER_STATE_ENTERED;
    break;

REGISTER 必须对应驱动之前的 requested_threads;ENTER 和 REGISTER 不能在同一线程交叉使用。 协议错误会标记 INVALID,而不是把线程默认为正常 worker。

5. 空闲等待 ​

可消费proc work ​

源码文件:kernel/common/drivers/android/binder.c

c
static bool
binder_available_for_proc_work_ilocked(
        struct binder_thread *thread) {
    return !thread->transaction_stack &&
            binder_worklist_empty_ilocked(
                    &thread->todo);
}

只有没有嵌套 transaction_stack 且 thread.todo 为空的线程,才可去消费 proc.todo。正在等待某个 reply 或拥有定向 work 的线程不是通用空闲线程。

waiting_threads ​

源码文件:kernel/common/drivers/android/binder.c

c
prepare_to_wait(&thread->wait,
        &wait,
        TASK_INTERRUPTIBLE |
        TASK_FREEZABLE);

if (binder_has_work_ilocked(
        thread, do_proc_work))
    break;

if (do_proc_work)
    list_add(
            &thread->waiting_thread_node,
            &proc->waiting_threads);

binder_inner_proc_unlock(proc);
schedule();
binder_inner_proc_lock(proc);
list_del_init(
        &thread->waiting_thread_node);

线程只有在允许 proc work 时才加入 waiting_threads。被选中后会从链表移除,选择者必须负责 唤醒;信号中断则返回 EINTR。

选择线程 ​

源码文件:kernel/common/drivers/android/binder.c

c
static struct binder_thread*
binder_select_thread_ilocked(
        struct binder_proc *proc) {
    struct binder_thread* thread =
            list_first_entry_or_null(
                    &proc->waiting_threads,
                    struct binder_thread,
                    waiting_thread_node);
    if (thread)
        list_del_init(
                &thread->waiting_thread_node);
    return thread;
}

选择规则不是 round-robin 业务调度器,只取 waiting_threads 头部;没有 waiting thread 时, 事务进入 proc.todo,或唤醒使用 poll 接口的线程。

6. 事务投递 ​

同步事务 ​

源码文件:kernel/common/drivers/android/binder.c

相关函数:binder_proc_transaction()

c
if (!thread && !pending_async)
    thread =
            binder_select_thread_ilocked(proc);

if (thread) {
    binder_transaction_priority(
            thread, transaction, node);
    binder_enqueue_thread_work_ilocked(
            thread,
            &transaction->work);
} else if (!pending_async) {
    binder_enqueue_work_ilocked(
            &transaction->work,
            &proc->todo);
}

有空闲线程时事务定向到 thread.todo;否则进入 proc.todo,等待某个可消费 proc work 的线程。 同步事务还可能因 transaction_stack 找到嵌套调用关联线程,这与普通 waiting_threads 选择不同。

Oneway事务 ​

同一 node 已有 async transaction 时,新 oneway 进入 node.async_todo;它不通过增加线程数获得 并行消费。oneway 顺序、同步线程池容量和 node async 队列是三个不同边界。

7. 动态扩容 ​

生成条件 ​

源码文件:kernel/common/drivers/android/binder.c

c
if (proc->requested_threads == 0 &&
        list_empty(
                &proc->waiting_threads) &&
        proc->requested_threads_started <
                proc->max_threads &&
        (thread->looper &
                (BINDER_LOOPER_STATE_REGISTERED |
                 BINDER_LOOPER_STATE_ENTERED))) {
    proc->requested_threads++;
    put_user(BR_SPAWN_LOOPER,
            (uint32_t __user*)buffer);
}

驱动只在没有未完成请求、没有 waiting thread、已启动数量低于 max,并且当前线程是合法 looper 时请求新线程。max_threads 不是当前总线程数,也不含所有用户直接 join 的线程。

用户态响应 ​

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

cpp
case BR_SPAWN_LOOPER:
    mProcess->spawnPooledThread(false);
    break;

新线程启动后发送 BC_REGISTER_LOOPER,驱动再把 requested_threads 减一并增加 requested_threads_started。只有请求和注册都完成,扩容才闭环。

8. 线程计数 ​

总量估算 ​

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

相关函数:getThreadPoolMaxTotalThreadCount()

cpp
size_t kernelStarted =
        mKernelStartedThreads;

if (mThreadPoolStarted) {
    size_t threads = 1;
    threads += mMaxThreads;

    size_t current = mCurrentThreads;
    if (current > kernelStarted)
        threads += current - kernelStarted;

    return threads;
}
return mCurrentThreads;

返回值是上界/估算:1 个 startThreadPool 线程、驱动可启动的 max,以及无法单独统计的直接 join 线程。源码注释明确存在竞态,因此不能把它当作某一时刻精确活跃数。

执行计数 ​

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

cpp
size_t executing =
        mProcess->mExecutingThreadsCount
                .fetch_add(1) + 1;

if (executing >= mProcess->mMaxThreads) {
    auto expected = ProcessState::never();
    mProcess->mStarvationStartTime
            .compare_exchange_strong(
                    expected,
                    std::chrono::steady_clock::now());
}

result = executeCommand(cmd);

executing =
        mProcess->mExecutingThreadsCount
                .fetch_sub(1) - 1;

执行计数围绕 top-level command,而不是线程是否存在。达到 max 后记录 starvation 时间;这只是 诊断信号,不等于驱动必然能再创建线程。

9. Poll模式 ​

setupPolling ​

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

cpp
status_t IPCThreadState::setupPolling(
        int* fd) {
    if (mProcess->mDriverFD < 0)
        return -EBADF;

    mOut.writeInt32(BC_ENTER_LOOPER);
    flushCommands();
    *fd = mProcess->mDriverFD;
    mProcess->mCurrentThreads++;
    return NO_ERROR;
}

外部循环拿 Binder fd 加入 epoll,事件到达后调用 handlePolledCommands。poll 线程不一定出现在 waiting_threads,因此驱动找不到普通 waiting thread 时会扫描并唤醒 poll looper。

Poll消费 ​

cpp
do {
    result = getAndExecuteCommand();
} while (mIn.dataPosition() <
        mIn.dataSize());

processPendingDerefs();
flushCommands();

poll consumer 必须把当前 mIn 命令处理完,并 flush BC_FREE_BUFFER 等后续命令。只读一个命令会 遗留协议状态。

10. 退出失败 ​

Looper退出 ​

BC_EXIT_LOOPER 标记内核 thread looper EXITED;驱动连接返回 ECONNREFUSED 或 EBADF 时,join 循环退出。非预期错误会 fatal,而不是静默继续。

线程死亡 ​

服务线程死亡时,定向 transaction、transaction_stack、thread.todo 和 reply error 都需要驱动 清理;尚未回复的同步调用可能转为 BR_DEAD_REPLY。线程退出不等于整个服务 proc/node 死亡。

饥饿 ​

所有 worker 阻塞在业务锁、同步回调或长事务时,proc.todo 会堆积。BR_SPAWN_LOOPER 受 max 和 requested 状态限制;增加 max 不能解决锁循环、oneway 单 node 串行或嵌套死锁。

11. 测试输入 ​

线程总量 ​

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

相关测试:ThreadPoolAvailableThreads()

cpp
EXPECT_THAT(server->transact(
        BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
        data, &reply), StatusEq(NO_ERROR));

int32_t count = reply.readInt32();
EXPECT_TRUE(count == kKernelThreads + 1 ||
        count == kKernelThreads + 2);

for (size_t i = 0;
        i < kKernelThreads + 1; i++) {
    workers.emplace_back([&] {
        Parcel localReply;
        server->transact(
                BINDER_LIB_TEST_LOCK_UNLOCK,
                data, &localReply);
    });
}

测试允许 +1/+2 的竞态,随后占用大量 worker、延迟解锁并在最终断言总量。它证明计数是带竞态的 池容量模型,不支持“恒定线程数”结论。

启动状态 ​

相关测试:ThreadPoolStarted()

服务端返回 ProcessState.isThreadPoolStarted,客户端断言 true。它只证明 server harness 已调用 startThreadPool,不证明当前所有 worker 都已创建或空闲。

优先级测试 ​

BinderThreadPriorityTest 的优先级传播用例当前带 SkipPresubmit,不能作为稳定运行证据;源码仍可 用来发现“调用优先级”和“回调后恢复”问题,但公开结论必须回到驱动 priority 代码或重新执行测试。

12. 阅读边界 ​

线程状态图 ​

waiting_threads 是驱动 proc work 的消费者候选集合;mExecutingThreadsCount 是 Native 执行计数; requested_threads 是尚未注册的请求。三者不等价,排查线程池问题时必须分别读取。

本文证明了 TLS、线程池启动、ENTER/REGISTER、waiting_threads、proc/thread todo、动态扩容、 计数竞态、poll 模式、退出和饥饿边界。没有展开完整优先级继承、嵌套死锁算法、oneway 限流、 Java Binder 线程命名、system_server 专用线程和调试工具。

下一篇进入驱动层 BD013。复查线程问题时按“线程入口、looper bits、transaction_stack、 thread.todo/proc.todo、waiting_threads、requested/max、退出状态”取证。