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

简介:

  注意,这里的status参数为0。从这里可以看出,binder_send_reply告诉Binder驱动程序执行BC_FREE_BUFFER和BC_REPLY命令,前者释放之前在binder_transaction分配的空间,地址为buffer_to_free,buffer_to_free这个地址是Binder驱动程序把自己在内核空间用的地址转换成用户空间地址再传给Service Manager的,所以Binder驱动程序拿到这个地址后,知道怎么样释放这个空间;后者告诉Binder驱动程序,它的SVC_MGR_CHECK_SERVICE操作已经完成了,要查询的服务的句柄值也是保存在data.txn.data,操作结果码是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命令,这个命令的执行在前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析已经介绍过了,这里就不再累述了。

        我们重点关注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;    
  35. }  

   又再次进入到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.         ......  
  27.         thread->transaction_stack = in_reply_to->to_parent;  
  28.         target_thread = in_reply_to->from;  
  29.         ......  
  30.         target_proc = target_thread->proc;  
  31.     } else {  
  32.         ......  
  33.     }  
  34.     if (target_thread) {  
  35.         e->to_thread = target_thread->pid;  
  36.         target_list = &target_thread->todo;  
  37.         target_wait = &target_thread->wait;  
  38.     } else {  
  39.         ......  
  40.     }  
  41.       
  42.  
  43.     /* TODO: reuse incoming transaction for reply */  
  44.     t = kzalloc(sizeof(*t), GFP_KERNEL);  
  45.     if (t == NULL) {  
  46.         return_error = BR_FAILED_REPLY;  
  47.         goto err_alloc_t_failed;  
  48.     }  
  49.     binder_stats.obj_created[BINDER_STAT_TRANSACTION]++;  
  50.  
  51.     tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);  
  52.     if (tcomplete == NULL) {  
  53.         return_error = BR_FAILED_REPLY;  
  54.         goto err_alloc_tcomplete_failed;  
  55.     }  
  56.     ......  
  57.  
  58.     if (!reply && !(tr->flags & TF_ONE_WAY))  
  59.         t->from = thread;  
  60.     else 
  61.         t->from = NULL;  
  62.     t->sender_euid = proc->tsk->cred->euid;  
  63.     t->to_proc = target_proc;  
  64.     t->to_thread = target_thread;  
  65.     t->code = tr->code;  
  66.     t->flags = tr->flags;  
  67.     t->priority = task_nice(current);  
  68.     t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  69.         tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));  
  70.     if (t->buffer == NULL) {  
  71.         return_error = BR_FAILED_REPLY;  
  72.         goto err_binder_alloc_buf_failed;  
  73.     }  
  74.     t->buffer->allow_user_free = 0;  
  75.     t->buffer->debug_id = t->debug_id;  
  76.     t->buffer->transaction = t;  
  77.     t->buffer->target_node = target_node;  
  78.     if (target_node)  
  79.         binder_inc_node(target_node, 1, 0, NULL);  
  80.  
  81.     offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  
  82.  
  83.     if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  84.         binder_user_error("binder: %d:%d got transaction with invalid " 
  85.             "data ptr\n", proc->pid, thread->pid);  
  86.         return_error = BR_FAILED_REPLY;  
  87.         goto err_copy_data_failed;  
  88.     }  
  89.     if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  90.         binder_user_error("binder: %d:%d got transaction with invalid " 
  91.             "offsets ptr\n", proc->pid, thread->pid);  
  92.         return_error = BR_FAILED_REPLY;  
  93.         goto err_copy_data_failed;  
  94.     }  
  95.     ......  
  96.  
  97.     off_end = (void *)offp + tr->offsets_size;  
  98.     for (; offp < off_end; offp++) {  
  99.         struct flat_binder_object *fp;  
  100.         ......  
  101.         fp = (struct flat_binder_object *)(t->buffer->data + *offp);  
  102.         switch (fp->type) {  
  103.         ......  
  104.         case BINDER_TYPE_HANDLE:  
  105.         case BINDER_TYPE_WEAK_HANDLE: {  
  106.             struct binder_ref *ref = binder_get_ref(proc, fp->handle);  
  107.             if (ref == NULL) {  
  108.                 ......  
  109.                 return_error = BR_FAILED_REPLY;  
  110.                 goto err_binder_get_ref_failed;  
  111.             }  
  112.             if (ref->node->proc == target_proc) {  
  113.                 ......  
  114.             } else {  
  115.                 struct binder_ref *new_ref;  
  116.                 new_ref = binder_get_ref_for_node(target_proc, ref->node);  
  117.                 if (new_ref == NULL) {  
  118.                     return_error = BR_FAILED_REPLY;  
  119.                     goto err_binder_get_ref_for_node_failed;  
  120.                 }  
  121.                 fp->handle = new_ref->desc;  
  122.                 binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);  
  123.                 ......  
  124.             }  
  125.         } break;  
  126.  
  127.         ......  
  128.         }  
  129.     }  
  130.  
  131.     if (reply) {  
  132.         BUG_ON(t->buffer->async_transaction != 0);  
  133.         binder_pop_transaction(target_thread, in_reply_to);  
  134.     } else if (!(t->flags & TF_ONE_WAY)) {  
  135.         ......  
  136.     } else {  
  137.         ......  
  138.     }  
  139.  
  140.     t->work.type = BINDER_WORK_TRANSACTION;  
  141.     list_add_tail(&t->work.entry, target_list);  
  142.     tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;  
  143.     list_add_tail(&tcomplete->entry, &thread->todo);  
  144.     if (target_wait)  
  145.         wake_up_interruptible(target_wait);  
  146.     return;  
  147.  
  148.     ......  

   这次进入binder_transaction函数的情形和上面介绍的binder_transaction函数的情形基本一致,只是这里的proc、thread和target_proc、target_thread调换了角色,这里的proc和thread指的是Service Manager进程,而target_proc和target_thread指的是刚才请求SVC_MGR_CHECK_SERVICE的进程。

        那么,这次是如何找到target_proc和target_thread呢。首先,我们注意到,这里的reply等于1,其次,上面我们提到,Binder驱动程序在唤醒Service Manager,告诉它有一个事务t要处理时,事务t虽然从Service Manager的todo队列中删除了,但是仍然保留在transaction_stack中。因此,这里可以从thread->transaction_stack找回这个等待回复的事务t,然后通过它找回target_proc和target_thread:


 

 
 
  1. in_reply_to = thread->transaction_stack;  
  2. target_thread = in_reply_to->from;  
  3. target_list = &target_thread->todo;  
  4. target_wait = &target_thread->wait; 

   再接着往下看,由于Service Manager返回来了一个Binder引用,所以这里要处理一下,就是中间的for循环了。这是一个BINDER_TYPE_HANDLE类型的Binder引用,这是前面设置的。先把t->buffer->data的内容转换为一个struct flat_binder_object对象fp,这里的fp->handle值就是这个Service在Service Manager进程里面的引用值了。接通过调用binder_get_ref函数得到Binder引用对象struct binder_ref类型的对象ref:


 

 
 
  1. struct binder_ref *ref = binder_get_ref(proc, fp->handle); 

   这里一定能找到,因为前面MediaPlayerService执行IServiceManager::addService的时候把自己添加到Service Manager的时候,会在Service Manager进程中创建这个Binder引用,然后把这个Binder引用的句柄值返回给Service Manager用户空间。

       这里面的ref->node->proc不等于target_proc,因为这个Binder实体是属于创建MediaPlayerService的进程的,而不是请求这个服务的远程接口的进程的,因此,这里调用binder_get_ref_for_node函数为这个Binder实体在target_proc创建一个引用:

 
 
  1. struct binder_ref *new_ref;  
  2. new_ref = binder_get_ref_for_node(target_proc, ref->node); 

   然后增加引用计数:


 

 
 
  1. binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); 

  这样,返回数据中的Binder对象就处理完成了。注意,这里会把fp->handle的值改为在target_proc中的引用值:

 

 
 
  1. fp->handle = new_ref->desc

  这里就相当于是把t->buffer->data里面的Binder对象的句柄值改写了。因为这是在另外一个不同的进程里面的Binder引用,所以句柄值当然要用新的了。这个值最终是要拷贝回target_proc进程的用户空间去的。


      再往下看:

 
 
  1. if (reply) {  
  2.      BUG_ON(t->buffer->async_transaction != 0);  
  3.      binder_pop_transaction(target_thread, in_reply_to);  
  4. else if (!(t->flags & TF_ONE_WAY)) {  
  5.      ......  
  6. else {  
  7.      ......  


  这里reply等于1,执行binder_pop_transaction函数把当前事务in_reply_to从target_thread->transaction_stack队列中删掉,这是上次调用binder_transaction函数的时候设置的,现在不需要了,所以把它删掉。

       再往后的逻辑就跟前面执行binder_transaction函数时候一样了,这里不再介绍。最后的结果就是唤醒请求SVC_MGR_CHECK_SERVICE操作的线程:


 

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

   这样,Service Manger回复调用SVC_MGR_CHECK_SERVICE请求就算完成了,重新回到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.     ......    
  13. }   

     binder_loop函数执行完这个ioctl调用后,才会在下一次调用ioctl进入到Binder驱动程序进入休眠状态,等待下一次Client的请求。
      上面讲到调用请求SVC_MGR_CHECK_SERVICE操作的线程被唤醒了,于是,重新执行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;    
  109. }   

  就是从下面这个调用:


 

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

    被唤醒过来了。在while循环中,从thread->todo得到w,w->type为BINDER_WORK_TRANSACTION,于是,得到t。从上面可以知道,Service Manager返回来了一个Binder引用和一个结果码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;    
  4. }   

