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

简介:

这个函数的实现很简单,就是把MediaPlayerService这个Binder实体的引用写到一个struct svcinfo结构体中,主要是它的名称和句柄值,然后插入到链接svclist的头部去。这样,Client来向Service Manager查询服务接口时,只要给定服务名称,Service Manger就可以返回相应的句柄值了。

 

        这个函数执行完成后,返回到svcmgr_handler函数,函数的最后,将一个错误码0写到reply变量中去,表示一切正常:

 

 
 
  1. bio_put_uint32(reply, 0); 

svcmgr_handler函数执行完成后,返回到binder_parse函数,执行下面语句:

 

 
 
  1. binder_send_reply(bs, &reply, txn->data, res); 

我们看一下binder_send_reply的实现,从函数名就可以猜到它要做什么了,告诉Binder驱动程序,它完成了Binder驱动程序交给它的任务了。

 

 
 
  1. void binder_send_reply(struct binder_state *bs,  
  2.                        struct binder_io *reply,  
  3.                        void *buffer_to_free,  
  4.                        int status)  
  5. {  
  6.     struct {  
  7.         uint32_t cmd_free;  
  8.         void *buffer;  
  9.         uint32_t cmd_reply;  
  10.         struct binder_txn txn;  
  11.     } __attribute__((packed)) data;  
  12.  
  13.     data.cmd_free = BC_FREE_BUFFER;  
  14.     data.buffer = buffer_to_free;  
  15.     data.cmd_reply = BC_REPLY;  
  16.     data.txn.target = 0;  
  17.     data.txn.cookie = 0;  
  18.     data.txn.code = 0;  
  19.     if (status) {  
  20.         data.txn.flags = TF_STATUS_CODE;  
  21.         data.txn.data_size = sizeof(int);  
  22.         data.txn.offs_size = 0;  
  23.         data.txn.data = &status;  
  24.         data.txn.offs = 0;  
  25.     } else {  
  26.         data.txn.flags = 0;  
  27.         data.txn.data_size = reply->data - reply->data0;  
  28.         data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0);  
  29.         data.txn.data = reply->data0;  
  30.         data.txn.offs = reply->offs0;  
  31.     }  
  32.     binder_write(bs, &data, sizeof(data));  

  从这里可以看出,binder_send_reply告诉Binder驱动程序执行BC_FREE_BUFFER和BC_REPLY命令,前者释放之前在binder_transaction分配的空间,地址为buffer_to_free,buffer_to_free这个地址是Binder驱动程序把自己在内核空间用的地址转换成用户空间地址再传给Service Manager的,所以Binder驱动程序拿到这个地址后,知道怎么样释放这个空间;后者告诉MediaPlayerService,它的addService操作已经完成了,错误码是0,保存在data.txn.data中。
 

 

       再来看binder_write函数:

 

 
 
  1. int binder_write(struct binder_state *bs, void *data, unsigned len)  
  2. {  
  3.     struct binder_write_read bwr;  
  4.     int res;  
  5.     bwr.write_size = len;  
  6.     bwr.write_consumed = 0;  
  7.     bwr.write_buffer = (unsigned) data;  
  8.     bwr.read_size = 0;  
  9.     bwr.read_consumed = 0;  
  10.     bwr.read_buffer = 0;  
  11.     res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  
  12.     if (res < 0) {  
  13.         fprintf(stderr,"binder_write: ioctl failed (%s)\n",  
  14.                 strerror(errno));  
  15.     }  
  16.     return res;  

这里可以看出,只有写操作,没有读操作,即read_size为0。

 

       这里又是一个ioctl的BINDER_WRITE_READ操作。直入到驱动程序的binder_ioctl函数后,执行BINDER_WRITE_READ命令,这里就不累述了。

       最后,从binder_ioctl执行到binder_thread_write函数,我们首先看第一个命令BC_FREE_BUFFER:

 

 
 
  1. int 
  2. binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,  
  3.                     void __user *buffer, int size, signed long *consumed)  
  4. {  
  5.     uint32_t cmd;  
  6.     void __user *ptr = buffer + *consumed;  
  7.     void __user *end = buffer + size;  
  8.  
  9.     while (ptr < end && thread->return_error == BR_OK) {  
  10.         if (get_user(cmd, (uint32_t __user *)ptr))  
  11.             return -EFAULT;  
  12.         ptr += sizeof(uint32_t);  
  13.         if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {  
  14.             binder_stats.bc[_IOC_NR(cmd)]++;  
  15.             proc->stats.bc[_IOC_NR(cmd)]++;  
  16.             thread->stats.bc[_IOC_NR(cmd)]++;  
  17.         }  
  18.         switch (cmd) {  
  19.         ......  
  20.         case BC_FREE_BUFFER: {  
  21.             void __user *data_ptr;  
  22.             struct binder_buffer *buffer;  
  23.  
  24.             if (get_user(data_ptr, (void * __user *)ptr))  
  25.                 return -EFAULT;  
  26.             ptr += sizeof(void *);  
  27.  
  28.             buffer = binder_buffer_lookup(proc, data_ptr);  
  29.             if (buffer == NULL) {  
  30.                 binder_user_error("binder: %d:%d " 
  31.                     "BC_FREE_BUFFER u%p no match\n",  
  32.                     proc->pid, thread->pid, data_ptr);  
  33.                 break;  
  34.             }  
  35.             if (!buffer->allow_user_free) {  
  36.                 binder_user_error("binder: %d:%d " 
  37.                     "BC_FREE_BUFFER u%p matched " 
  38.                     "unreturned buffer\n",  
  39.                     proc->pid, thread->pid, data_ptr);  
  40.                 break;  
  41.             }  
  42.             if (binder_debug_mask & BINDER_DEBUG_FREE_BUFFER)  
  43.                 printk(KERN_INFO "binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",  
  44.                 proc->pid, thread->pid, data_ptr, buffer->debug_id,  
  45.                 buffer->transaction ? "active" : "finished");  
  46.  
  47.             if (buffer->transaction) {  
  48.                 buffer->transaction->buffer = NULL;  
  49.                 buffer->transaction = NULL;  
  50.             }  
  51.             if (buffer->async_transaction && buffer->target_node) {  
  52.                 BUG_ON(!buffer->target_node->has_async_transaction);  
  53.                 if (list_empty(&buffer->target_node->async_todo))  
  54.                     buffer->target_node->has_async_transaction = 0;  
  55.                 else 
  56.                     list_move_tail(buffer->target_node->async_todo.next, &thread->todo);  
  57.             }  
  58.             binder_transaction_buffer_release(proc, buffer, NULL);  
  59.             binder_free_buf(proc, buffer);  
  60.             break;  
  61.                              }  
  62.  
  63.         ......  
  64.         *consumed = ptr - buffer;  
  65.     }  
  66.     return 0;  

 首先通过看这个语句:

 

 
 
  1. get_user(data_ptr, (void * __user *)ptr) 

 这个是获得要删除的Buffer的用户空间地址,接着通过下面这个语句来找到这个地址对应的struct binder_buffer信息:

 

 
 
  1. buffer = binder_buffer_lookup(proc, data_ptr); 

因为这个空间是前面在binder_transaction里面分配的,所以这里一定能找到。

 

       最后,就可以释放这块内存了:

 

 
 
  1. binder_transaction_buffer_release(proc, buffer, NULL);  
  2. binder_free_buf(proc, buffer); 

 再来看另外一个命令BC_REPLY:

 

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

又再次进入到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.         in_reply_to = thread->transaction_stack;  
  21.         if (in_reply_to == NULL) {  
  22.             ......  
  23.             return_error = BR_FAILED_REPLY;  
  24.             goto err_empty_call_stack;  
  25.         }  
  26.         binder_set_nice(in_reply_to->saved_priority);  
  27.         if (in_reply_to->to_thread != thread) {  
  28.             .......  
  29.             goto err_bad_call_stack;  
  30.         }  
  31.         thread->transaction_stack = in_reply_to->to_parent;  
  32.         target_thread = in_reply_to->from;  
  33.         if (target_thread == NULL) {  
  34.             return_error = BR_DEAD_REPLY;  
  35.             goto err_dead_binder;  
  36.         }  
  37.         if (target_thread->transaction_stack != in_reply_to) {  
  38.             ......  
  39.             return_error = BR_FAILED_REPLY;  
  40.             in_reply_to = NULL;  
  41.             target_thread = NULL;  
  42.             goto err_dead_binder;  
  43.         }  
  44.         target_proc = target_thread->proc;  
  45.     } else {  
  46.         ......  
  47.     }  
  48.     if (target_thread) {  
  49.         e->to_thread = target_thread->pid;  
  50.         target_list = &target_thread->todo;  
  51.         target_wait = &target_thread->wait;  
  52.     } else {  
  53.         ......  
  54.     }  
  55.  
  56.  
  57.     /* TODO: reuse incoming transaction for reply */  
  58.     t = kzalloc(sizeof(*t), GFP_KERNEL);  
  59.     if (t == NULL) {  
  60.         return_error = BR_FAILED_REPLY;  
  61.         goto err_alloc_t_failed;  
  62.     }  
  63.       
  64.  
  65.     tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);  
  66.     if (tcomplete == NULL) {  
  67.         return_error = BR_FAILED_REPLY;  
  68.         goto err_alloc_tcomplete_failed;  
  69.     }  
  70.  
  71.     if (!reply && !(tr->flags & TF_ONE_WAY))  
  72.         t->from = thread;  
  73.     else 
  74.         t->from = NULL;  
  75.     t->sender_euid = proc->tsk->cred->euid;  
  76.     t->to_proc = target_proc;  
  77.     t->to_thread = target_thread;  
  78.     t->code = tr->code;  
  79.     t->flags = tr->flags;  
  80.     t->priority = task_nice(current);  
  81.     t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  82.         tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));  
  83.     if (t->buffer == NULL) {  
  84.         return_error = BR_FAILED_REPLY;  
  85.         goto err_binder_alloc_buf_failed;  
  86.     }  
  87.     t->buffer->allow_user_free = 0;  
  88.     t->buffer->debug_id = t->debug_id;  
  89.     t->buffer->transaction = t;  
  90.     t->buffer->target_node = target_node;  
  91.     if (target_node)  
  92.         binder_inc_node(target_node, 1, 0, NULL);  
  93.  
  94.     offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  
  95.  
  96.     if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  97.         binder_user_error("binder: %d:%d got transaction with invalid " 
  98.             "data ptr\n", proc->pid, thread->pid);  
  99.         return_error = BR_FAILED_REPLY;  
  100.         goto err_copy_data_failed;  
  101.     }  
  102.     if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  103.         binder_user_error("binder: %d:%d got transaction with invalid " 
  104.             "offsets ptr\n", proc->pid, thread->pid);  
  105.         return_error = BR_FAILED_REPLY;  
  106.         goto err_copy_data_failed;  
  107.     }  
  108.       
  109.     ......  
  110.  
  111.     if (reply) {  
  112.         BUG_ON(t->buffer->async_transaction != 0);  
  113.         binder_pop_transaction(target_thread, in_reply_to);  
  114.     } else if (!(t->flags & TF_ONE_WAY)) {  
  115.         ......  
  116.     } else {  
  117.         ......  
  118.     }  
  119.     t->work.type = BINDER_WORK_TRANSACTION;  
  120.     list_add_tail(&t->work.entry, target_list);  
  121.     tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;  
  122.     list_add_tail(&tcomplete->entry, &thread->todo);  
  123.     if (target_wait)  
  124.         wake_up_interruptible(target_wait);  
  125.     return;  
  126.     ......  

