Binder线程池

Binder线程池

目录

https://blog.csdn.net/qq_40587575/article/details/130394731

在这种情况下,如果Server只有一个线程处理响应,就会导致客户端的请求可能需要排队而导致响应过慢的现象发生。解决这个问题的方法就是引入多线程。【多个客户端不同线程去请求,服务端需要使用多线程机制,binder线程池,创建多个线程去回复多个客户端的请求】

binder线程有主线程和非主线程之分,主线程是启动的时候才会有的,每个binder线程池只有一个。其他情况下申请的都是非主线程,binder线程(非主线程)有两种情况启动:client进程向binderDriver发送IPC请求,以及 client进程向binderDriver回复IPC请求结果,binder线程池的默认大小是16,1个主线程和15个非主线程。

设置进程Binder线程数量

创建 ProcessState 进程单实例时,设置默认的最大线程数量为 DEFAULT_MAX_BINDER_THREADS

ProcessState::ProcessState(const char* driver)
      : mDriverName(String8(driver)),
        mDriverFD(-1),
        mVMStart(MAP_FAILED),
        mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
        mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
        mExecutingThreadsCount(0),
        mWaitingForThreads(0),
         mMaxThreads(DEFAULT_MAX_BINDER_THREADS), //15 
        mCurrentThreads(0),
        mKernelStartedThreads(0),
        mStarvationStartTimeMs(0),
        mForked(false),
        mThreadPoolStarted(false),
        mThreadPoolSeq(1),
        mCallRestriction(CallRestriction::NONE) {
     unique_fd opened = open_driver(driver); 

    if (opened.ok()) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
                        opened.get(), 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using %s failed: unable to mmap transaction memory.", driver);
            opened.reset();
            mDriverName.clear();
        }
    }

#ifdef __ANDROID__
    LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating.",
                        driver);
#endif

    if (opened.ok()) {
        mDriverFD = opened.release();
    }
}

/*------------------------------------------------------------------*/
static unique_fd open_driver(const char* driver) {
    auto fd = unique_fd(open(driver, O_RDWR | O_CLOEXEC));
    if (!fd.ok()) {
        PLOGE("Opening '%s' failed", driver);
        return {};
    }
    int vers = 0;
    int result = ioctl(fd.get(), BINDER_VERSION, &vers);
    if (result == -1) {
        PLOGE("Binder ioctl to obtain version failed");
        return {};
    }
    if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
        ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! "
              "ioctl() return value: %d",
              vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
        return {};
    }
     size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; 
    // 与 binder 驱动交互,设置 proc->max_threads = max_threads
     result = ioctl(fd.get(), BINDER_SET_MAX_THREADS, &maxThreads); 
    if (result == -1) {
        ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
    }
    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;
}

可单独调用函数设置线程池数量:

status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
    // 如果开启线程池后,则不能再更改线程池数量
    LOG_ALWAYS_FATAL_IF(mThreadPoolStarted && maxThreads < mMaxThreads,
           "Binder threadpool cannot be shrunk after starting");
    status_t result = NO_ERROR;
     if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1)  {
        mMaxThreads = maxThreads;
    } else {
        result = -errno;
        ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
    }
    return result;
}

ServiceManager 未开启线程池,只有一个主线程。

创建线程池

void ProcessState::startThreadPool()
{
    std::unique_lock<std::mutex> _l(mLock);
    if (!mThreadPoolStarted) {
        if (mMaxThreads == 0) {
            // see also getThreadPoolMaxTotalThreadCount
            ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
                  "*startThreadPool when zero threads are requested.");
        }
        // 开启线程池
        mThreadPoolStarted = true;
        // 主线程
        spawnPooledThread(true);
    }
}

// 创建线程实例及运行
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.c_str());
        // 创建一个线程实例
        sp<Thread> t = sp<PoolThread>::make(isMain);
        // 线程启动
        t->run(name.c_str());
        pthread_mutex_lock(&mThreadCountLock);
        mKernelStartedThreads++;
        pthread_mutex_unlock(&mThreadCountLock);
    }
    // TODO: if startThreadPool is called on another thread after the process
    // starts up, the kernel might think that it already requested those
    // binder threads, and additional won't be started. This is likely to
    // cause deadlocks, and it will also cause getThreadPoolMaxTotalThreadCount
    // to return too high of a value.
}

