Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)

简介:

注意,这里的参数reply = 0,表示这是一个BC_TRANSACTION命令。
        前面我们提到,传给驱动程序的handle值为0,即这里的tr->target.handle = 0,表示请求的目标Binder对象是Service Manager,因此有:


 

 
 
  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; 

     其中binder_context_mgr_node是在Service Manager通知Binder驱动程序它是守护过程时创建的。

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


 

 
 
  1. t->from_parent = thread->transaction_stack;  
  2. thread->transaction_stack = t; 

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

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


 

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

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

 
 
  1. 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函数去了:


 

 
 
  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;  

函数首先是写入一个操作码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函数中,将操作结果写回到用户空间中去:


 

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

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

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


 

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

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


 

 
 
  1. if (bwr.write_consumed > 0) {  
  2.      if (bwr.write_consumed < (ssize_t)mOut.dataSize())  
  3.           mOut.remove(0, bwr.write_consumed);  
  4.      else 
  5.           mOut.setDataSize(0);  

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

 
 
  1. if (bwr.read_consumed > 0) {  
  2.      mIn.setDataSize(bwr.read_consumed);  
  3.      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操作的处理结果。

      这里属于后一种情况,于是再次通过IPCThreadState::talkWithDriver进入到Binder驱动程序的binder_ioctl函数中。不过这一次在binder_ioctl函数中,bwr.write_size等于0,而bwr.read_size大于0,于是再次进入到binder_thread_read函数中。这时候thread->transaction_stack仍然不为NULL,不过thread->todo队列已经为空了,因为前面我们已经处理过thread->todo队列的内容了,于是就通过下面语句:


 

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

    进入休眠状态了,等待Service Manager的唤醒。

      现在,我们终于可以回到Service Manager被唤醒之后的过程了。前面我们说过,Service Manager此时正在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.             t->saved_priority = task_nice(current);  
  70.             if (t->priority < target_node->min_priority &&  
  71.                 !(t->flags & TF_ONE_WAY))  
  72.                 binder_set_nice(t->priority);  
  73.             else if (!(t->flags & TF_ONE_WAY) ||  
  74.                 t->saved_priority > target_node->min_priority)  
  75.                 binder_set_nice(target_node->min_priority);  
  76.             cmd = BR_TRANSACTION;  
  77.         } else {  
  78.             ......  
  79.         }  
  80.         tr.code = t->code;  
  81.         tr.flags = t->flags;  
  82.         tr.sender_euid = t->sender_euid;  
  83.  
  84.         if (t->from) {  
  85.             struct task_struct *sender = t->from->proc->tsk;  
  86.             tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns);  
  87.         } else {  
  88.             ......  
  89.         }  
  90.  
  91.         tr.data_size = t->buffer->data_size;  
  92.         tr.offsets_size = t->buffer->offsets_size;  
  93.         tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;  
  94.         tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));  
  95.  
  96.         if (put_user(cmd, (uint32_t __user *)ptr))  
  97.             return -EFAULT;  
  98.         ptr += sizeof(uint32_t);  
  99.         if (copy_to_user(ptr, &tr, sizeof(tr)))  
  100.             return -EFAULT;  
  101.         ptr += sizeof(tr);  
  102.  
  103.         ......  
  104.  
  105.         list_del(&t->work.entry);  
  106.         t->buffer->allow_user_free = 1;  
  107.         if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {  
  108.             t->to_parent = thread->transaction_stack;  
  109.             t->to_thread = thread;  
  110.             thread->transaction_stack = t;  
  111.         } else {  
  112.             ......  
  113.         }  
  114.         break;  
  115.     }  
  116.  
  117. done:  
  118.  
  119.     *consumed = ptr - buffer;  
  120.     ......  
  121.     return 0;  