注意,这里的reply为1,我们忽略掉其它无关代码。

 

       前面Service Manager正在binder_thread_read函数中被MediaPlayerService启动后进程唤醒后,在最后会把当前处理完的事务放在thread->transaction_stack中:

 

 
 
  1. if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {  
  2.     t->to_parent = thread->transaction_stack;  
  3.     t->to_thread = thread;  
  4.     thread->transaction_stack = t;  
  5. }  

   所以,这里,首先是把它这个binder_transaction取回来,并且放在本地变量in_reply_to中:

 

 
 
  1. in_reply_to = thread->transaction_stack; 

    接着就可以通过in_reply_to得到最终发出这个事务请求的线程和进程:

 

 
 
  1. target_thread = in_reply_to->from;  
  2. target_proc = target_thread->proc; 

然后得到target_list和target_wait:

 

 
 
  1. target_list = &target_thread->todo;  
  2. target_wait = &target_thread->wait; 

下面这一段代码:

 

 
 
  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. if (!reply && !(tr->flags & TF_ONE_WAY))  
  16.     t->from = thread;  
  17. else 
  18.     t->from = NULL;  
  19. t->sender_euid = proc->tsk->cred->euid;  
  20. t->to_proc = target_proc;  
  21. t->to_thread = target_thread;  
  22. t->code = tr->code;  
  23. t->flags = tr->flags;  
  24. t->priority = task_nice(current);  
  25. t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  26.     tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));  
  27. if (t->buffer == NULL) {  
  28.     return_error = BR_FAILED_REPLY;  
  29.     goto err_binder_alloc_buf_failed;  
  30. }  
  31. t->buffer->allow_user_free = 0;  
  32. t->buffer->debug_id = t->debug_id;  
  33. t->buffer->transaction = t;  
  34. t->buffer->target_node = target_node;  
  35. if (target_node)  
  36.     binder_inc_node(target_node, 1, 0, NULL);  
  37.  
  38. offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  
  39.  
  40. if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  41.     binder_user_error("binder: %d:%d got transaction with invalid " 
  42.         "data ptr\n", proc->pid, thread->pid);  
  43.     return_error = BR_FAILED_REPLY;  
  44.     goto err_copy_data_failed;  
  45. }  
  46. if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  47.     binder_user_error("binder: %d:%d got transaction with invalid " 
  48.         "offsets ptr\n", proc->pid, thread->pid);  
  49.     return_error = BR_FAILED_REPLY;  
  50.     goto err_copy_data_failed;  

