Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(2)

简介:

这个函数虽然很长,但是主要调用了talkWithDriver函数来与Binder驱动程序进行交互:

 

 
 
  1. status_t IPCThreadState::talkWithDriver(bool doReceive)  
  2. {  
  3.     LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");  
  4.       
  5.     binder_write_read bwr;  
  6.       
  7.     // Is the read buffer empty?  
  8.     const bool needRead = mIn.dataPosition() >= mIn.dataSize();  
  9.       
  10.     // We don't want to write anything if we are still reading  
  11.     // from data left in the input buffer and the caller  
  12.     // has requested to read the next data.  
  13.     const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;  
  14.       
  15.     bwr.write_size = outAvail;  
  16.     bwr.write_buffer = (long unsigned int)mOut.data();  
  17.  
  18.     // This is what we'll read.  
  19.     if (doReceive && needRead) {  
  20.         bwr.read_size = mIn.dataCapacity();  
  21.         bwr.read_buffer = (long unsigned int)mIn.data();  
  22.     } else {  
  23.         bwr.read_size = 0;  
  24.     }  
  25.       
  26.     IF_LOG_COMMANDS() {  
  27.         TextOutput::Bundle _b(alog);  
  28.         if (outAvail != 0) {  
  29.             alog << "Sending commands to driver: " << indent;  
  30.             const void* cmds = (const void*)bwr.write_buffer;  
  31.             const void* end = ((const uint8_t*)cmds)+bwr.write_size;  
  32.             alog << HexDump(cmds, bwr.write_size) << endl;  
  33.             while (cmds < end) cmds = printCommand(alog, cmds);  
  34.             alog << dedent;  
  35.         }  
  36.         alog << "Size of receive buffer: " << bwr.read_size  
  37.             << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;  
  38.     }  
  39.       
  40.     // Return immediately if there is nothing to do.  
  41.     if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;  
  42.       
  43.     bwr.write_consumed = 0;  
  44.     bwr.read_consumed = 0;  
  45.     status_t err;  
  46.     do {  
  47.         IF_LOG_COMMANDS() {  
  48.             alog << "About to read/write, write size = " << mOut.dataSize() << endl;  
  49.         }  
  50. #if defined(HAVE_ANDROID_OS)  
  51.         if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)  
  52.             err = NO_ERROR;  
  53.         else 
  54.             err = -errno;  
  55. #else 
  56.         err = INVALID_OPERATION;  
  57. #endif  
  58.         IF_LOG_COMMANDS() {  
  59.             alog << "Finished read/write, write size = " << mOut.dataSize() << endl;  
  60.         }  
  61.     } while (err == -EINTR);  
  62.       
  63.     IF_LOG_COMMANDS() {  
  64.         alog << "Our err: " << (void*)err << ", write consumed: " 
  65.             << bwr.write_consumed << " (of " << mOut.dataSize()  
  66.             << "), read consumed: " << bwr.read_consumed << endl;  
  67.     }  
  68.  
  69.     if (err >= NO_ERROR) {  
  70.         if (bwr.write_consumed > 0) {  
  71.             if (bwr.write_consumed < (ssize_t)mOut.dataSize())  
  72.                 mOut.remove(0, bwr.write_consumed);  
  73.             else 
  74.                 mOut.setDataSize(0);  
  75.         }  
  76.         if (bwr.read_consumed > 0) {  
  77.             mIn.setDataSize(bwr.read_consumed);  
  78.             mIn.setDataPosition(0);  
  79.         }  
  80.         IF_LOG_COMMANDS() {  
  81.             TextOutput::Bundle _b(alog);  
  82.             alog << "Remaining data size: " << mOut.dataSize() << endl;  
  83.             alog << "Received commands from driver: " << indent;  
  84.             const void* cmds = mIn.data();  
  85.             const void* end = mIn.data() + mIn.dataSize();  
  86.             alog << HexDump(cmds, mIn.dataSize()) << endl;  
  87.             while (cmds < end) cmds = printReturnCommand(alog, cmds);  
  88.             alog << dedent;  
  89.         }  
  90.         return NO_ERROR;  
  91.     }  
  92.       
  93.     return err;  

   这里doReceive和needRead均为1,有兴趣的读者可以自已分析一下。因此,这里告诉Binder驱动程序,先执行write操作,再执行read操作,下面我们将会看到。

 

        最后,通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)进行到Binder驱动程序的binder_ioctl函数,我们只关注cmd为BINDER_WRITE_READ的逻辑:

 

 
 
  1. static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  2. {  
  3.     int ret;  
  4.     struct binder_proc *proc = filp->private_data;  
  5.     struct binder_thread *thread;  
  6.     unsigned int size = _IOC_SIZE(cmd);  
  7.     void __user *ubuf = (void __user *)arg;  
  8.  
  9.     /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/  
  10.  
  11.     ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);  
  12.     if (ret)  
  13.         return ret;  
  14.  
  15.     mutex_lock(&binder_lock);  
  16.     thread = binder_get_thread(proc);  
  17.     if (thread == NULL) {  
  18.         ret = -ENOMEM;  
  19.         goto err;  
  20.     }  
  21.  
  22.     switch (cmd) {  
  23.     case BINDER_WRITE_READ: {  
  24.         struct binder_write_read bwr;  
  25.         if (size != sizeof(struct binder_write_read)) {  
  26.             ret = -EINVAL;  
  27.             goto err;  
  28.         }  
  29.         if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {  
  30.             ret = -EFAULT;  
  31.             goto err;  
  32.         }  
  33.         if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  34.             printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",  
  35.             proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);  
  36.         if (bwr.write_size > 0) {  
  37.             ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);  
  38.             if (ret < 0) {  
  39.                 bwr.read_consumed = 0;  
  40.                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  41.                     ret = -EFAULT;  
  42.                 goto err;  
  43.             }  
  44.         }  
  45.         if (bwr.read_size > 0) {  
  46.             ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);  
  47.             if (!list_empty(&proc->todo))  
  48.                 wake_up_interruptible(&proc->wait);  
  49.             if (ret < 0) {  
  50.                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  51.                     ret = -EFAULT;  
  52.                 goto err;  
  53.             }  
  54.         }  
  55.         if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  56.             printk(KERN_INFO "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",  
  57.             proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size);  
  58.         if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {  
  59.             ret = -EFAULT;  
  60.             goto err;  
  61.         }  
  62.         break;  
  63.     }  
  64.     ......  
  65.     }  
  66.     ret = 0;  
  67. err:  
  68.     ......  
  69.     return ret;  

   函数首先是将用户传进来的参数拷贝到本地变量struct binder_write_read bwr中去。这里bwr.write_size > 0为true,因此,进入到binder_thread_write函数中,我们只关注BC_TRANSACTION部分的逻辑:

 

 
 
  1. binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,  
  2.                     void __user *buffer, int size, signed long *consumed)  
  3. {  
  4.     uint32_t cmd;  
  5.     void __user *ptr = buffer + *consumed;  
  6.     void __user *end = buffer + size;  
  7.  
  8.     while (ptr < end && thread->return_error == BR_OK) {  
  9.         if (get_user(cmd, (uint32_t __user *)ptr))  
  10.             return -EFAULT;  
  11.         ptr += sizeof(uint32_t);  
  12.         if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {  
  13.             binder_stats.bc[_IOC_NR(cmd)]++;  
  14.             proc->stats.bc[_IOC_NR(cmd)]++;  
  15.             thread->stats.bc[_IOC_NR(cmd)]++;  
  16.         }  
  17.         switch (cmd) {  
  18.             .....  
  19.         case BC_TRANSACTION:  
  20.         case BC_REPLY: {  
  21.             struct binder_transaction_data tr;  
  22.  
  23.             if (copy_from_user(&tr, ptr, sizeof(tr)))  
  24.                 return -EFAULT;  
  25.             ptr += sizeof(tr);  
  26.             binder_transaction(proc, thread, &tr, cmd == BC_REPLY);  
  27.             break;  
  28.         }  
  29.         ......  
  30.         }  
  31.         *consumed = ptr - buffer;  
  32.     }  
  33.     return 0;  

首先将用户传进来的transact参数拷贝在本地变量struct binder_transaction_data tr中去,接着调用binder_transaction函数进一步处理,这里我们忽略掉无关代码:

 

 
 
  1. static void  
  2. binder_transaction(struct binder_proc *proc, struct binder_thread *thread,  
  3. struct binder_transaction_data *tr, int reply)  
  4. {  
  5.     struct binder_transaction *t;  
  6.     struct binder_work *tcomplete;  
  7.     size_t *offp, *off_end;  
  8.     struct binder_proc *target_proc;  
  9.     struct binder_thread *target_thread = NULL;  
  10.     struct binder_node *target_node = NULL;  
  11.     struct list_head *target_list;  
  12.     wait_queue_head_t *target_wait;  
  13.     struct binder_transaction *in_reply_to = NULL;  
  14.     struct binder_transaction_log_entry *e;  
  15.     uint32_t return_error;  
  16.  
  17.         ......  
  18.  
  19.     if (reply) {  
  20.          ......  
  21.     } else {  
  22.         if (tr->target.handle) {  
  23.             ......  
  24.         } else {  
  25.             target_node = binder_context_mgr_node;  
  26.             if (target_node == NULL) {  
  27.                 return_error = BR_DEAD_REPLY;  
  28.                 goto err_no_context_mgr_node;  
  29.             }  
  30.         }  
  31.         ......  
  32.         target_proc = target_node->proc;  
  33.         if (target_proc == NULL) {  
  34.             return_error = BR_DEAD_REPLY;  
  35.             goto err_dead_binder;  
  36.         }  
  37.         ......  
  38.     }  
  39.     if (target_thread) {  
  40.         ......  
  41.     } else {  
  42.         target_list = &target_proc->todo;  
  43.         target_wait = &target_proc->wait;  
  44.     }  
  45.       
  46.     ......  
  47.  
  48.     /* TODO: reuse incoming transaction for reply */  
  49.     t = kzalloc(sizeof(*t), GFP_KERNEL);  
  50.     if (t == NULL) {  
  51.         return_error = BR_FAILED_REPLY;  
  52.         goto err_alloc_t_failed;  
  53.     }  
  54.     ......  
  55.  
  56.     tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);  
  57.     if (tcomplete == NULL) {  
  58.         return_error = BR_FAILED_REPLY;  
  59.         goto err_alloc_tcomplete_failed;  
  60.     }  
  61.       
  62.     ......  
  63.  
  64.     if (!reply && !(tr->flags & TF_ONE_WAY))  
  65.         t->from = thread;  
  66.     else 
  67.         t->from = NULL;  
  68.     t->sender_euid = proc->tsk->cred->euid;  
  69.     t->to_proc = target_proc;  
  70.     t->to_thread = target_thread;  
  71.     t->code = tr->code;  
  72.     t->flags = tr->flags;  
  73.     t->priority = task_nice(current);  
  74.     t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  75.         tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));  
  76.     if (t->buffer == NULL) {  
  77.         return_error = BR_FAILED_REPLY;  
  78.         goto err_binder_alloc_buf_failed;  
  79.     }  
  80.     t->buffer->allow_user_free = 0;  
  81.     t->buffer->debug_id = t->debug_id;  
  82.     t->buffer->transaction = t;  
  83.     t->buffer->target_node = target_node;  
  84.     if (target_node)  
  85.         binder_inc_node(target_node, 1, 0, NULL);  
  86.  
  87.     offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  
  88.  
  89.     if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  90.         ......  
  91.         return_error = BR_FAILED_REPLY;  
  92.         goto err_copy_data_failed;  
  93.     }  
  94.     if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  95.         ......  
  96.         return_error = BR_FAILED_REPLY;  
  97.         goto err_copy_data_failed;  
  98.     }  
  99.     ......  
  100.  
  101.     off_end = (void *)offp + tr->offsets_size;  
  102.     for (; offp < off_end; offp++) {  
  103.         struct flat_binder_object *fp;  
  104.         ......  
  105.         fp = (struct flat_binder_object *)(t->buffer->data + *offp);  
  106.         switch (fp->type) {  
  107.         case BINDER_TYPE_BINDER:  
  108.         case BINDER_TYPE_WEAK_BINDER: {  
  109.             struct binder_ref *ref;  
  110.             struct binder_node *node = binder_get_node(proc, fp->binder);  
  111.             if (node == NULL) {  
  112.                 node = binder_new_node(proc, fp->binder, fp->cookie);  
  113.                 if (node == NULL) {  
  114.                     return_error = BR_FAILED_REPLY;  
  115.                     goto err_binder_new_node_failed;  
  116.                 }  
  117.                 node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  
  118.                 node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  
  119.             }  
  120.             if (fp->cookie != node->cookie) {  
  121.                 ......  
  122.                 goto err_binder_get_ref_for_node_failed;  
  123.             }  
  124.             ref = binder_get_ref_for_node(target_proc, node);  
  125.             if (ref == NULL) {  
  126.                 return_error = BR_FAILED_REPLY;  
  127.                 goto err_binder_get_ref_for_node_failed;  
  128.             }  
  129.             if (fp->type == BINDER_TYPE_BINDER)  
  130.                 fp->type = BINDER_TYPE_HANDLE;  
  131.             else 
  132.                 fp->type = BINDER_TYPE_WEAK_HANDLE;  
  133.             fp->handle = ref->desc;  
  134.             binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);  
  135.             ......  
  136.                                 
  137.         } break;  
  138.         ......  
  139.         }  
  140.     }  
  141.  
  142.     if (reply) {  
  143.         ......  
  144.     } else if (!(t->flags & TF_ONE_WAY)) {  
  145.         BUG_ON(t->buffer->async_transaction != 0);  
  146.         t->need_reply = 1;  
  147.         t->from_parent = thread->transaction_stack;  
  148.         thread->transaction_stack = t;  
  149.     } else {  
  150.         ......  
  151.     }  
  152.     t->work.type = BINDER_WORK_TRANSACTION;  
  153.     list_add_tail(&t->work.entry, target_list);  
  154.     tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;  
  155.     list_add_tail(&tcomplete->entry, &thread->todo);  
  156.     if (target_wait)  
  157.         wake_up_interruptible(target_wait);  
  158.     return;  
  159.     ......  

   注意,这里传进来的参数reply为0,tr->target.handle也为0。因此,target_proc、target_thread、target_node、target_list和target_wait的值分别为:

 

 
 
  1. target_node = binder_context_mgr_node;  
  2. target_proc = target_node->proc;  
  3. target_list = &target_proc->todo;  
  4. target_wait = &target_proc->wait;  

