Android系统进程间通信(IPC)机制Binder中的Client获(5)

接着创建一个待完成事项tcomplete,它的类型为struct binder_work,这是等一会要保存在当前线程的todo队列去的,表示当前线程有一个待完成的事务。紧跟着创建一个待处理事务t,它的类型为struct binder_transaction,这是等一会要存在到Service Manager的todo队列去的,表示Service Manager当前有一个事务需要处理。同时,这个待处理事务t也要存放在当前线程的待完成事务transaction_stack列表中去:

t->from_parent = thread->transaction_stack;   thread->transaction_stack = t;  

        这样表明当前线程还有事务要处理。

继续往下看,就是分别把tcomplete和t放在当前线程thread和Service Manager进程的todo队列去了:

 

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);  

        最后,Service Manager有事情可做了,就要唤醒它了:

 

wake_up_interruptible(target_wait);  

前面我们提到,此时Service Manager正在等待Client的请求,也就是Service Manager此时正在进入到Binder驱动程序的binder_thread_read函数中,并且休眠在target->wait上,具体参考浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路一文。

这里,我们暂时忽略Service Manager被唤醒之后的情景,继续看当前线程的执行。

函数binder_transaction执行完成之后,就一路返回到binder_ioctl函数里去了。函数binder_ioctl从binder_thread_write函数调用处返回后,发现bwr.read_size大于0,于是就进入到binder_thread_read函数去了:

static int   binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,                      void  __user *buffer, int size, signed long *consumed, int non_block)   {       void __user *ptr = buffer + *consumed;       void __user *end = buffer + size;          int ret = 0;       int wait_for_proc_work;          if (*consumed == 0) {           if (put_user(BR_NOOP, (uint32_t __user *)ptr))               return -EFAULT;           ptr += sizeof(uint32_t);       }      retry:       wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);          ......              if (wait_for_proc_work) {           ......       } else {           if (non_block) {               if (!binder_has_thread_work(thread))                   ret = -EAGAIN;           } else               ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));       }          ......          while (1) {           uint32_t cmd;           struct binder_transaction_data tr;           struct binder_work *w;           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 {               if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */                   goto retry;               break;           }              if (end - ptr < sizeof(tr) + 4)               break;              switch (w->type) {           ......           case BINDER_WORK_TRANSACTION_COMPLETE: {               cmd = BR_TRANSACTION_COMPLETE;               if (put_user(cmd, (uint32_t __user *)ptr))                   return -EFAULT;               ptr += sizeof(uint32_t);                  binder_stat_br(proc, thread, cmd);               if (binder_debug_mask & BINDER_DEBUG_TRANSACTION_COMPLETE)                   printk(KERN_INFO "binder: %d:%d BR_TRANSACTION_COMPLETE\n",                   proc->pid, thread->pid);                  list_del(&w->entry);               kfree(w);               binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++;                                                  } break;           ......           }              if (!t)               continue;              ......       }      done:       ......       return 0;   }  

       函数首先是写入一个操作码BR_NOOP到用户传进来的缓冲区中去。

回忆一下上面的binder_transaction函数,这里的thread->transaction_stack != NULL,并且thread->todo也不为空,所以线程不会进入休眠状态。

进入while循环中,首先是从thread->todo队列中取回待处理事项w,w的类型为BINDER_WORK_TRANSACTION_COMPLETE,这也是在binder_transaction函数里面设置的。对BINDER_WORK_TRANSACTION_COMPLETE的处理也很简单,只是把一个操作码BR_TRANSACTION_COMPLETE写回到用户传进来的缓冲区中去。这时候,用户传进来的缓冲区就包含两个操作码了,分别是BR_NOOP和BINDER_WORK_TRANSACTION_COMPLETE。

binder_thread_read执行完之后,返回到binder_ioctl函数中,将操作结果写回到用户空间中去:

 

if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {       ret = -EFAULT;       goto err;   }  

       最后就返回到IPCThreadState::talkWithDriver函数中了。

IPCThreadState::talkWithDriver函数从下面语句:

 

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)  

       返回后,首先是清空之前写入Binder驱动程序的内容:

 

if (bwr.write_consumed > 0) {        if (bwr.write_consumed < (ssize_t)mOut.dataSize())             mOut.remove(0, bwr.write_consumed);        else             mOut.setDataSize(0);   }  

       接着是设置从Binder驱动程序读取的内容:

 

if (bwr.read_consumed > 0) {        mIn.setDataSize(bwr.read_consumed);        mIn.setDataPosition(0);   }  

       然后就返回到IPCThreadState::waitForResponse去了。IPCThreadState::waitForResponse函数的处理也很简单,就是处理刚才从Binder驱动程序读入内容了。从前面的分析中,我们知道,从Binder驱动程序读入的内容就是两个整数了,分别是BR_NOOP和BR_TRANSACTION_COMPLETE。对BR_NOOP的处理很简单,正如它的名字所示,什么也不做;而对BR_TRANSACTION_COMPLETE的处理,就分情况了,如果这个请求是异步的,那个整个BC_TRANSACTION操作就完成了,如果这个请求是同步的,即要等待回复的,也就是reply不为空,那么还要继续通过IPCThreadState::talkWithDriver进入到Binder驱动程序中去等待BC_TRANSACTION操作的处理结果。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwjjgs.html