我们在前面已经分析过了,这里不再重复。但是有一点要注意的是,这里target_node为NULL,因此,t->buffer->target_node也为NULL。

 

          函数本来有一个for循环,用来处理数据中的Binder对象,这里由于没有Binder对象,所以就略过了。到了下面这句代码:

 

 
 
  1. binder_pop_transaction(target_thread, in_reply_to); 

 我们看看做了什么事情

 

 
 
  1. static void  
  2. binder_pop_transaction(  
  3.     struct binder_thread *target_thread, struct binder_transaction *t)  
  4. {  
  5.     if (target_thread) {  
  6.         BUG_ON(target_thread->transaction_stack != t);  
  7.         BUG_ON(target_thread->transaction_stack->from != target_thread);  
  8.         target_thread->transaction_stack =  
  9.             target_thread->transaction_stack->from_parent;  
  10.         t->from = NULL;  
  11.     }  
  12.     t->need_reply = 0;  
  13.     if (t->buffer)  
  14.         t->buffer->transaction = NULL;  
  15.     kfree(t);  
  16.     binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++;  

 由于到了这里,已经不需要in_reply_to这个transaction了,就把它删掉。

 

        回到binder_transaction函数:

 

 
 
  1. t->work.type = BINDER_WORK_TRANSACTION;  
  2. list_add_tail(&t->work.entry, target_list);  
  3. tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;  
  4. list_add_tail(&tcomplete->entry, &thread->todo); 

  和前面一样,分别把t和tcomplete分别放在target_list和thread->todo队列中,这里的target_list指的就是最初调用IServiceManager::addService的MediaPlayerService的Server主线程的的thread->todo队列了,而thread->todo指的是Service Manager中用来回复IServiceManager::addService请求的线程。

 

        最后,唤醒等待在target_wait队列上的线程了,就是最初调用IServiceManager::addService的MediaPlayerService的Server主线程了,它最后在binder_thread_read函数中睡眠在thread->wait上,就是这里的target_wait了:

 

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

 这样,Service Manger回复调用IServiceManager::addService请求就算完成了,重新回到frameworks/base/cmds/servicemanager/binder.c文件中的binder_loop函数等待下一个Client请求的到来。事实上,Service Manger回到binder_loop函数再次执行ioctl函数时候,又会再次进入到binder_thread_read函数。这时个会发现thread->todo不为空,这是因为刚才我们调用了:

 

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

 把一个工作项tcompelete放在了在thread->todo中,这个tcompelete的type为BINDER_WORK_TRANSACTION_COMPLETE,因此,Binder驱动程序会执行下面操作:

 

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

binder_loop函数执行完这个ioctl调用后,才会在下一次调用ioctl进入到Binder驱动程序进入休眠状态,等待下一次Client的请求。

 

        上面讲到调用IServiceManager::addService的MediaPlayerService的Server主线程被唤醒了,于是,重新执行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.         ......  
  51.  
  52.         switch (w->type) {  
  53.         case BINDER_WORK_TRANSACTION: {  
  54.             t = container_of(w, struct binder_transaction, work);  
  55.                                       } break;  
  56.         ......  
  57.         }  
  58.  
  59.         if (!t)  
  60.             continue;  
  61.  
  62.         BUG_ON(t->buffer == NULL);  
  63.         if (t->buffer->target_node) {  
  64.             ......  
  65.         } else {  
  66.             tr.target.ptr = NULL;  
  67.             tr.cookie = NULL;  
  68.             cmd = BR_REPLY;  
  69.         }  
  70.         tr.code = t->code;  
  71.         tr.flags = t->flags;  
  72.         tr.sender_euid = t->sender_euid;  
  73.  
  74.         if (t->from) {  
  75.             ......  
  76.         } else {  
  77.             tr.sender_pid = 0;  
  78.         }  
  79.  
  80.         tr.data_size = t->buffer->data_size;  
  81.         tr.offsets_size = t->buffer->offsets_size;  
  82.         tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;  
  83.         tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));  
  84.  
  85.         if (put_user(cmd, (uint32_t __user *)ptr))  
  86.             return -EFAULT;  
  87.         ptr += sizeof(uint32_t);  
  88.         if (copy_to_user(ptr, &tr, sizeof(tr)))  
  89.             return -EFAULT;  
  90.         ptr += sizeof(tr);  
  91.  
  92.         ......  
  93.  
  94.         list_del(&t->work.entry);  
  95.         t->buffer->allow_user_free = 1;  
  96.         if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {  
  97.             ......  
  98.         } else {  
  99.             t->buffer->transaction = NULL;  
  100.             kfree(t);  
  101.             binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++;  
  102.         }  
  103.         break;  
  104.     }  
  105.  
  106. done:  
  107.     ......  
  108.     return 0;  