接着,分配了一个待处理事务t和一个待完成工作项tcomplete,并执行初始化工作:
 

 
 
  1. /* TODO: reuse incoming transaction for reply */  
  2. t = kzalloc(sizeof(*t), GFP_KERNEL);  
  3. if (t == NULL) {  
  4.     return_error = BR_FAILED_REPLY;  
  5.     goto err_alloc_t_failed;  
  6. }  
  7. ......  
  8.  
  9. tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);  
  10. if (tcomplete == NULL) {  
  11.     return_error = BR_FAILED_REPLY;  
  12.     goto err_alloc_tcomplete_failed;  
  13. }  
  14.  
  15. ......  
  16.  
  17. if (!reply && !(tr->flags & TF_ONE_WAY))  
  18.     t->from = thread;  
  19. else 
  20.     t->from = NULL;  
  21. t->sender_euid = proc->tsk->cred->euid;  
  22. t->to_proc = target_proc;  
  23. t->to_thread = target_thread;  
  24. t->code = tr->code;  
  25. t->flags = tr->flags;  
  26. t->priority = task_nice(current);  
  27. t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  28.     tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));  
  29. if (t->buffer == NULL) {  
  30.     return_error = BR_FAILED_REPLY;  
  31.     goto err_binder_alloc_buf_failed;  
  32. }  
  33. t->buffer->allow_user_free = 0;  
  34. t->buffer->debug_id = t->debug_id;  
  35. t->buffer->transaction = t;  
  36. t->buffer->target_node = target_node;  
  37. if (target_node)  
  38.     binder_inc_node(target_node, 1, 0, NULL);  
  39.  
  40. offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  
  41.  
  42. if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  43.     ......  
  44.     return_error = BR_FAILED_REPLY;  
  45.     goto err_copy_data_failed;  
  46. }  
  47. if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  48.     ......  
  49.     return_error = BR_FAILED_REPLY;  
  50.     goto err_copy_data_failed;  

 注意,这里的事务t是要交给target_proc处理的,在这个场景之下,就是Service Manager了。因此,下面的语句:
 

 
 
  1. t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  2.         tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); 

 就是在Service Manager的进程空间中分配一块内存来保存用户传进入的参数了:
 

 
 
  1. if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  2.     ......  
  3.     return_error = BR_FAILED_REPLY;  
  4.     goto err_copy_data_failed;  
  5. }  
  6. if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  7.     ......  
  8.     return_error = BR_FAILED_REPLY;  
  9.     goto err_copy_data_failed;  

 由于现在target_node要被使用了,增加它的引用计数:

 

 
 
  1. if (target_node)  
  2.         binder_inc_node(target_node, 1, 0, NULL); 

 接下去的for循环,就是用来处理传输数据中的Binder对象了。在我们的场景中,有一个类型为BINDER_TYPE_BINDER的Binder实体MediaPlayerService:

 

 
 
  1.    switch (fp->type) {  
  2.    case BINDER_TYPE_BINDER:  
  3.    case BINDER_TYPE_WEAK_BINDER: {  
  4. struct binder_ref *ref;  
  5. struct binder_node *node = binder_get_node(proc, fp->binder);  
  6. if (node == NULL) {  
  7.     node = binder_new_node(proc, fp->binder, fp->cookie);  
  8.     if (node == NULL) {  
  9.         return_error = BR_FAILED_REPLY;  
  10.         goto err_binder_new_node_failed;  
  11.     }  
  12.     node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  
  13.     node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  
  14. }  
  15. if (fp->cookie != node->cookie) {  
  16.     ......  
  17.     goto err_binder_get_ref_for_node_failed;  
  18. }  
  19. ref = binder_get_ref_for_node(target_proc, node);  
  20. if (ref == NULL) {  
  21.     return_error = BR_FAILED_REPLY;  
  22.     goto err_binder_get_ref_for_node_failed;  
  23. }  
  24. if (fp->type == BINDER_TYPE_BINDER)  
  25.     fp->type = BINDER_TYPE_HANDLE;  
  26. else 
  27.     fp->type = BINDER_TYPE_WEAK_HANDLE;  
  28. fp->handle = ref->desc;  
  29. binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);  
  30. ......  
  31.                             
  32. } break; 

