开发者社区> 余二五> 正文

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,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
鸿蒙系统下载地址_华为鸿蒙代码全开源(3)
鸿蒙系统下载地址_华为鸿蒙代码全开源(3)
64 0
鸿蒙系统下载地址_华为鸿蒙代码全开源(5)
鸿蒙系统下载地址_华为鸿蒙代码全开源(5)
30 0
Unity与 SO 交互 ☀️| 详细讲解 怎样通过 Android Studio 生成一个.so文件 并简单调用!
📢前言 🎬SO文件生成 🍺通过Android Studio生成.so文件 🏳️‍🌈第一步:下载配置好NDK 🏳️‍🌈第二步:新建一个AS工程,新建一个JniTest.java文件 🏳️‍🌈第三步:选中JniTest.java文件,进行Make Project 🏳️‍🌈第四步:新建一个jni文件夹,生成.h头文件 🏳️‍🌈第五步:新建 一个c/c++source file文件test.c 和 Android.mk、Application.mk文件 🏳️‍🌈第六步:关联下载好的NDK包 🏳️‍🌈第七步:简单在AS端调用一下 💬总结
63 0
(C语言代码分享):车辆信息管理系统源代码来了。
(C语言代码分享):车辆信息管理系统源代码来了。
35 0
鸿蒙系统下载地址_华为鸿蒙代码全开源(4)
鸿蒙系统下载地址_华为鸿蒙代码全开源(4)
42 0
鸿蒙系统下载地址_华为鸿蒙代码全开源(2)
鸿蒙系统下载地址_华为鸿蒙代码全开源(2)
30 0
鸿蒙系统下载地址_华为鸿蒙代码全开源(6)
鸿蒙系统下载地址_华为鸿蒙代码全开源(6)
37 0
【Android 逆向】Android 进程注入工具开发 ( 调试进程中寄存器的作用 | 通过 EIP 寄存器控制程序运行 | EIP 寄存器的存档与恢复 )
【Android 逆向】Android 进程注入工具开发 ( 调试进程中寄存器的作用 | 通过 EIP 寄存器控制程序运行 | EIP 寄存器的存档与恢复 )
26 0
Eclipse如何跳转到Java系统类的源代码
Eclipse如何跳转到Java系统类的源代码
36 0
「免费开源」基于Vue和Quasar的前端SPA项目crudapi零代码开发平台后台管理系统实战之元数据导出导入(十五)
本文主要介绍了元数据表单的导出导入功能,可以用于日常元数据表单备份,也可以分享给其他系统进行导入,以达到复用的目标。后续可以利用元数据导出导入功能配置一些常见的业务表单,比如电商、CRM、教育等领域,然后将这些业务表单导出供用户下载和使用。
51 0
+关注
20381
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载