在while循环中,从thread->todo得到w,w->type为BINDER_WORK_TRANSACTION,于是,得到t。从上面可以知道,Service Manager反回了一个0回来,写在t->buffer->data里面,现在把t->buffer->data加上proc->user_buffer_offset,得到用户空间地址,保存在tr.data.ptr.buffer里面,这样用户空间就可以访问这个返回码了。由于cmd不等于BR_TRANSACTION,这时就可以把t删除掉了,因为以后都不需要用了。

 

         执行完这个函数后,就返回到binder_ioctl函数,执行下面语句,把数据返回给用户空间:

 

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

接着返回到用户空间IPCThreadState::talkWithDriver函数,最后返回到IPCThreadState::waitForResponse函数,最终执行到下面语句:

 

 
 
  1. status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)  
  2. {  
  3.     int32_t cmd;  
  4.     int32_t err;  
  5.  
  6.     while (1) {  
  7.         if ((err=talkWithDriver()) < NO_ERROR) break;  
  8.           
  9.         ......  
  10.  
  11.         cmd = mIn.readInt32();  
  12.  
  13.         ......  
  14.  
  15.         switch (cmd) {  
  16.         ......  
  17.         case BR_REPLY:  
  18.             {  
  19.                 binder_transaction_data tr;  
  20.                 err = mIn.read(&tr, sizeof(tr));  
  21.                 LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");  
  22.                 if (err != NO_ERROR) goto finish;  
  23.  
  24.                 if (reply) {  
  25.                     if ((tr.flags & TF_STATUS_CODE) == 0) {  
  26.                         reply->ipcSetDataReference(  
  27.                             reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),  
  28.                             tr.data_size,  
  29.                             reinterpret_cast<const size_t*>(tr.data.ptr.offsets),  
  30.                             tr.offsets_size/sizeof(size_t),  
  31.                             freeBuffer, this);  
  32.                     } else {  
  33.                         ......  
  34.                     }  
  35.                 } else {  
  36.                     ......  
  37.                 }  
  38.             }  
  39.             goto finish;  
  40.  
  41.         ......  
  42.         }  
  43.     }  
  44.  
  45. finish:  
  46.     ......  
  47.     return err;  

   注意,这里的tr.flags等于0,这个是在上面的binder_send_reply函数里设置的。最终把结果保存在reply了:

 

 
 
  1. reply->ipcSetDataReference(  
  2.        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),  
  3.        tr.data_size,  
  4.        reinterpret_cast<const size_t*>(tr.data.ptr.offsets),  
  5.        tr.offsets_size/sizeof(size_t),  
  6.        freeBuffer, this); 