由于是第一次在Binder驱动程序中传输这个MediaPlayerService,调用binder_get_node函数查询这个Binder实体时,会返回空,于是binder_new_node在proc中新建一个,下次就可以直接使用了。
 

        现在,由于要把这个Binder实体MediaPlayerService交给target_proc,也就是Service Manager来管理,也就是说Service Manager要引用这个MediaPlayerService了,于是通过binder_get_ref_for_node为MediaPlayerService创建一个引用,并且通过binder_inc_ref来增加这个引用计数,防止这个引用还在使用过程当中就被销毁。注意,到了这里的时候,t->buffer中的flat_binder_obj的type已经改为BINDER_TYPE_HANDLE,handle已经改为ref->desc,跟原来不一样了,因为这个flat_binder_obj是最终是要传给Service Manager的,而Service Manager只能够通过句柄值来引用这个Binder实体。

        最后,把待处理事务加入到target_list列表中去:

 

 
 
  1. list_add_tail(&t->work.entry, target_list); 

并且把待完成工作项加入到本线程的todo等待执行列表中去:

 

 
 
  1. list_add_tail(&tcomplete->entry, &thread->todo); 

 现在目标进程有事情可做了,于是唤醒它:

 

 
 
  1. if (target_wait)  
  2.     wake_up_interruptible(target_wait); 

