目录
1. 前言
本文主要是
binder系列
文章的总结笔记,主要是理清binder的总体流程和总体架构,期间会对照Android R进行代码重读,也会按照自己的理解对内容进行调整,以加深对binder总体的理解。本文主要讲述 获取binder线程创建,主要以vold进程的binder线程创建为例。
2. vold/main
vold/main
|--mkdir("/dev/block/vold", 0755);
|--vm = VolumeManager::Instance()
|--nm = NetlinkManager::Instance()
|--vm->start()
|--process_config(vm, &has_adoptable, &has_quota, &has_reserved)
|--android::vold::VoldNativeService::start()
| |--IPCThreadState::self()->disableBackgroundScheduling(true);
| |--BinderService<VoldNativeService>::publish();
| |--sp<ProcessState> ps(ProcessState::self())
| |--ps->startThreadPool()
| |--ps->giveThreadPoolName()
|--nm->start()
|--coldboot("/sys/block");
|- -ProcessState::self()
ProcessState::self()是单例模式,主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值ProcessState对象中的变量mDriverFD,用于交互操作。
ProcessState::self()
|--if (gProcess != nullptr) return gProcess;
|--gProcess = new ProcessState(kDefaultDriver)
|--open_driver(driver)
| |--status_t result = ioctl(fd, BINDER_VERSION, &vers)
| |--size_t maxThreads = DEFAULT_MAX_BINDER_THREADS
| |--result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
|--mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE |
MAP_NORESERVE, mDriverFD, 0);
ProcessState的单例模式的惟一性,因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD记录binder驱动的fd,用于访问binder设备。ProcessState是负责打开Binder节点并做mmap映射,IPCThreadState是负责与Binder驱动进行具体的命令交互。open_driver会创建binder_proc,binder_proc的pid为当前进程组的领头进程,它会被保存到filp->private_data中
|- -ps->startThreadPool()
ps->startThreadPool();
|--mThreadPoolStarted = true
|--spawnPooledThread(true)
| //获取Binder线程名Binder:<pid>_x
|--String8 name = makeBinderThreadName();
|--sp<Thread> t = new PoolThread(isMain);
|--t->run(name.string())
|--threadLoop()
threadLoop()
|--IPCThreadState::self()->joinThreadPool(mIsMain)
| //对于isMain=true的情况下, command为BC_ENTER_LOOPER,代表的是Binder主线程,不会退出的线程;
| //对于isMain=false的情况下,command为BC_REGISTER_LOOPER,表示是由binder驱动创建的线程。
|--mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER)
|--do {
| //清除队列的引用
| processPendingDerefs();
| result = getAndExecuteCommand()
| } while (result != -ECONNREFUSED && result != -EBADF);
|--mOut.writeInt32(BC_EXIT_LOOPER);
|--talkWithDriver(false)
startThreadPool主要是通过创建线程池,实际只创建了一个线程,最终执行joinThreadPool,通过循环调用getAndExecuteCommand->talkWithDriver来与binder驱动进行交互。
IPCThreadState::getAndExecuteCommand
|--result = talkWithDriver();
| |-- binder_write_read bwr
| |--bwr.write_size = outAvail;
| | bwr.write_buffer = (uintptr_t)mOut.data()
| |--do {
| | if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
| | err = NO_ERROR;
| | } while (err == -EINTR);
|--size_t IN = mIn.dataAvail()
|--cmd = mIn.readInt32()
|--mProcess->mExecutingThreadsCount++;
|--result = executeCommand(cmd)
|- – -ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
|--struct binder_proc *proc = filp->private_data
|--wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
|--thread = binder_get_thread(proc)
|--switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
...
}
binder_ioctl_write_read(filp, cmd, arg, thread)
|--struct binder_proc *proc = filp->private_data
| void __user *ubuf = (void __user *)arg
|--copy_from_user(&bwr, ubuf, sizeof(bwr))
|--if (bwr.write_size > 0)
| binder_thread_write(proc, thread,
| bwr.write_buffer,
| bwr.write_size,
| &bwr.write_consumed);
|--if (bwr.read_size > 0)
| binder_thread_read(proc, thread, bwr.read_buffer,
| bwr.read_size,
| &bwr.read_consumed,
| filp->f_flags & O_NONBLOCK);
|--copy_to_user(ubuf, &bwr, sizeof(bwr)
首先进入binder_thread_write过程
binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
|--struct binder_context *context = proc->context
| 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.cmd == BR_OK)
//拷贝用户空间的cmd命令,此时为BC_ENTER_LOOPER
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
switch (cmd) {
......
case BC_ENTER_LOOPER:
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
//出错原因:线程调用完BC_REGISTER_LOOPER,不能立刻执行该分支
thread->looper |= BINDER_LOOPER_STATE_INVALID;
}
//创建Binder主线程
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
处理完BC_ENTER_LOOPER命令后,一般情况下成功设置thread->looper |= BINDER_LOOPER_STATE_ENTERED。那么binder线程的创建是在什么时候呢? 那就当该线程有事务需要处理的时候,进入binder_thread_read()过程
binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK)
|--void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
| void __user *ptr = buffer + *consumed;
| void __user *end = buffer + size;
| //当前线程todo队列为空且transaction栈为空,则代表该线程是空闲的
|--wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
| if (non_block) {
| if (!binder_has_work(thread, wait_for_proc_work))
| ret = -EAGAIN;
| } else //阻塞的则等待处理完毕
| ret = binder_wait_for_work(thread, wait_for_proc_work);
| thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
|--while (1) {
| uint32_t cmd;
| struct binder_transaction_data_secctx tr;
| struct binder_transaction_data *trd = &tr.transaction_data;
| struct binder_work *w = NULL;
| struct list_head *list = NULL;
| struct binder_transaction *t = NULL;
| struct binder_thread *t_from;
| size_t trsize = sizeof(*trd);
|
| binder_inner_proc_lock(proc);
| if (!binder_worklist_empty_ilocked(&thread->todo))
| list = &thread->todo;
| else if (!binder_worklist_empty_ilocked(&proc->todo) &&
| wait_for_proc_work)
| list = &proc->todo;
| else {
| binder_inner_proc_unlock(proc);
|
| /* no data added */
| if (ptr - buffer == 4 && !thread->looper_need_return)
| goto retry;
| break;
| }
| if (end - ptr < sizeof(tr) + 4) {
| binder_inner_proc_unlock(proc);
| break;
| }
| w = binder_dequeue_work_head_ilocked(list);
| if (binder_worklist_empty_ilocked(&thread->todo))
| thread->process_todo = false;
|
| switch (w->type) {
| case BINDER_WORK_TRANSACTION: {
| binder_inner_proc_unlock(proc);
| t = container_of(w, struct binder_transaction, work);
| } break;
| ....
| if (!t)
| continue;
| ...
|--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);
|- – -executeCommand(cmd)
IPC.joinThreadPool –> IPC.getAndExecuteCommand() -> IPC.talkWithDriver() ,但talkWithDriver收到事务之后, 便进入IPC.executeCommand(), 接下来,从executeCommand说起.
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;
| ...
参考文档