接着返回到用户空间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;    
  48. }   

     注意,这里的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);   

  我们简单看一下Parcel::ipcSetDataReference函数的实现:


 

 
 
  1. void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,  
  2.     const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)  
  3. {  
  4.     freeDataNoInit();  
  5.     mError = NO_ERROR;  
  6.     mData = const_cast<uint8_t*>(data);  
  7.     mDataSize = mDataCapacity = dataSize;  
  8.     //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());  
  9.     mDataPos = 0;  
  10.     LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);  
  11.     mObjects = const_cast<size_t*>(objects);  
  12.     mObjectsSize = mObjectsCapacity = objectsCount;  
  13.     mNextObjectHint = 0;  
  14.     mOwner = relFunc;  
  15.     mOwnerCookie = relCookie;  
  16.     scanForFds();  

  上面提到,返回来的数据中有一个Binder引用,因此,这里的mObjectSize等于1,这个Binder引用对应的位置记录在mObjects成员变量中。

        从这里层层返回,最后回到BpServiceManager::checkService函数中:


 

 
 
  1. virtual sp<IBinder> BpServiceManager::checkService( const String16& name) const  
  2. {  
  3.     Parcel data, reply;  
  4.     data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());  
  5.     data.writeString16(name);  
  6.     remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);  
  7.     return reply.readStrongBinder();  

     这里就是从:


 

 
 
  1. remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); 