这里就是要唤醒Service Manager进程了。回忆一下前面浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路这篇文章,此时, Service Manager正在binder_thread_read函数中调用wait_event_interruptible进入休眠状态。

 

       这里我们先忽略一下Service Manager被唤醒之后的场景,继续MedaPlayerService的启动过程,然后再回来。

       回到binder_ioctl函数,bwr.read_size > 0为true,于是进入binder_thread_read函数:

 

 
 
  1. static int 
  2. binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,  
  3.                    void  __user *buffer, int size, signed long *consumed, int non_block)  
  4. {  
  5.     void __user *ptr = buffer + *consumed;  
  6.     void __user *end = buffer + size;  
  7.  
  8.     int ret = 0;  
  9.     int wait_for_proc_work;  
  10.  
  11.     if (*consumed == 0) {  
  12.         if (put_user(BR_NOOP, (uint32_t __user *)ptr))  
  13.             return -EFAULT;  
  14.         ptr += sizeof(uint32_t);  
  15.     }  
  16.  
  17. retry:  
  18.     wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);  
  19.       
  20.     .......  
  21.  
  22.     if (wait_for_proc_work) {  
  23.         .......  
  24.     } else {  
  25.         if (non_block) {  
  26.             if (!binder_has_thread_work(thread))  
  27.                 ret = -EAGAIN;  
  28.         } else 
  29.             ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));  
  30.     }  
  31.       
  32.     ......  
  33.  
  34.     while (1) {  
  35.         uint32_t cmd;  
  36.         struct binder_transaction_data tr;  
  37.         struct binder_work *w;  
  38.         struct binder_transaction *t = NULL;  
  39.  
  40.         if (!list_empty(&thread->todo))  
  41.             w = list_first_entry(&thread->todo, struct binder_work, entry);  
  42.         else if (!list_empty(&proc->todo) && wait_for_proc_work)  
  43.             w = list_first_entry(&proc->todo, struct binder_work, entry);  
  44.         else {  
  45.             if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */  
  46.                 goto retry;  
  47.             break;  
  48.         }  
  49.  
  50.         if (end - ptr < sizeof(tr) + 4)  
  51.             break;  
  52.  
  53.         switch (w->type) {  
  54.         ......  
  55.         case BINDER_WORK_TRANSACTION_COMPLETE: {  
  56.             cmd = BR_TRANSACTION_COMPLETE;  
  57.             if (put_user(cmd, (uint32_t __user *)ptr))  
  58.                 return -EFAULT;  
  59.             ptr += sizeof(uint32_t);  
  60.  
  61.             binder_stat_br(proc, thread, cmd);  
  62.             if (binder_debug_mask & BINDER_DEBUG_TRANSACTION_COMPLETE)  
  63.                 printk(KERN_INFO "binder: %d:%d BR_TRANSACTION_COMPLETE\n",  
  64.                 proc->pid, thread->pid);  
  65.  
  66.             list_del(&w->entry);  
  67.             kfree(w);  
  68.             binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++;  
  69.                                                } break;  
  70.         ......  
  71.         }  
  72.  
  73.         if (!t)  
  74.             continue;  
  75.  
  76.         ......  
  77.     }  
  78.  
  79. done:  
  80.     ......  
  81.     return 0;  

 这里,thread->transaction_stack和thread->todo均不为空,于是wait_for_proc_work为false,由于binder_has_thread_work的时候,返回true,这里因为thread->todo不为空,因此,线程虽然调用了wait_event_interruptible,但是不会睡眠,于是继续往下执行。

        由于thread->todo不为空,执行下列语句:

 

 
 
  1. if (!list_empty(&thread->todo))  
  2.      w = list_first_entry(&thread->todo, struct binder_work, entry); 

 

        w->type为BINDER_WORK_TRANSACTION_COMPLETE,这是在上面的binder_transaction函数设置的,于是执行:

 

 
 
  1.    switch (w->type) {  
  2.    ......  
  3.    case BINDER_WORK_TRANSACTION_COMPLETE: {  
  4. cmd = BR_TRANSACTION_COMPLETE;  
  5. if (put_user(cmd, (uint32_t __user *)ptr))  
  6.     return -EFAULT;  
  7. ptr += sizeof(uint32_t);  
  8.  
  9.        ......  
  10. list_del(&w->entry);  
  11. kfree(w);  
  12.           
  13. } break;  
  14. ......  
  15.    } 

