在binder系统中,由一个server进程提供服务,有一个或者多个client向他发送服务请求,并且是有可能同时发生请求的,假若client进程非常的多,server进程忙不过来怎么办呢?
忙不过来时,创建多线程,由这些线程处理这些服务。那么怎么才能判断他忙不过来?通过前面的小节我们知道,对于每一个进程都存在一个binder_proc,binder_proc中有一个todo链表,当client发送请求的时候,会把数据放入到todo链表,并且唤醒等待在todo这个链表上的线程,如果有线程在wait这里等待,则代表忙得过来,如果没有一个线程在等待,就代表已经忙不过来了,下图四个简要框图:
这个时候,驱动程序就会向server进程发出相应,告诉server进程需要创建更多的线程。 1.是在驱动程序中判断,是否忙得过来。 2.驱动程序向APP发出请求,创建新线程。 3.APP创建新线程
围绕着上面3点我们去查看源代码(SDK/kernel/driver/android/binder.c),找到其中的binder_thread_read函数,在该函数的最末尾部分,可以看到如下代码:
binder_inner_proc_lock(proc);
/*当proc->requested_threads == 0:未处理的新线程请求,list_empty(&thread->proc->waiting_threads):等待的线程为0时,
proc->requested_threads_started < proc->max_threads:已经启动的线程数,小于设定的最大值*/
if (proc->requested_threads == 0 &&
list_empty(&thread->proc->waiting_threads) &&
proc->requested_threads_started 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,当新线程运行完成的时候-1*/
proc->requested_threads++;
binder_inner_proc_unlock(proc);
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BR_SPAWN_LOOPER\n",
proc->pid, thread->pid);
/*发送一个创建线程的请求给应用程序*/
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
} else
binder_inner_proc_unlock(proc);
其作用就是判断是否发送创建新线程的请求。驱动程序向APP发出"创建新线程请求"的条件: 1.proc->requested_threads == 0(未处理的新线程请求) 2.list_empty(&thread->proc->waiting_threads):等待的线程为0 3.proc->requested_threads_started < proc->max_threads:已经启动的线程数,小于设定最大值数max_threads
在发送请求之后,会执行proc->requested_threads++,当应用程序调用新线程,进行写操作时,会执行proc->requested_threads–。如下:
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)
case BC_REGISTER_LOOPER:
/*未处理的线程数*/
proc->requested_threads--;
/*启动的线程数目+1*/
proc->requested_threads_started++;
表示新的线程已经进入了循环体。
那么我们怎么去写应用程序呢? 1.设置max_threads,如果未设定,默认值为0 2.收到BR_SPAWN_LOOPER时,创建新线程。 3.新线程要执行一个ioctl,发送BC_REGISTER_LOOPER给驱动程序,告诉其已经进入循环体了 4.像主线程一样进入一个循环体:read-driver,处理。