返回来了。我们接着看一下reply.readStrongBinder函数的实现:


 

 
 
  1. sp<IBinder> Parcel::readStrongBinder() const  
  2. {  
  3.     sp<IBinder> val;  
  4.     unflatten_binder(ProcessState::self(), *this, &val);  
  5.     return val;  

    这里调用了unflatten_binder函数来构造一个Binder对象:


 

 
 
  1. status_t unflatten_binder(const sp<ProcessState>& proc,  
  2.     const Parcel& in, sp<IBinder>* out)  
  3. {  
  4.     const flat_binder_object* flat = in.readObject(false);  
  5.       
  6.     if (flat) {  
  7.         switch (flat->type) {  
  8.             case BINDER_TYPE_BINDER:  
  9.                 *out = static_cast<IBinder*>(flat->cookie);  
  10.                 return finish_unflatten_binder(NULL, *flat, in);  
  11.             case BINDER_TYPE_HANDLE:  
  12.                 *out = proc->getStrongProxyForHandle(flat->handle);  
  13.                 return finish_unflatten_binder(  
  14.                     static_cast<BpBinder*>(out->get()), *flat, in);  
  15.         }          
  16.     }  
  17.     return BAD_TYPE;  

    这里的flat->type是BINDER_TYPE_HANDLE,因此调用ProcessState::getStrongProxyForHandle函数:


 

 
 
  1. sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)  
  2. {  
  3.     sp<IBinder> result;  
  4.  
  5.     AutoMutex _l(mLock);  
  6.  
  7.     handle_entry* e = lookupHandleLocked(handle);  
  8.  
  9.     if (e != NULL) {  
  10.         // We need to create a new BpBinder if there isn't currently one, OR we  
  11.         // are unable to acquire a weak reference on this current one.  See comment  
  12.         // in getWeakProxyForHandle() for more info about this.  
  13.         IBinder* b = e->binder;  
  14.         if (b == NULL || !e->refs->attemptIncWeak(this)) {  
  15.             b = new BpBinder(handle);   
  16.             e->binder = b;  
  17.             if (b) e->refs = b->getWeakRefs();  
  18.             result = b;  
  19.         } else {  
  20.             // This little bit of nastyness is to allow us to add a primary 
  21.             // reference to the remote proxy when this team doesn't have one  
  22.             // but another team is sending the handle to us.  
  23.             result.force_set(b);  
  24.             e->refs->decWeak(this);  
  25.         }  
  26.     }  
  27.  
  28.     return result;  

      这里我们可以看到,ProcessState会把使用过的Binder远程接口(BpBinder)缓存起来,这样下次从Service Manager那里请求得到相同的句柄(Handle)时就可以直接返回这个Binder远程接口了,不用再创建一个出来。这里是第一次使用,因此,e->binder为空,于是创建了一个BpBinder对象:

 
 
  1. b = new BpBinder(handle);   
  2. e->binder = b;  
  3. if (b) e->refs = b->getWeakRefs();  
  4. result = b; 

   最后,函数返回到IMediaDeathNotifier::getMediaPlayerService这里,从这个语句返回:

 

 
 
  1. binder = sm->getService(String16("media.player")); 

    这里,就相当于是:

 
 
  1. binder = new BpBinder(handle); 

     最后,函数调用:


 

 
 
  1. sMediaPlayerService = interface_cast<IMediaPlayerService>(binder); 

    到了这里,我们可以参考一下前面一篇文章浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager,就会知道,这里的interface_cast实际上最终调用了IMediaPlayerService::asInterface函数:


 

 
 
  1. android::sp<IMediaPlayerService> IMediaPlayerService::asInterface(const android::sp<android::IBinder>& obj)  
  2. {  
  3.     android::sp<IServiceManager> intr;  
  4.     if (obj != NULL) {               
  5.         intr = static_cast<IMediaPlayerService*>(   
  6.             obj->queryLocalInterface(IMediaPlayerService::descriptor).get());  
  7.         if (intr == NULL) {  
  8.             intr = new BpMediaPlayerService(obj);  
  9.         }  
  10.     }  
  11.     return intr;   

    这里的obj就是BpBinder,而BpBinder::queryLocalInterface返回NULL,因此就创建了一个BpMediaPlayerService对象:


 

 
 
  1. intr = new BpMediaPlayerService(new BpBinder(handle)); 

因此,我们最终就得到了一个BpMediaPlayerService对象,达到我们最初的目标。

        有了这个BpMediaPlayerService这个远程接口之后,MediaPlayer就可以调用MediaPlayerService的服务了。

        至此,Android系统进程间通信(IPC)机制Binder中的Client如何通过Service Manager的getService函数获得Server远程接口的过程就分析完了,Binder机制的学习就暂告一段落了。

        不过,细心的读者可能会发现,我们这里介绍的Binder机制都是基于C/C++语言实现的,但是我们在编写应用程序都是基于Java语言的,那么,我们如何使用Java语言来使用系统的Binder机制来进行进程间通信呢?这就是下一篇文章要介绍的内容了,敬请关注。





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

目录
相关文章
|
30天前
|
搜索推荐 Android开发 iOS开发
安卓与iOS系统的用户界面设计对比分析
本文通过对安卓和iOS两大操作系统的用户界面设计进行对比分析,探讨它们在设计理念、交互方式、视觉风格等方面的差异及各自特点,旨在帮助读者更好地理解和评估不同系统的用户体验。
20 1
|
2月前
|
Android开发 数据安全/隐私保护 iOS开发
安卓与iOS系统的发展趋势与比较分析
【2月更文挑战第6天】 在移动互联网时代,安卓和iOS系统作为两大主流移动操作系统,各自呈现出不同的发展趋势。本文将从技术角度出发,对安卓和iOS系统的发展方向、特点及未来趋势进行比较分析,以期为读者提供更深入的了解和思考。
35 4
|
3月前
|
监控 Android开发 C语言
深度解读Android崩溃日志案例分析2:tombstone日志
深度解读Android崩溃日志案例分析2:tombstone日志
84 0
|
2天前
|
存储 Java Android开发
Android系统 设置第三方应用为默认Launcher实现和原理分析
Android系统 设置第三方应用为默认Launcher实现和原理分析
16 0
|
2天前
|
Android开发
Android源代码定制:Overlay目录定制|调试Overlay资源是否生效
Android源代码定制:Overlay目录定制|调试Overlay资源是否生效
10 0
|
2天前
|
存储 Java Linux
Android系统获取event事件回调等几种实现和原理分析
Android系统获取event事件回调等几种实现和原理分析
22 0
|
2天前
|
Android开发
Android源代码定制:添加customize.mk文件进行分项目和分客户的定制
Android源代码定制:添加customize.mk文件进行分项目和分客户的定制
2 0
|
2月前
|
网络协议 算法 Android开发
安卓逆向 -- 实战某峰窝APP(动态分析)
安卓逆向 -- 实战某峰窝APP(动态分析)
31 4
|
2月前
|
安全 搜索推荐 Android开发
Android 与 iOS 的比较分析
【2月更文挑战第5天】 Android 和 iOS 是目前市场上两种最流行的移动操作系统,它们都拥有自己的特点和优势。本文将会分别从操作系统设计、应用生态、安全性等方面对这两种操作系统进行比较和分析,希望能够帮助读者更好地选择适合自己的移动设备。
|
3月前
|
SQL 定位技术 Android开发
分享119个Android手机应用源代码总有一个是你想要的
分享119个Android手机应用源代码总有一个是你想要的
86 2

相关实验场景

更多