这个函数我们就不看了,有兴趣的读者可以研究一下。

 

       从这里层层返回,最后回到MediaPlayerService::instantiate函数中。

       至此,IServiceManager::addService终于执行完毕了。这个过程非常复杂,但是如果我们能够深刻地理解这一过程,将能很好地理解Binder机制的设计思想和实现过程。这里,对IServiceManager::addService过程中MediaPlayerService、ServiceManager和BinderDriver之间的交互作一个小结:

 

   回到frameworks/base/media/mediaserver/main_mediaserver.cpp文件中的main函数,接下去还要执行下面两个函数:

 

 
 
  1. ProcessState::self()->startThreadPool();  
  2. IPCThreadState::self()->joinThreadPool(); 

 首先看ProcessState::startThreadPool函数的实现:

 

 
 
  1. void ProcessState::startThreadPool()  
  2. {  
  3.     AutoMutex _l(mLock);  
  4.     if (!mThreadPoolStarted) {  
  5.         mThreadPoolStarted = true;  
  6.         spawnPooledThread(true);  
  7.     }  

  这里调用spwanPooledThread:

 

 
 
  1. void ProcessState::spawnPooledThread(bool isMain)  
  2. {  
  3.     if (mThreadPoolStarted) {  
  4.         int32_t s = android_atomic_add(1, &mThreadPoolSeq);  
  5.         char buf[32];  
  6.         sprintf(buf, "Binder Thread #%d", s);  
  7.         LOGV("Spawning new pooled thread, name=%s\n", buf);  
  8.         sp<Thread> t = new PoolThread(isMain);  
  9.         t->run(buf);  
  10.     }  

  这里主要是创建一个线程,PoolThread继续Thread类,Thread类定义在frameworks/base/libs/utils/Threads.cpp文件中,其run函数最终调用子类的threadLoop函数,这里即为PoolThread::threadLoop函数:

 

 
 
  1. virtual bool threadLoop()  
  2. {  
  3.     IPCThreadState::self()->joinThreadPool(mIsMain);  
  4.     return false;  

 这里和frameworks/base/media/mediaserver/main_mediaserver.cpp文件中的main函数一样,最终都是调用了IPCThreadState::joinThreadPool函数,它们的区别是,一个参数是true,一个是默认值false。我们来看一下这个函数的实现:

 

 
 
  1. void IPCThreadState::joinThreadPool(bool isMain)  
  2. {  
  3.     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());  
  4.  
  5.     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);  
  6.  
  7.     ......  
  8.  
  9.     status_t result;  
  10.     do {  
  11.         int32_t cmd;  
  12.  
  13.         .......  
  14.  
  15.         // now get the next command to be processed, waiting if necessary  
  16.         result = talkWithDriver();  
  17.         if (result >= NO_ERROR) {  
  18.             size_t IN = mIn.dataAvail();  
  19.             if (IN < sizeof(int32_t)) continue;  
  20.             cmd = mIn.readInt32();  
  21.             ......  
  22.             }  
  23.  
  24.             result = executeCommand(cmd);  
  25.         }  
  26.  
  27.         ......  
  28.     } while (result != -ECONNREFUSED && result != -EBADF);  
  29.  
  30.     .......  
  31.  
  32.     mOut.writeInt32(BC_EXIT_LOOPER);  
  33.     talkWithDriver(false);  

这个函数最终是在一个无穷循环中,通过调用talkWithDriver函数来和Binder驱动程序进行交互,实际上就是调用talkWithDriver来等待Client的请求,然后再调用executeCommand来处理请求,而在executeCommand函数中,最终会调用BBinder::transact来真正处理Client的请求:

 

 
 
  1. status_t IPCThreadState::executeCommand(int32_t cmd)  
  2. {  
  3.     BBinder* obj;  
  4.     RefBase::weakref_type* refs;  
  5.     status_t result = NO_ERROR;  
  6.  
  7.     switch (cmd) {  
  8.     ......  
  9.  
  10.     case BR_TRANSACTION:  
  11.         {  
  12.             binder_transaction_data tr;  
  13.             result = mIn.read(&tr, sizeof(tr));  
  14.               
  15.             ......  
  16.  
  17.             Parcel reply;  
  18.               
  19.             ......  
  20.  
  21.             if (tr.target.ptr) {  
  22.                 sp<BBinder> b((BBinder*)tr.cookie);  
  23.                 const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);  
  24.                 if (error < NO_ERROR) reply.setError(error);  
  25.  
  26.             } else {  
  27.                 const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);  
  28.                 if (error < NO_ERROR) reply.setError(error);  
  29.             }  
  30.  
  31.             ......  
  32.         }  
  33.         break;  
  34.  
  35.     .......  
  36.     }  
  37.  
  38.     if (result != NO_ERROR) {  
  39.         mLastError = result;  
  40.     }  
  41.  
  42.     return result;  

  接下来再看一下BBinder::transact的实现:

 

 
 
  1. status_t BBinder::transact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.     data.setDataPosition(0);  
  5.  
  6.     status_t err = NO_ERROR;  
  7.     switch (code) {  
  8.         case PING_TRANSACTION:  
  9.             reply->writeInt32(pingBinder());  
  10.             break;  
  11.         default:  
  12.             err = onTransact(code, data, reply, flags);  
  13.             break;  
  14.     }  
  15.  
  16.     if (reply != NULL) {  
  17.         reply->setDataPosition(0);  
  18.     }  
  19.  
  20.     return err;  