PoolThread

PoolThread 继承于 Thread 类,run 函数回调 threadLoop,isMain 为 true 时,创建主线程,反之则创建非主线程。

// ProcessState.cpp
class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

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

joinThreadPool

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
    pthread_mutex_lock(&mProcess->mThreadCountLock);
    mProcess->mCurrentThreads++;
    pthread_mutex_unlock(&mProcess->mThreadCountLock);
    //先往mOut中往binder驱动写入指令
    //如果是主线程的话发送BC_ENTER_LOOPER,不会退出
    //如果是一般线程的话发送BC_REGISTER_LOOPER,表示 binder 驱动创建出来的线程
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); 

    mIsLooper = true;
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        // 调用 talkWithDriver 将 mOut 中的内容发送给 binder
        // 调用 executeCommand 处理 binder 驱动的响应码
        result = getAndExecuteCommand();

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
        }

        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
        (void*)pthread_self(), getpid(), result);

    mOut.writeInt32(BC_EXIT_LOOPER);
    mIsLooper = false;
    talkWithDriver(false);
    pthread_mutex_lock(&mProcess->mThreadCountLock);
    LOG_ALWAYS_FATAL_IF(mProcess->mCurrentThreads == 0,
                        "Threadpool thread count = 0. Thread cannot exist and exit in empty "
                        "threadpool\n"
                        "Misconfiguration. Increase threadpool max threads configuration\n");
    mProcess->mCurrentThreads--;
    pthread_mutex_unlock(&mProcess->mThreadCountLock);
}

binder 驱动对BC_ENTER_LOOPER 以及BC_REGISTER_LOOPER的处理

**binder_thread_write**中

while (ptr < end && thread->return_error.cmd == BR_OK) {
    // 调用 spawnPooledThread(false) 则创建普通线程
     case BC_REGISTER_LOOPER: //普通线程 
      binder_debug(BINDER_DEBUG_THREADS,
             "%d:%d BC_REGISTER_LOOPER\n",
             proc->pid, thread->pid);
      binder_inner_proc_lock(proc);
      if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
        thread->looper |= BINDER_LOOPER_STATE_INVALID;
        binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n",
          proc->pid, thread->pid);
      } else if (proc->requested_threads == 0) {
        thread->looper |= BINDER_LOOPER_STATE_INVALID;
        binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called without request\n",
          proc->pid, thread->pid);
      } else {
        proc->requested_threads--;
        proc->requested_threads_started++;
      }
      thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
      binder_inner_proc_unlock(proc);
      break;
    // 调用 spawnPooledThread(true) 创建主线程
    // 由 startThreadPool 调用
     case BC_ENTER_LOOPER: // 主线程 
      binder_debug(BINDER_DEBUG_THREADS,
             "%d:%d BC_ENTER_LOOPER\n",
             proc->pid, thread->pid);
      if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
        thread->looper |= BINDER_LOOPER_STATE_INVALID;
        binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
          proc->pid, thread->pid);
      }
      // 设置 thread->looper 为 BINDER_LOOPER_STATE_ENTERED
      thread->looper |= BINDER_LOOPER_STATE_ENTERED;
      break;
     case BC_EXIT_LOOPER: 
      binder_debug(BINDER_DEBUG_THREADS,
             "%d:%d BC_EXIT_LOOPER\n",
             proc->pid, thread->pid);
      thread->looper |= BINDER_LOOPER_STATE_EXITED;
      break;
}

Binder 驱动通知用户态创建线程

binder 驱动拷贝 BR_SPAWN_LOOPER 到用户空间,执行用户空间的代码创建普通线程:

**binder_thread_read**函数中:

当发生以下3种情况之一,便会进入done:

  • 当前线程的return_error发生error的情况;
  • 当Binder驱动向client端发送死亡通知的情况;
  • 当类型为BINDER_WORK_TRANSACTION(即收到命令是BC_TRANSACTION或BC_REPLY)的情况;