这里就是从语句中唤醒了:


 

 
 
  1. ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread)); 

   Service Manager唤醒过来看,继续往下执行,进入到while循环中。首先是从proc->todo中取回待处理事项w。这个事项w的类型是BINDER_WORK_TRANSACTION,这是上面调用binder_transaction的时候设置的,于是通过w得到待处理事务t:


 

 
 
  1. t = container_of(w, struct binder_transaction, work); 

   接下来的内容,就把cmd和t->buffer的内容拷贝到用户传进来的缓冲区去了,这里就是Service Manager从用户空间传进来的缓冲区了:


 

 
 
  1. if (put_user(cmd, (uint32_t __user *)ptr))  
  2.     return -EFAULT;  
  3. ptr += sizeof(uint32_t);  
  4. if (copy_to_user(ptr, &tr, sizeof(tr)))  
  5.     return -EFAULT;  
  6. ptr += sizeof(tr); 

   注意,这里先是把t->buffer的内容拷贝到本地变量tr中,再拷贝到用户空间缓冲区去。关于t->buffer内容的拷贝,请参考Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文,它的一个关键地方是Binder驱动程序和Service Manager守护进程共享了同一个物理内存的内容,拷贝的只是这个物理内存在用户空间的虚拟地址回去:


 

 
 
  1. tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset;  
  2. tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); 

    对于Binder驱动程序这次操作来说,这个事项就算是处理完了,就要从todo队列中删除了:

 
 
  1. list_del(&t->work.entry); 

紧接着,还不放删除这个事务,因为它还要等待Service Manager处理完成后,再进一步处理,因此,放在thread->transaction_stack队列中:


 

 
 
  1. t->to_parent = thread->transaction_stack;  
  2. t->to_thread = thread;  
  3. thread->transaction_stack = t; 

