Binder本身是C/S架构,就可能存在多个Client会同时访问Server的情况。 在这种情况下,如果Server只有一个线程处理响应,就会导致客户端的请求可能需要排队而导致响应过慢的现象发生。解决这个问题的方法就是引入多线程。【多个客户端不同线程去请求,服务端需要使用多线程机制,binder线程池,创建多个线程去回复多个客户端的请求】
Binder机制的设计从最底层–驱动层,就考虑到了对于多线程的支持。具体内容如下:
a. 使用 Binder 的进程在启动之后,通过 BINDER_SET_MAX_THREADS 告知驱动其支持的最大线程数量
b. 驱动会对线程进行管理。在 binder_proc 结构中,这些字段记录了进程中线程的信息:max_threads,requested_threads,requested_threads_started,ready_threads
c. binder_thread 结构对应了 Binder 进程中的线程
d. 驱动通过 BR_SPAWN_LOOPER 命令告知进程需要创建一个新的线程
c. 进程通过 BC_ENTER_LOOPER 命令告知驱动其主线程已经ready
d. 进程通过 BC_REGISTER_LOOPER 命令告知驱动其子线程(非主线程)已经ready
e. 进程通过 BC_EXIT_LOOPER 命令告知驱动其线程将要退出
f. 在线程退出之后,通过 BINDER_THREAD_EXIT 告知Binder驱动。驱动将对应的 binder_thread 对象销毁
1. 最大的binder 数量
在每个进程启动时候,都会创建 ProcessState 对象,获得ProcessState对象是单例模式,从而保证每一个进程只有一个ProcessState对象。因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD记录binder驱动的fd,用于访问binder设备。
/frameworks/native/libs/binder/ProcessState.cpp
// 在创建 ProcessState 对象的时候,会去打开driver
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != nullptr) {
return gProcess;
}
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
// 打开驱动设备
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
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);
close(fd);
fd = -1;
}
// 设置最大的线程数量为:15
// #define DEFAULT_MAX_BINDER_THREADS 15
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
// 与binder 驱动交互,设置驱动的线程数量为 15个
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
return fd;
}
与binder 驱动交互,设置最大线程数量
/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
binder_lock(__func__);
// 这里可以通过进程获取对应的线程
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
。。。
case BINDER_SET_MAX_THREADS:
// 保存到 proc->max_threads
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
设置 binder_proc 结构体的 max_threads 为 15,结构体为如下:
struct binder_proc {
struct hlist_node proc_node;
// 使用红黑树保存 threads 线程
struct rb_root threads;
// 进程的pid 号
int pid;
// 进程需要做的事项
struct list_head todo;
// 保存最大的线程数量
int max_threads;
// 请求的线程数量
int requested_threads;
int requested_threads_started;
int ready_threads;
};
2. binder 主线程的创建
进程调用下列 startThreadPool 方法,去启动binder 主线程
ProcessState::self()->startThreadPool();
/frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
// mThreadPoolStarted 初始值为 false
if (!mThreadPoolStarted) {
// 设置为true,走到 spawnPooledThread(true)
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
走到 spawnPooledThread(true)
void ProcessState::spawnPooledThread(bool isMain)
{
// 如果没有执行:startThreadPool,则 mThreadPoolStarted 为false,不走下列的代码
// 此时是为 true 的
if (mThreadPoolStarted) {
// 设置binder thread 的名字
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
// 创建一个线程PoolThread,isMain 为true 表示是主线程
sp<Thread> t = new PoolThread(isMain);
// run 这个线程
t->run(name.string());
}
}
==========
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
pid_t pid = getpid();
String8 name;
// 主线程的binder 名字为:Binder:pid号_1,如:Binder:9320_1
name.appendFormat("Binder:%d_%X", pid, s);
return name;
}
创建一个线程PoolThread,isMain 为true 表示是主线程
PoolThread 继承了 Thread:
/system/core/libutils/include/utils/threads.h
28 #include <utils/AndroidThreads.h>
29
30 #ifdef __cplusplus
31 #include <utils/Condition.h>
32 #include <utils/Errors.h>
33 #include <utils/Mutex.h>
34 #include <utils/RWLock.h>
35 #include <utils/Thread.h>
36 #endif
37
38 #endif // _LIBS_UTILS_THREADS_H
/system/core/libutils/Threads.cpp
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
LOG_ALWAYS_FATAL_IF(name == nullptr, "thread name not provided to Thread::run");
Mutex::Autolock _l(mLock);
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = OK;
mExitPending = false;
mThread = thread_id_t(-1);
// hold a strong reference on ourself
mHoldSelf = this;
mRunning = true;
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
======
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast<Thread*>(user);
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
self->mHoldSelf.clear();
#if defined(__ANDROID__)
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
bool first = true;
do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == OK);
if (result && !self->exitPending()) {
// Binder threads (and maybe others) rely on threadLoop
// running at least once after a successful ::readyToRun()
// (unless, of course, the thread has already been asked to exit
// at that point).
// This is because threads are essentially used like this:
// (new ThreadSubclass())->run();
// The caller therefore does not retain a strong reference to
// the thread and the thread would simply disappear after the
// successful ::readyToRun() call instead of entering the
// threadLoop at least once.
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
执行run 方法,循环回调 threadLoop 方法
class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
// 一个线程只有一个 IPCThreadState 实例,调用 joinThreadPool 方法
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
调用 joinThreadPool 方法
/frameworks/native/libs/binder/IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
// 如果 isMain 为true ,则为 BC_ENTER_LOOPER
// false 为:BC_REGISTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
// talkwithdriver 去驱动设备交互,执行命令
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
binder 驱动对:BC_ENTER_LOOPER 的处理
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
switch (cmd) {
。。。。。。。。
case BC_ENTER_LOOPER:
// 如果 thread->looper 有设置 binder 普通线程的值:BINDER_LOOPER_STATE_REGISTERED,则回复error
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:0x02, 位运算来保存
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
// 如果是退出线程的话,则设置为:BINDER_LOOPER_STATE_EXITED 0x04
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;
3. binder 普通线程的创建
线程池是在service端,用于响应处理client端的众多请求。binder线程池中的线程都是由Binder驱动来控制创建的。
创建binder 普通线程是由binder 驱动控制的,驱动通过 BR_SPAWN_LOOPER 命令告知进程需要创建一个新的线程,然后进程通过 BC_REGISTER_LOOPER 命令告知驱动其子线程(非主线程)已经ready
service 端创建线程的2种情况:
- BC_TRANSACTION:client进程向binderDriver发送IPC调用请求的时候。
- BC_REPLY:client进程收到了binderDriver的IPC调用请求,逻辑执行结束后发送返回值。
首先客户端调用 IPCThreadState::transact:
-
客户端进程
/frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err;
flags |= TF_ACCEPT_FDS;
// 封装data 值
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
if (reply) {
// 与binder 驱动交互 waitForResponse
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
// 与binder 驱动交互 waitForResponse
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
========================
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
// 与binder 驱动交互
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
与binder 驱动交互:BC_TRANSACTION
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
。。。。。
// 只有cmd 命令是 BC_TRANSACTION 和 BC_REPLY 才会调用 binder_transaction 函数
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
只有cmd 命令是 BC_TRANSACTION 和 BC_REPLY 才会调用 binder_transaction 函数
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end;
binder_size_t off_min;
。。。。。。
}
// 设置工作类型为 BINDER_WORK_TRANSACTION,增加到工作的双向链表中
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
// 唤醒对应的进程处理
if (target_wait)
wake_up_interruptible(target_wait);
return;
-
service 服务端处理消息
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
// 如果返回有 error,则有可能 执行到 done
if (thread->return_error != BR_OK && ptr < end) {
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error2);
if (ptr == end)
goto done;
thread->return_error2 = BR_OK;
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error);
thread->return_error = BR_OK;
goto done;
}
。。。。。。
// 执行while 循环
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
// 初始值 t 为 null
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work,
entry);
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
w = list_first_entry(&proc->todo, struct binder_work,
entry);
} else {
/* no data added */
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}
if (end - ptr < sizeof(tr) + 4)
break;
switch (w->type) {
// 执行 BINDER_WORK_TRANSACTION,t 不为空,不走cotinue,回走到 done 分支
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
。。。。。
// 如果命令是 BR_DEAD_BINDER,也会走到 done
if (cmd == BR_DEAD_BINDER)
goto done; /* DEAD_BINDER notifications can cause transactions */
} break;
}
// 如果 t 为null,则执行 continue,不退出循环
if (!t)
continue;
。。。
} else {
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
break;
// 下列括号是 while 的括号
}
done:
*consumed = ptr - buffer;
// 需要满足 3 个条件:
// 1. 当前进程没有可请求的线程,也没有已经ready可用的线程
// 2. 启动的线程要小于 15;
// 3. 对应的client中的线程不能已经启动过。
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)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
// 设置请求线程的数量 + 1
proc->requested_threads++;
// 拷贝 BR_SPAWN_LOOPER 到用户空间
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
return 0;
}
当发生以下3种情况之一,便会进入done分支:
- 当前线程的return_error发生error的情况;
- 当Binder驱动向client端发送死亡通知的情况;
- 当类型为BINDER_WORK_TRANSACTION(即收到命令是BC_TRANSACTION或BC_REPLY)的情况;
线程的含义:
- ready_threads: 表示当前线程池中有多少可用的空闲线程。
- requested_threads:请求开启线程的数量。
- requested_threads_started:表示当前已经接受请求开启的线程数量。
创建 Binder 普通线程的条件有3个:
1. 当前进程没有可请求的线程,也没有已经ready可用的线程
2. 启动的线程要小于 15;
3. 对应的client中的线程不能已经启动过
拷贝 BR_SPAWN_LOOPER 到用户空间,执行用户空间的代码创建普通线程:
/frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);
executeCommand
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_SPAWN_LOOPER:
mProcess->spawnPooledThread(false);
break;
执行 mProcess->spawnPooledThread(false)
/frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::spawnPooledThread(bool isMain)
{
// isMain 为false
if (mThreadPoolStarted) {
// 设置binder 的名字:
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
// 创建 PoolThread对象,指向run 方法
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
=======
String8 ProcessState::makeBinderThreadName() {
// 递增加1
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
pid_t pid = getpid();
String8 name;
// 这里为:Binder:9032_2
name.appendFormat("Binder:%d_%X", pid, s);
return name;
}
创建 PoolThread对象,指向run 方法
class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
又回到:IPCThreadState::self()->joinThreadPool(false),此 IPCThreadState 对象是个新的对象,与主线程的 IPCThreadState 是不同的。
/frameworks/native/libs/binder/IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
// isMain 为false,与binder 驱动交互的命令是 BC_REGISTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
// 如果普通线程返回的结果是 TIMED_OUT,则回收该普通线程
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);
// 通知binder 驱动线程退出了:BC_EXIT_LOOPER
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
isMain 为false,与binder 驱动交互的命令是 BC_REGISTER_LOOPER
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
。。。。。。。
case BC_REGISTER_LOOPER:
// 如果是主线程,则报错。
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);
// 如果binder 驱动都没有请求创建线程,则报错
} 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 {
// requested_threads减1, requested_threads_started开启的线程增加为 1;
proc->requested_threads--;
proc->requested_threads_started++;
}
// 设置looper 模式
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
break;
Binder机制中的收发消息及线程池 - 腾讯云开发者社区-腾讯云文章来源:https://www.toymoban.com/news/detail-426785.html
进程的Binder线程池工作过程-移动端开发文章来源地址https://www.toymoban.com/news/detail-426785.html
到了这里,关于【安卓源码】Binder机制3 -- Binder线程池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!