binder_thread_read(){
  ...
retry:
    //当前线程todo队列为空且transaction栈为空,则代表该线程是空闲的
    wait_for_proc_work = thread->transaction_stack == NULL &&
        list_empty(&thread->todo);

    if (thread->return_error != BR_OK && ptr < end) {
        ...
        put_user(thread->return_error, (uint32_t __user *)ptr);
        ptr += sizeof(uint32_t);
        goto done; //发生error,则直接进入done
    }

    thread->looper |= BINDER_LOOPER_STATE_WAITING;
    if (wait_for_proc_work)
        proc->ready_threads++; //可用线程个数+1
    binder_unlock(__func__);

    if (wait_for_proc_work) {
        if (non_block) {
            ...
        } else
            //当进程todo队列没有数据,则进入休眠等待状态
            ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    } else {
        if (non_block) {
            ...
        } else
            //当线程todo队列没有数据,则进入休眠等待状态
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
    }

    binder_lock(__func__);
    if (wait_for_proc_work)
        proc->ready_threads--; //可用线程个数-1
    thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

    if (ret)
        return ret; //对于非阻塞的调用,直接返回

    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;

        //先考虑从线程todo队列获取事务数据
        if (!list_empty(&thread->todo)) {
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        //线程todo队列没有数据, 则从进程todo对获取事务数据
        } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
            w = list_first_entry(&proc->todo, struct binder_work, entry);
        } else {
            ... //没有数据,则返回retry
        }

        switch (w->type) {
             case BINDER_WORK_TRANSACTION: { // client 端写入binder_work 时的type 
              binder_inner_proc_unlock(proc);
              t = container_of(w, struct binder_transaction, work);
            } break;
            case BINDER_WORK_TRANSACTION_COMPLETE:...  break;
            case BINDER_WORK_NODE: ...    break;
            case BINDER_WORK_DEAD_BINDER:
            case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
            case BINDER_WORK_CLEAR_DEATH_NOTIFICATION:
                struct binder_ref_death *death;
                uint32_t cmd;

                death = container_of(w, struct binder_ref_death, work);
                if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
                  cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
                else
                  cmd = BR_DEAD_BINDER;
                put_user(cmd, (uint32_t __user *)ptr;
                ptr += sizeof(uint32_t);
                put_user(death->cookie, (void * __user *)ptr);
                ptr += sizeof(void *);
                ...
                if (cmd == BR_DEAD_BINDER)
                   goto done; //Binder驱动向client端发送死亡通知,则进入done 
                break;
        }

        if (!t)
            continue; //只有BINDER_WORK_TRANSACTION命令才能继续往下执行
        ...
        // 跳出 while 循环,执行 done 分支
        break;
    }

done:
    *consumed = ptr - buffer;
    //创建线程的条件
    if (proc->requested_threads + proc->ready_threads == 0 &&
        proc->requested_threads_started < proc->max_threads &&
        (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
         BINDER_LOOPER_STATE_ENTERED))) {
        proc->requested_threads++;
        // 生成BR_SPAWN_LOOPER命令,用于创建新的线程
         put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer); 
    }
    return 0;
}

进程创建线程