最终会调用onTransact函数来处理。在这个场景中,BnMediaPlayerService继承了BBinder类,并且重载了onTransact函数,因此,这里实际上是调用了BnMediaPlayerService::onTransact函数,这个函数定义在frameworks/base/libs/media/libmedia/IMediaPlayerService.cpp文件中:

 

 
 
  1. status_t BnMediaPlayerService::onTransact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.     switch(code) {  
  5.         case CREATE_URL: {  
  6.             ......  
  7.                          } break;  
  8.         case CREATE_FD: {  
  9.             ......  
  10.                         } break;  
  11.         case DECODE_URL: {  
  12.             ......  
  13.                          } break;  
  14.         case DECODE_FD: {  
  15.             ......  
  16.                         } break;  
  17.         case CREATE_MEDIA_RECORDER: {  
  18.             ......  
  19.                                     } break;  
  20.         case CREATE_METADATA_RETRIEVER: {  
  21.             ......  
  22.                                         } break;  
  23.         case GET_OMX: {  
  24.             ......  
  25.                       } break;  
  26.         default:  
  27.             return BBinder::onTransact(code, data, reply, flags);  
  28.     }  

 至此,我们就以MediaPlayerService为例,完整地介绍了Android系统进程间通信Binder机制中的Server启动过程。Server启动起来之后,就会在一个无穷循环中等待Client的请求了。在下一篇文章中,我们将介绍Client如何通过Service Manager远程接口来获得Server远程接口,进而调用Server远程接口来使用Server提供的服务,敬请关注。





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