这里就将w从thread->todo删除了。由于这里t为空,重新执行while循环,这时由于已经没有事情可做了,最后就返回到binder_ioctl函数中。注间,这里一共往用户传进来的缓冲区buffer写入了两个整数,分别是BR_NOOP和BR_TRANSACTION_COMPLETE。

 

        binder_ioctl函数返回到用户空间之前,把数据消耗情况拷贝回用户空间中:

 

 
 
  1. if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {  
  2.     ret = -EFAULT;  
  3.     goto err;  

最后返回到IPCThreadState::talkWithDriver函数中,执行下面语句:

 

 
 
  1.     if (err >= NO_ERROR) {  
  2.         if (bwr.write_consumed > 0) {  
  3.             if (bwr.write_consumed < (ssize_t)mOut.dataSize())  
  4.                 mOut.remove(0, bwr.write_consumed);  
  5.             else 
  6.                 mOut.setDataSize(0);  
  7.         }  
  8.         if (bwr.read_consumed > 0) {  
  9. <PRE class=cpp name="code">            mIn.setDataSize(bwr.read_consumed);  
  10.             mIn.setDataPosition(0);</PRE>        }        ......        return NO_ERROR;    } 

 首先是把mOut的数据清空:

 

 
 
  1. mOut.setDataSize(0); 

    然后设置已经读取的内容的大小:

 

 
 
  1. mIn.setDataSize(bwr.read_consumed);  
  2. mIn.setDataPosition(0); 

然后返回到IPCThreadState::waitForResponse函数中。在IPCThreadState::waitForResponse函数,先是从mIn读出一个整数,这个便是BR_NOOP了,这是一个空操作,什么也不做。然后继续进入IPCThreadState::talkWithDriver函数中。
        这时候,下面语句执行后:

 

 
 
  1. const bool needRead = mIn.dataPosition() >= mIn.dataSize(); 

 needRead为false,因为在mIn中,尚有一个整数BR_TRANSACTION_COMPLETE未读出。

 

       这时候,下面语句执行后:

 

 
 
  1. const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; 

outAvail等于0。因此,最后bwr.write_size和bwr.read_size均为0,IPCThreadState::talkWithDriver函数什么也不做,直接返回到IPCThreadState::waitForResponse函数中。在IPCThreadState::waitForResponse函数,又继续从mIn读出一个整数,这个便是BR_TRANSACTION_COMPLETE:

 

 
 
  1. switch (cmd) {  
  2. case BR_TRANSACTION_COMPLETE:  
  3.        if (!reply && !acquireResult) goto finish;  
  4.        break;  
  5. ......  

reply不为NULL,因此,IPCThreadState::waitForResponse的循环没有结束,继续执行,又进入到IPCThreadState::talkWithDrive中。

 

        这次,needRead就为true了,而outAvail仍为0,所以bwr.read_size不为0,bwr.write_size为0。于是通过:

 

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

 进入到Binder驱动程序中的binder_ioctl函数中。由于bwr.write_size为0,bwr.read_size不为0,这次直接就进入到binder_thread_read函数中。这时候,thread->transaction_stack不等于0,但是thread->todo为空,于是线程就通过:

 

 
 
  1. wait_event_interruptible(thread->wait, binder_has_thread_work(thread)); 

进入睡眠状态,等待Service Manager来唤醒了。

 

        现在,我们可以回到Service Manager被唤醒的过程了。我们接着前面浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路这篇文章的最后,继续描述。此时, Service Manager正在binder_thread_read函数中调用wait_event_interruptible_exclusive进入休眠状态。上面被MediaPlayerService启动后进程唤醒后,继续执行binder_thread_read函数:

 

 
 
  1. static int 
  2. binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,  
  3.                    void  __user *buffer, int size, signed long *consumed, int non_block)  
  4. {  
  5.     void __user *ptr = buffer + *consumed;  
  6.     void __user *end = buffer + size;  
  7.  
  8.     int ret = 0;  
  9.     int wait_for_proc_work;  
  10.  
  11.     if (*consumed == 0) {  
  12.         if (put_user(BR_NOOP, (uint32_t __user *)ptr))  
  13.             return -EFAULT;  
  14.         ptr += sizeof(uint32_t);  
  15.     }  
  16.  
  17. retry:  
  18.     wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);  
  19.  
  20.     ......  
  21.  
  22.     if (wait_for_proc_work) {  
  23.         ......  
  24.         if (non_block) {  
  25.             if (!binder_has_proc_work(proc, thread))  
  26.                 ret = -EAGAIN;  
  27.         } else 
  28.             ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));  
  29.     } else {  
  30.         ......  
  31.     }  
  32.       
  33.     ......  
  34.  
  35.     while (1) {  
  36.         uint32_t cmd;  
  37.         struct binder_transaction_data tr;  
  38.         struct binder_work *w;  
  39.         struct binder_transaction *t = NULL;  
  40.  
  41.         if (!list_empty(&thread->todo))  
  42.             w = list_first_entry(&thread->todo, struct binder_work, entry);  
  43.         else if (!list_empty(&proc->todo) && wait_for_proc_work)  
  44.             w = list_first_entry(&proc->todo, struct binder_work, entry);  
  45.         else {  
  46.             if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */  
  47.                 goto retry;  
  48.             break;  
  49.         }  
  50.  
  51.         if (end - ptr < sizeof(tr) + 4)  
  52.             break;  
  53.  
  54.         switch (w->type) {  
  55.         case BINDER_WORK_TRANSACTION: {  
  56.             t = container_of(w, struct binder_transaction, work);  
  57.                                       } break;  
  58.         ......  
  59.         }  
  60.  
  61.         if (!t)  
  62.             continue;  
  63.  
  64.         BUG_ON(t->buffer == NULL);  
  65.         if (t->buffer->target_node) {  
  66.             struct binder_node *target_node = t->buffer->target_node;  
  67.             tr.target.ptr = target_node->ptr;  
  68.             tr.cookie =  target_node->cookie;  
  69.             ......  
  70.             cmd = BR_TRANSACTION;  
  71.         } else {  
  72.             ......  
  73.         }  
  74.         tr.code = t->code;  
  75.         tr.flags = t->flags;  
  76.         tr.sender_euid = t->sender_euid;  
  77.  
  78.         if (t->from) {  
  79.             struct task_struct *sender = t->from->proc->tsk;  
  80.             tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns);  
  81.         } else {  
  82.             tr.sender_pid = 0;  
  83.         }  
  84.  
  85.         tr.data_size = t->buffer->data_size;  
  86.         tr.offsets_size = t->buffer->offsets_size;  
  87.         tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;  
  88.         tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));  
  89.  
  90.         if (put_user(cmd, (uint32_t __user *)ptr))  
  91.             return -EFAULT;  
  92.         ptr += sizeof(uint32_t);  
  93.         if (copy_to_user(ptr, &tr, sizeof(tr)))  
  94.             return -EFAULT;  
  95.         ptr += sizeof(tr);  
  96.  
  97.         ......  
  98.  
  99.         list_del(&t->work.entry);  
  100.         t->buffer->allow_user_free = 1;  
  101.         if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {  
  102.             t->to_parent = thread->transaction_stack;  
  103.             t->to_thread = thread;  
  104.             thread->transaction_stack = t;  
  105.         } else {  
  106.             t->buffer->transaction = NULL;  
  107.             kfree(t);  
  108.             binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++;  
  109.         }  
  110.         break;  
  111.     }  
  112.  
  113. done:  
  114.  
  115.     ......  
  116.     return 0;  




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/964539,如需转载请自行联系原作者