status_t IPCThreadState::executeCommand(int32_t cmd)
{
  switch ((uint32_t)cmd) {
    case BR_TRANSACTION: ...
     case BR_SPAWN_LOOPER: 
        mProcess->spawnPooledThread(false); // 创建普通线程 
       break;
  }

  return result;
}
<think>好的,我现在要介绍一下Binder线程池。不过我对这个概念还不是很熟悉,需要先理清楚相关知识。首先,Binder是Android中用于进程间通信(IPC)的机制,所以线程池可能和它处理请求的方式有关。 记得在Android系统中,每个应用进程在和系统服务或者其他进程通信时,会使用Binder驱动。Binder线程池应该是指处理这些Binder请求的线程集合。可能涉及到服务端如何管理并发请求的问题。 那线程池的作用通常是管理多个线程,避免频繁创建和销毁线程的开销。Binder线程池可能由系统维护,用于处理来自不同客户端的请求。每个Binder服务端可能有自己的线程池,或者整个Binder机制有一个共享的池子? 需要确认Binder线程池的默认大小。好像听说过默认是15或者16个线程?例如,在创建Service时,系统可能会分配一定数量的线程来处理收到的Binder调用。这样当多个请求同时到达时,线程池中的线程可以并行处理,提高效率。 另外,主线程和Binder线程的关系如何?主线程可能负责接收请求,然后将任务分发给线程池中的线程?或者Binder驱动直接将请求分发到线程池中的空闲线程? 可能存在一些限制,比如线程池的大小是否可以调整。某些情况下,如果所有线程都被占用,新的请求可能需要等待,或者被丢弃,这可能导致ANR(应用无响应)的问题。开发者可能需要了解如何优化Binder调用的处理时间,避免阻塞线程池中的线程。 还有,Binder线程池的创建和管理是由系统自动处理的,还是应用可以配置?比如,在Service的onBind方法中,或者通过其他方式设置线程池参数? 可能需要查阅Android文档或相关资料,确认这些细节。例如,Android的Binder机制中,每个进程的Binder线程池默认有15个线程,当所有线程都在处理任务时,新的请求会被阻塞,直到有线程可用。因此,开发者需要确保Binder服务中的操作不会长时间阻塞线程,以免影响其他请求的处理。 总结一下,Binder线程池是Android系统中用于处理进程间通信请求的线程池,管理并发的Binder调用,避免资源浪费,并提高处理效率。开发者需要了解其工作机制,以优化应用性能,避免ANR问题。</think>Binder线程池是Android系统中用于管理**Binder IPC通信**的核心机制。以下从结构和工作原理逐步解析: --- ### 一、Binder线程池的作用 1. **处理进程间通信(IPC)** Android应用与系统服务(如`ActivityManagerService`)或其他进程通信时,通过Binder驱动传递请求,线程池负责处理这些跨进程调用。 2. **管理并发请求** 线程池通过复用固定数量的线程,避免频繁创建/销毁线程的开销,提升效率。 --- ### 二、核心机制 1. **默认线程数量** - **每个进程的Binder线程池默认大小为15**(实际为16,其中1个保留给系统)。 - 可通过`adb shell cat /proc/<pid>/limits`查看进程的`max locked memory`字段(含Binder相关限制)。 2. **线程创建规则** - **按需创建**:当请求到达且无空闲线程时,新建线程处理,直到达到上限。 - **空闲回收**:线程空闲一段时间后自动销毁,但核心线程会保留。 --- ### 三、工作流程 1. **客户端发起调用** 客户端通过`Binder Proxy`发送请求至Binder驱动。 2. **驱动分发请求** Binder驱动将请求放入服务端的接收队列,并唤醒空闲线程。 3. **线程池处理** - 空闲线程从队列中取出请求,执行服务端实现的`onTransact()`方法。 - 若所有线程繁忙,新请求需等待,可能导致客户端阻塞或ANR(超时默认为5秒)。 --- ### 四、开发者注意事项 1. **避免阻塞Binder线程** - 在`Service`或`AIDL`接口中,**切勿执行耗时操作**(如网络请求、复杂计算),否则会占满线程池,导致后续请求阻塞。 2. **异步处理策略** ```java // 示例:在AIDL接口中将耗时任务切换到工作线程 @Override public void performTask(final int param) { new Thread(() -> { // 执行耗时操作 }).start(); } ``` 3. **监控Binder调用** - 使用`adb shell dumpsys activity service <service_name>`查看Binder调用状态。 - 通过Systrace或Perfetto分析Binder调用的耗时。 --- ### 五、常见问题 1. **ANR(Application Not Responding)** Binder线程被长时间占用(如主线程同步调用耗时Binder方法)会触发ANR。 **解决方案**:确保主线程不等待Binder调用结果,改用异步回调。 2. **线程池耗尽** 若日志出现`BinderProxy.transactNative failed: java.lang.OutOfMemoryError`,可能是线程池满且内存不足。 **优化方案**:减少同步Binder调用,拆分大事务。 --- ### 六、高级配置 - **调整线程池大小**(需Root权限) 修改`/sys/module/binder/parameters/max_threads`文件,但Android默认限制生效,通常不建议修改。 --- ### 总结 Binder线程池是Android IPC的基石,其设计平衡了并发性能和资源消耗。开发者需遵循**异步化**和**轻量化**原则,确保Binder调用高效执行,从而提升应用整体性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值