binder进程间通讯 C程序代码示例添加多线程支持 下载链接 binder_c_thread
如果多个client同时向server发起请求,就有可能导致binder驱动,告知server需要创建线程。该逻辑在binder驱动中的binder_thread_read函数中。binder驱动源码路径:kernel\drivers\android\binder.c
done:
*consumed = ptr - buffer;
binder_inner_proc_lock(proc);
if (proc->requested_threads == 0 &&
list_empty(&thread->proc->waiting_threads) &&
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 */) {
proc->requested_threads++;//1
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);
可以看出需要同时满足以下条件,才会告知server进程创建线程
- server进程中的 requested_threads 为0。这个代表创建线程的请求,在注释1处会自加,当binder驱动接收到BC_REGISTER_LOOPER命令时,会自减。所以server进程创建好线程后,需要发出BC_REGISTER_LOOPER,否则requested_threads 不可能为0
- server进程等待的线程为空
- 请求创建的线程数要小于max_threads最大线程数。max_threads默认为0,binder驱动通过接收到BINDER_SET_MAX_THREADS命令设置
满足条件后,就会向server进程发出BR_SPAWN_LOOPER,让server进程去创建线程
所以,如果server需要添加多线程支持,就要做以下工作:
1,设置最大线程数
void set_max_thread(struct binder_state *bs,int value){
ioctl(bs->fd, BINDER_SET_MAX_THREADS, &value);
}
2,在处理函数中处理BR_SPAWN_LOOPER命令,创建线程
void *my_binder_thread_func(struct my_thread_data *data){
/*进入循环等待数据*/
my_binder_loop(data->my_bs, data->func);
return NULL;
}
case BR_SPAWN_LOOPER:{
/*创建新线程*/
pthread_t my_pthread_t;
struct my_thread_data my_data ;
my_data.my_bs=bs;
my_data.func=func;
pthread_create(&my_pthread_t,NULL,my_binder_thread_func,&my_data);
break;
}
注意在 my_binder_loop 中需要发出BC_REGISTER_LOOPER
void my_binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_REGISTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
添加以上内容后,经测试,server进程是可以支持多线程的
# ps -t | grep test_server
root 24257 17186 4720 1588 binder_thr b3ddf8e8 S test_server
root 24329 24257 4720 1588 binder_thr b3ddf8e8 S test_server
可以看出已经多了一个线程。如果不加上面的内容,就只有一个主线程。
总结
binder多线程由binder驱动发起,server进程处理。处理之后需要发送BC_REGISTER_LOOPER。
具体的代码实现可参考上面的下载链接中的文件。