目录
相关文章
|
16天前
|
运维 JavaScript jenkins
鸿蒙5.0版开发:分析CppCrash(进程崩溃)
在HarmonyOS 5.0中,CppCrash指C/C++运行时崩溃,常见原因包括空指针、数组越界等。系统提供基于posix信号机制的异常检测能力,生成详细日志辅助定位。本文详解CppCrash分析方法,涵盖异常检测、问题定位思路及案例分析。
39 4
|
16天前
|
运维 监控 JavaScript
鸿蒙next版开发:分析JS Crash(进程崩溃)
在HarmonyOS 5.0中,JS Crash指未处理的JavaScript异常导致应用意外退出。本文详细介绍如何分析JS Crash,包括异常捕获、日志分析和典型案例,帮助开发者定位问题、修复错误,提升应用稳定性。通过DevEco Studio收集日志,结合HiChecker工具,有效解决JS Crash问题。
37 4
|
23天前
|
消息中间件 存储 Linux
|
1月前
|
消息中间件 存储 网络协议
操作系统的心脏:深入理解进程间通信(IPC)机制
在现代计算机系统中,操作系统扮演着至关重要的角色,而进程间通信(IPC)作为操作系统的核心功能之一,极大地影响着系统的性能和稳定性。本文将通过浅显易懂的语言,详细探讨进程间通信的基本原理、主要类型及其实际应用,旨在为读者提供一个清晰且全面的理解和认识。 ##
132 1
|
2月前
|
人工智能 Kubernetes 算法
探究操作系统的心脏——进程管理机制
本文深入探讨了操作系统核心组件之一——进程管理机制。进程管理作为操作系统的基础功能,负责协调和控制计算机系统内运行的所有进程,确保系统资源的有效分配与利用。通过详细介绍进程的定义、状态转换、调度算法以及多线程技术等关键概念,本文揭示了进程管理如何支撑起整个操作系统的运行框架,并保障用户任务的顺利执行。同时,文章还讨论了现代操作系统在进程管理方面的创新与挑战,为读者提供了一个全面而深入的理解视角。
48 1
|
2月前
|
消息中间件 Python
深入理解操作系统的进程间通信(IPC)机制
本文将探讨操作系统中的核心概念——进程间通信(IPC),揭示其在系统运作中的重要性及实现方式。通过分析不同类型的IPC手段,如管道、信号、共享内存等,帮助读者更好地理解操作系统的内部工作原理及其在实际应用中的表现。
148 1
|
1月前
|
NoSQL Linux 程序员
进程管理与运行分析
进程管理与运行分析
23 0
|
2月前
|
并行计算 API 调度
探索Python中的并发编程:线程与进程的对比分析
【9月更文挑战第21天】本文深入探讨了Python中并发编程的核心概念,通过直观的代码示例和清晰的逻辑推理,引导读者理解线程与进程在解决并发问题时的不同应用场景。我们将从基础理论出发,逐步过渡到实际案例分析,旨在揭示Python并发模型的内在机制,并比较它们在执行效率、资源占用和适用场景方面的差异。文章不仅适合初学者构建并发编程的基础认识,同时也为有经验的开发者提供深度思考的视角。
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
4月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
176 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)

相关实验场景

更多
下一篇
无影云桌面