目录
相关文章
|
1月前
|
消息中间件 Unix Linux
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
48 1
|
3月前
|
缓存 负载均衡 Linux
内核:进程与调度机制(笔记)
内核:进程与调度机制(笔记)
59 0
|
1月前
|
资源调度 算法 Linux
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
66 0
|
6天前
|
算法 Linux 调度
深入理解Linux内核的进程调度机制
【4月更文挑战第17天】在多任务操作系统中,进程调度是核心功能之一,它决定了处理机资源的分配。本文旨在剖析Linux操作系统内核的进程调度机制,详细讨论其调度策略、调度算法及实现原理,并探讨了其对系统性能的影响。通过分析CFS(完全公平调度器)和实时调度策略,揭示了Linux如何在保证响应速度与公平性之间取得平衡。文章还将评估最新的调度技术趋势,如容器化和云计算环境下的调度优化。
|
11天前
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【4月更文挑战第12天】 在多任务操作系统如Linux中,进程调度机制是系统的核心组成部分之一,它决定了处理器资源如何分配给多个竞争的进程。本文深入探讨了Linux内核中的进程调度策略和相关算法,包括其设计哲学、实现原理及对系统性能的影响。通过分析进程调度器的工作原理,我们能够理解操作系统如何平衡效率、公平性和响应性,进而优化系统表现和用户体验。
20 3
|
存储 监控 安全
深度剖析Linux进程的内部机制:一探/proc/pid的奥秘
深度剖析Linux进程的内部机制:一探/proc/pid的奥秘
82 0
|
1月前
|
SQL 网络协议 Windows
破解SQL Server迷局,彻底解决“管道的另一端无任何进程错误233”
破解SQL Server迷局,彻底解决“管道的另一端无任何进程错误233”
|
3月前
|
SQL 定位技术 Android开发
分享119个Android手机应用源代码总有一个是你想要的
分享119个Android手机应用源代码总有一个是你想要的
82 2
|
3月前
|
Android开发
分享88个Android控件源代码总有一个是你想要的
分享88个Android控件源代码总有一个是你想要的
23 0
|
3月前
|
Android开发
分享89个Android控件源代码总有一个是你想要的
分享89个Android控件源代码总有一个是你想要的
73 0