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

目录
相关文章
|
12天前
|
算法 JavaScript Android开发
|
13天前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
3天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
5天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
7天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
5天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!
|
6天前
|
存储 XML JSON
探索安卓开发:从新手到专家的旅程
【10月更文挑战第36天】在这篇文章中,我们将一起踏上一段激动人心的旅程,从零基础开始,逐步深入安卓开发的奥秘。无论你是编程新手,还是希望扩展技能的老手,这里都有适合你的知识宝藏等待发掘。通过实际的代码示例和深入浅出的解释,我们将解锁安卓开发的关键技能,让你能够构建自己的应用程序,甚至贡献于开源社区。准备好了吗?让我们开始吧!
18 2
|
7天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
15天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
14天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
27 5

相关实验场景

更多