还要注意的一个地方是,上面写入的cmd = BR_TRANSACTION,告诉Service Manager守护进程,它要做什么事情,后面我们会看到相应的分析。

       这样,binder_thread_read函数就处理完了,回到binder_ioctl函数中,同样是操作结果写回到用户空间的缓冲区中去:

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

  最后,就返回到frameworks/base/cmds/servicemanager/binder.c文件中的binder_loop函数去了:


 

 
 
  1. void binder_loop(struct binder_state *bs, binder_handler func)  
  2. {  
  3.     int res;  
  4.     struct binder_write_read bwr;  
  5.     unsigned readbuf[32];  
  6.  
  7.     bwr.write_size = 0;  
  8.     bwr.write_consumed = 0;  
  9.     bwr.write_buffer = 0;  
  10.       
  11.     readbuf[0] = BC_ENTER_LOOPER;  
  12.     binder_write(bs, readbuf, sizeof(unsigned));  
  13.  
  14.     for (;;) {  
  15.         bwr.read_size = sizeof(readbuf);  
  16.         bwr.read_consumed = 0;  
  17.         bwr.read_buffer = (unsigned) readbuf;  
  18.  
  19.         res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  
  20.  
  21.         if (res < 0) {  
  22.             LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));  
  23.             break;  
  24.         }  
  25.  
  26.         res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);  
  27.         if (res == 0) {  
  28.             LOGE("binder_loop: unexpected reply?!\n");  
  29.             break;  
  30.         }  
  31.         if (res < 0) {  
  32.             LOGE("binder_loop: io error %d %s\n", res, strerror(errno));  
  33.             break;  
  34.         }  
  35.     }  

   这里就是从下面的语句:


 

 
 
  1. res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 

     返回来了。接着就进入binder_parse函数处理从Binder驱动程序里面读取出来的数据:


 

 
 
  1. int binder_parse(struct binder_state *bs, struct binder_io *bio,  
  2.                  uint32_t *ptr, uint32_t size, binder_handler func)  
  3. {  
  4.     int r = 1;  
  5.     uint32_t *end = ptr + (size / 4);  
  6.  
  7.     while (ptr < end) {  
  8.         uint32_t cmd = *ptr++;  
  9.         switch(cmd) {  
  10.         ......  
  11.         case BR_TRANSACTION: {  
  12.             struct binder_txn *txn = (void *) ptr;  
  13.             ......  
  14.             if (func) {  
  15.                 unsigned rdata[256/4];  
  16.                 struct binder_io msg;  
  17.                 struct binder_io reply;  
  18.                 int res;  
  19.  
  20.                 bio_init(&reply, rdata, sizeof(rdata), 4);  
  21.                 bio_init_from_txn(&msg, txn);  
  22.                 res = func(bs, txn, &msg, &reply);  
  23.                 binder_send_reply(bs, &reply, txn->data, res);  
  24.             }  
  25.             ptr += sizeof(*txn) / sizeof(uint32_t);  
  26.             break;  
  27.                              }  
  28.         ......  
  29.         default:  
  30.             LOGE("parse: OOPS %d\n", cmd);  
  31.             return -1;  
  32.         }  
  33.     }  
  34.  
  35.     return r;  

前面我们说过,Binder驱动程序写入到用户空间的缓冲区中的cmd为BR_TRANSACTION,因此,这里我们只关注BR_TRANSACTION相关的逻辑。

         这里用到的两个数据结构struct binder_txn和struct binder_io可以参考前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析,这里就不复述了。

         接着往下看,函数调bio_init来初始化reply变量:


 

 
 
  1. void bio_init(struct binder_io *bio, void *data,  
  2.               uint32_t maxdata, uint32_t maxoffs)  
  3. {  
  4.     uint32_t n = maxoffs * sizeof(uint32_t);  
  5.  
  6.     if (n > maxdata) {  
  7.         bio->flags = BIO_F_OVERFLOW;  
  8.         bio->data_avail = 0;  
  9.         bio->offs_avail = 0;  
  10.         return;  
  11.     }  
  12.  
  13.     bio->data = bio->data0 = data + n;  
  14.     bio->offs = bio->offs0 = data;  
  15.     bio->data_avail = maxdata - n;  
  16.     bio->offs_avail = maxoffs;  
  17.     bio->flags = 0;  

   最后,真正进行处理的函数是从参数中传进来的函数指针func,这里就是定义在frameworks/base/cmds/servicemanager/service_manager.c文件中的svcmgr_handler函数:


 

 
 
  1. int svcmgr_handler(struct binder_state *bs,  
  2.                    struct binder_txn *txn,  
  3.                    struct binder_io *msg,  
  4.                    struct binder_io *reply)  
  5. {  
  6.     struct svcinfo *si;  
  7.     uint16_t *s;  
  8.     unsigned len;  
  9.     void *ptr;  
  10.     uint32_t strict_policy;  
  11.  
  12. //    LOGI("target=%p code=%d pid=%d uid=%d\n",  
  13. //         txn->target, txn->code, txn->sender_pid, txn->sender_euid);  
  14.  
  15.     if (txn->target != svcmgr_handle)  
  16.         return -1;  
  17.  
  18.     // Equivalent to Parcel::enforceInterface(), reading the RPC  
  19.     // header with the strict mode policy mask and the interface name.  
  20.     // Note that we ignore the strict_policy and don't propagate it  
  21.     // further (since we do no outbound RPCs anyway).  
  22.     strict_policy = bio_get_uint32(msg);  
  23.     s = bio_get_string16(msg, &len);  
  24.     if ((len != (sizeof(svcmgr_id) / 2)) ||  
  25.         memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {  
  26.         fprintf(stderr,"invalid id %s\n", str8(s));  
  27.         return -1;  
  28.     }  
  29.  
  30.     switch(txn->code) {  
  31.     case SVC_MGR_GET_SERVICE:  
  32.     case SVC_MGR_CHECK_SERVICE:  
  33.         s = bio_get_string16(msg, &len);  
  34.         ptr = do_find_service(bs, s, len);  
  35.         if (!ptr)  
  36.             break;  
  37.         bio_put_ref(reply, ptr);  
  38.         return 0;  
  39.  
  40.     ......  
  41.     }  
  42.     default:  
  43.         LOGE("unknown code %d\n", txn->code);  
  44.         return -1;  
  45.     }  
  46.  
  47.     bio_put_uint32(reply, 0);  
  48.     return 0;  

    这里, Service Manager要处理的code是SVC_MGR_CHECK_SERVICE,这是在前面的BpServiceManager::checkService函数里面设置的。

        回忆一下,在BpServiceManager::checkService时,传给Binder驱动程序的参数为:


 

 
 
  1. writeInt32(IPCThreadState::self()->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);    
  2. writeString16("android.os.IServiceManager");    
  3. writeString16("media.player");   

   这里的语句:


 

 
 
  1. strict_policy = bio_get_uint32(msg);    
  2. s = bio_get_string16(msg, &len);    
  3. s = bio_get_string16(msg, &len);  

     其中,会验证一下传进来的第二个参数,即"android.os.IServiceManager"是否正确,这个是验证RPC头,注释已经说得很清楚了。

       最后,就是调用do_find_service函数查找是存在名称为"media.player"的服务了。回忆一下前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析,MediaPlayerService已经把一个名称为"media.player"的服务注册到Service Manager中,所以这里一定能找到。我们看看do_find_service这个函数:


 

 
 
  1. void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)  
  2. {  
  3.     struct svcinfo *si;  
  4.     si = find_svc(s, len);  
  5.  
  6. //    LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);  
  7.     if (si && si->ptr) {  
  8.         return si->ptr;  
  9.     } else {  
  10.         return 0;  
  11.     }  

  这里又调用了find_svc函数:


 

 
 
  1. struct svcinfo *find_svc(uint16_t *s16, unsigned len)  
  2. {  
  3.     struct svcinfo *si;  
  4.  
  5.     for (si = svclist; si; si = si->next) {  
  6.         if ((len == si->len) &&  
  7.             !memcmp(s16, si->name, len * sizeof(uint16_t))) {  
  8.             return si;  
  9.         }  
  10.     }  
  11.     return 0;  

就是在svclist列表中查找对应名称的svcinfo了。

       然后返回到do_find_service函数中。回忆一下前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析,这里的si->ptr就是指MediaPlayerService这个Binder实体在Service Manager进程中的句柄值了。

       回到svcmgr_handler函数中,调用bio_put_ref函数将这个Binder引用写回到reply参数。我们看看bio_put_ref的实现:


 

 
 
  1. void bio_put_ref(struct binder_io *bio, void *ptr)  
  2. {  
  3.     struct binder_object *obj;  
  4.  
  5.     if (ptr)  
  6.         obj = bio_alloc_obj(bio);  
  7.     else 
  8.         obj = bio_alloc(bio, sizeof(*obj));  
  9.  
  10.     if (!obj)  
  11.         return;  
  12.  
  13.     obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;  
  14.     obj->type = BINDER_TYPE_HANDLE;  
  15.     obj->pointer = ptr;  
  16.     obj->cookie = 0;  

   这里很简单,就是把一个类型为BINDER_TYPE_HANDLE的binder_object写入到reply缓冲区中去。这里的binder_object就是相当于是flat_binder_obj了,具体可以参考Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文。

        再回到svcmgr_handler函数中,最后,还写入一个0值到reply缓冲区中,表示操作结果码:

 
 
  1. bio_put_uint32(reply, 0); 

    最后返回到binder_parse函数中,调用binder_send_reply函数将操作结果反馈给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));  




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

目录
相关文章
|
2月前
|
监控 关系型数据库 MySQL
在CentOS系统中,如何统计哪个进程打开了文件描述符?
利用上述方法,你可以有效地监控和统计CentOS系统中的进程打开的文件描述符数量,以帮助排查错误或优化系统配置。通过组合使用各种工具和命令,可以获得对系统状态和行为的深入了解,进而做出相应的调整和
153 5
|
9月前
|
弹性计算 运维 监控
基于进程热点分析与系统资源优化的智能运维实践
智能服务器管理平台提供直观的可视化界面,助力高效操作系统管理。核心功能包括运维监控、智能助手和扩展插件管理,支持系统健康监控、故障诊断等,确保集群稳定运行。首次使用需激活服务并安装管控组件。平台还提供进程热点追踪、性能观测与优化建议,帮助开发人员快速识别和解决性能瓶颈。定期分析和多维度监控可提前预警潜在问题,保障系统长期稳定运行。
394 17
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
1925 58
|
11月前
|
监控 搜索推荐 开发工具
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
1251 2
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
547 13
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
464 4
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
1176 1
|
9月前
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。
|
9月前
|
Linux Shell
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
727 5
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能

热门文章

最新文章