关闭

Android之binder驱动个人学习小结

324人阅读 评论(0) 收藏 举报
分类:

前言:

Read the fucking Source Code.

这段时间,大概花了两个星期(期间还偷懒了好几天),深入学习了一下Android的Binder驱动。话说上半年在看Mediaplay的源码时,就遇到过很多的IPC,当时也没有深入的去了解这块内容。这次为了对Android有一个系统级别的了解,所以较为深入的学习了一番。主要参考的内容包括:csdn的android 红人老罗,以及手里的一本杨丰盛的Android技术内幕(系统卷),作为主要的学习资料。当然我所小结的内容,也没有他们那么的详细,只是理清了整个思路而已。

注释:

SM:ServiceManager

MS:MediaPlayerService

xxx:指的是某种服务,入HelloService。

一.Binder驱动的整体架构

单从C++层宏观上看来,binder驱动的主要组成部分是:client(客户端),server(服务端),一个Service Manager和binder底层驱动。

整体的框图如下(摘自老罗的图):

其实从图中可以清晰的发现,在Android的应用层中Client和Server所谓的IPC,其实真正的工作均由底层的Binder驱动来完成。也就是说binder驱动可以完成进程间通信,这也是Android特点之一。Service Manager做为一个守护进程,主要来处理客户端的服务请求,管理所有的服务项。

 

二.binder底层驱动核心内容。

说到底,binder底层的驱动架构和通用的linux驱动没有区别,核心的内容包括binder_init,binder_open,binder_mmap,binder_ioctl.

binder驱动在Android系统中以miscdevice完成设备的注册,作为抽象设备,他没有直接操作硬件,只是完成了内存的拷贝处理。如果要深入理解这块机制,请参考老罗的android之旅。在这里对binder_ioctl做一定的分析:

2.1 驱动核心的操作数据结构:

binder_proc和binder_thread:

每open一个binder驱动(系统允许多个进程打开binder驱动),都会有一个专门的binder_proc管理当前进程的信息,包括进程的ID,当前进程由mmap所映射出的buffer信息,以及当前进程所允许的最大线程量。同时这个binder_proc会加入到系统的全局链表binder_procs中去,方便在不同进程之间可以查找信息。

binder_thread:在当前进程下存在多线程,因此binder驱动使用binder_thread来管理对应的线程信息,主要包括线程所属的binder_proc、当前状态looper以及一个transaction_stack(我的理解是负责着实际进程间通信交互的源头和目的地)。

binder_write_read :

[plain] view plaincopy
  1. struct binder_write_read {  
  2.     signed long write_size; /* bytes to write */  
  3.     signed long write_consumed; /* bytes consumed by driver */  
  4.     unsigned long   write_buffer;  
  5.     signed long read_size;  /* bytes to read */  
  6.     signed long read_consumed;  /* bytes consumed by driver */  
  7.     unsigned long   read_buffer;  
  8. };  

在binder驱动中,以该结构体作为信息封装的中转(可以理解为内核和用户的连接)。在驱动中为根据write_size和read_size的大小来进行处理(见ioctl的解析部分),在write_buffer和read_buffer都代表着用户空间的buffer地址。在write_buffer中,由一个cmd和binder_transaction_data组成,cmd主要告知驱动当前所要处理的内容。
binder_transaction_data:

[plain] view plaincopy
  1. struct binder_transaction_data {  
  2.     /* The first two are only used for bcTRANSACTION and brTRANSACTION,  
  3.      * identifying the target and contents of the transaction.  
  4.      */  
  5.     union {  
  6.         size_t  handle; /* target descriptor of command transaction */  
  7.         void    *ptr;   /* target descriptor of return transaction */  
  8.     } target;  
  9.     void        *cookie;    /* target object cookie */  
  10.     unsigned int    code;       /* transaction command */  
  11.   
  12.     /* General information about the transaction. */  
  13.     unsigned int    flags;  
  14.     pid_t       sender_pid;  
  15.     uid_t       sender_euid;  
  16.     size_t      data_size;  /* number of bytes of data */  
  17.     size_t      offsets_size;   /* number of bytes of offsets */  
  18.   
  19.     /* If this transaction is inline, the data immediately  
  20.      * follows here; otherwise, it ends with a pointer to  
  21.      * the data buffer.  
  22.      */  
  23.     union {  
  24.         struct {  
  25.             /* transaction data */  
  26.             const void  *buffer;  
  27.             /* offsets from buffer to flat_binder_object structs */  
  28.             const void  *offsets;  
  29.         } ptr;  
  30.         uint8_t buf[8];  
  31.     } data;  
  32. };  

在这里,buffer和offsets分别代表传输内容的数据量以及Binder实体的偏移量(会遇到多个Binder实体)。

binder_transaction:该结构体主要C/S即请求进程和服务进程的相关信息,方便进程间通信,以及信息的调用

binder_work:理解为binder驱动中,进程所要处理的工作项。
binder_transactionbinder_transactionbinder_transactionbinder_transaction

2.2 binder驱动之ioctl解析:

和常用的ioctl相类似,在这里我们关注BINDER_WRITE_READ命令项的内容。

binder_thread_write和binder_thread_read会根据用户传入的write_size和read_size的有无来进行处理。在这里以Mediaplayservice和ServiceManager的通信来分析,调用的cmd如下:

MS首先传入cmd=BC_TRANSACTION:

调用binder_transaction:

[plain] view plaincopy
  1. static void binder_transaction(struct binder_proc *proc,  
  2.                    struct binder_thread *thread,  
  3.                    struct binder_transaction_data *tr, int reply)  
  4. {  
  5. ...else {//client请求service  
  6.         if (tr->target.handle) {//SM时为target.handle=0  
  7.             struct binder_ref *ref;  
  8.             ref = binder_get_ref(proc, tr->target.handle);  
  9.             if (ref == NULL) {  
  10.                 binder_user_error("binder: %d:%d got "  
  11.                     "transaction to invalid handle\n",  
  12.                     proc->pid, thread->pid);  
  13.                 return_error = BR_FAILED_REPLY;  
  14.                 goto err_invalid_target_handle;  
  15.             }  
  16.             target_node = ref->node;  
  17.         } else {  
  18.             target_node = binder_context_mgr_node;//调用的是SM守护进程节点  
  19.             if (target_node == NULL) {  
  20.                 return_error = BR_DEAD_REPLY;  
  21.                 goto err_no_context_mgr_node;  
  22.             }  
  23.         }  
  24.         e->to_node = target_node->debug_id;  
  25.         target_proc = target_node->proc;//SM守护进程的相关信息  
  26.         if (target_proc == NULL) {  
  27.             return_error = BR_DEAD_REPLY;  
  28.             goto err_dead_binder;  
  29.         }  
  30.         if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {  
  31.             struct binder_transaction *tmp;  
  32.             tmp = thread->transaction_stack;  
  33.             if (tmp->to_thread != thread) {  
  34.                 binder_user_error("binder: %d:%d got new "  
  35.                     "transaction with bad transaction stack"  
  36.                     ", transaction %d has target %d:%d\n",  
  37.                     proc->pid, thread->pid, tmp->debug_id,  
  38.                     tmp->to_proc ? tmp->to_proc->pid : 0,  
  39.                     tmp->to_thread ?  
  40.                     tmp->to_thread->pid : 0);  
  41.                 return_error = BR_FAILED_REPLY;  
  42.                 goto err_bad_call_stack;  
  43.             }  
  44.             while (tmp) {  
  45.                 if (tmp->from && tmp->from->proc == target_proc)  
  46.                     target_thread = tmp->from;  
  47.                 tmp = tmp->from_parent;  
  48.             }  
  49.         }  
  50.     }  
  51.     if (target_thread) {  
  52.         e->to_thread = target_thread->pid;  
  53.         target_list = &target_thread->todo;  
  54.         target_wait = &target_thread->wait;  
  55.     } else {  
  56.         target_list = &target_proc->todo;//SM进程binder_proc的todo  
  57.         target_wait = &target_proc->wait;//等待队列头,对应于SM  
  58.     }  
  59.     ...  
  60.     if (!reply && !(tr->flags & TF_ONE_WAY))  
  61.         t->from = thread;//事务性记录from binder进程,即记录下请求进程  
  62.     else  
  63.         t->from = NULL;  
  64.     t->sender_euid = proc->tsk->cred->euid;  
  65.     t->to_proc = target_proc;  
  66.     t->to_thread = target_thread;//目的服务进程  
  67.     t->code = tr->code;  
  68.     t->flags = tr->flags;  
  69.     t->priority = task_nice(current);  
  70.     t->buffer = binder_alloc_buf(target_proc, tr->data_size,  
  71.         tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));//在SM上进程上开辟一个binder_buffer  
  72.     if (t->buffer == NULL) {  
  73.         return_error = BR_FAILED_REPLY;  
  74.         goto err_binder_alloc_buf_failed;  
  75.     }  
  76.     t->buffer->allow_user_free = 0;  
  77.     t->buffer->debug_id = t->debug_id;  
  78.     t->buffer->transaction = t;  
  79.     t->buffer->target_node = target_node;  
  80.     if (target_node)  
  81.         binder_inc_node(target_node, 1, 0, NULL);//增加目标节点的引用  
  82.   
  83.     offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));//内存中的偏移量  
  84.   
  85.     if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {  
  86.         binder_user_error("binder: %d:%d got transaction with invalid "  
  87.             "data ptr\n", proc->pid, thread->pid);  
  88.         return_error = BR_FAILED_REPLY;  
  89.         goto err_copy_data_failed;  
  90.     }  
  91.     if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {  
  92.         binder_user_error("binder: %d:%d got transaction with invalid "  
  93.             "offsets ptr\n", proc->pid, thread->pid);  
  94.         return_error = BR_FAILED_REPLY;  
  95.         goto err_copy_data_failed;  
  96.     }  
  97.     if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {  
  98.         binder_user_error("binder: %d:%d got transaction with "  
  99.             "invalid offsets size, %zd\n",  
  100.             proc->pid, thread->pid, tr->offsets_size);  
  101.         return_error = BR_FAILED_REPLY;  
  102.         goto err_bad_offset;  
  103.     }  
  104.     off_end = (void *)offp + tr->offsets_size;  
  105.     for (; offp < off_end; offp++) {  
  106.         struct flat_binder_object *fp;  
  107.         if (*offp > t->buffer->data_size - sizeof(*fp) ||  
  108.             t->buffer->data_size < sizeof(*fp) ||  
  109.             !IS_ALIGNED(*offp, sizeof(void *))) {       //对buffer大小做一定的检验  
  110.             binder_user_error("binder: %d:%d got transaction with "  
  111.                 "invalid offset, %zd\n",  
  112.                 proc->pid, thread->pid, *offp);  
  113.             return_error = BR_FAILED_REPLY;  
  114.             goto err_bad_offset;  
  115.         }  
  116.         fp = (struct flat_binder_object *)(t->buffer->data + *offp);//获取一个binder实体  
  117.         switch (fp->type) {  
  118.         case BINDER_TYPE_BINDER://初次调用  
  119.         case BINDER_TYPE_WEAK_BINDER: {  
  120.             struct binder_ref *ref;  
  121.             struct binder_node *node = binder_get_node(proc, fp->binder);  
  122.             if (node == NULL) {  
  123.                 node = binder_new_node(proc, fp->binder, fp->cookie);//创建一个mediaservice节点  
  124.                 if (node == NULL) {  
  125.                     return_error = BR_FAILED_REPLY;  
  126.                     goto err_binder_new_node_failed;  
  127.                 }  
  128.                 node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  
  129.                 node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  
  130.             }  
  131.             if (fp->cookie != node->cookie) {  
  132.                 binder_user_error("binder: %d:%d sending u%p "  
  133.                     "node %d, cookie mismatch %p != %p\n",  
  134.                     proc->pid, thread->pid,  
  135.                     fp->binder, node->debug_id,  
  136.                     fp->cookie, node->cookie);  
  137.                 goto err_binder_get_ref_for_node_failed;  
  138.             }  
  139.             ref = binder_get_ref_for_node(target_proc, node);  
  140.             if (ref == NULL) {  
  141.                 return_error = BR_FAILED_REPLY;  
  142.                 goto err_binder_get_ref_for_node_failed;  
  143.             }  
  144.             if (fp->type == BINDER_TYPE_BINDER)  
  145.                 fp->type = BINDER_TYPE_HANDLE;//fp->type类型改为了BINDER_TYPE_HANDLE句柄  
  146.             else  
  147.                 fp->type = BINDER_TYPE_WEAK_HANDLE;  
  148.             fp->handle = ref->desc;//  
  149.             binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,  
  150.                        &thread->todo);//增加引用次数  
  151.   
  152.             binder_debug(BINDER_DEBUG_TRANSACTION,  
  153.                      "        node %d u%p -> ref %d desc %d\n",  
  154.                      node->debug_id, node->ptr, ref->debug_id,  
  155.                      ref->desc);  
  156.         } break;  
  157.         case BINDER_TYPE_HANDLE:  
  158.         case BINDER_TYPE_WEAK_HANDLE: {  
  159.             struct binder_ref *ref = binder_get_ref(proc, fp->handle);  
  160.             if (ref == NULL) {  
  161.                 binder_user_error("binder: %d:%d got "  
  162.                     "transaction with invalid "  
  163.                     "handle, %ld\n", proc->pid,  
  164.                     thread->pid, fp->handle);  
  165.                 return_error = BR_FAILED_REPLY;  
  166.                 goto err_binder_get_ref_failed;  
  167.             }  
  168.             if (ref->node->proc == target_proc) {  
  169.                 if (fp->type == BINDER_TYPE_HANDLE)  
  170.                     fp->type = BINDER_TYPE_BINDER;  
  171.                 else  
  172.                     fp->type = BINDER_TYPE_WEAK_BINDER;  
  173.                 fp->binder = ref->node->ptr;  
  174.                 fp->cookie = ref->node->cookie;  
  175.                 binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);  
  176.                 binder_debug(BINDER_DEBUG_TRANSACTION,  
  177.                          "        ref %d desc %d -> node %d u%p\n",  
  178.                          ref->debug_id, ref->desc, ref->node->debug_id,  
  179.                          ref->node->ptr);  
  180.             } else {  
  181.                 struct binder_ref *new_ref;  
  182.                 new_ref = binder_get_ref_for_node(target_proc, ref->node);  
  183.                 if (new_ref == NULL) {  
  184.                     return_error = BR_FAILED_REPLY;  
  185.                     goto err_binder_get_ref_for_node_failed;  
  186.                 }  
  187.                 fp->handle = new_ref->desc;  
  188.                 binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);  
  189.                 binder_debug(BINDER_DEBUG_TRANSACTION,  
  190.                          "        ref %d desc %d -> ref %d desc %d (node %d)\n",  
  191.                          ref->debug_id, ref->desc, new_ref->debug_id,  
  192.                          new_ref->desc, ref->node->debug_id);  
  193.             }  
  194.         } break;  
  195.         default:  
  196.             binder_user_error("binder: %d:%d got transactio"  
  197.                 "n with invalid object type, %lx\n",  
  198.                 proc->pid, thread->pid, fp->type);  
  199.             return_error = BR_FAILED_REPLY;  
  200.             goto err_bad_object_type;  
  201.         }  
  202.     }  
  203.     if (reply) {  
  204.         BUG_ON(t->buffer->async_transaction != 0);  
  205.         binder_pop_transaction(target_thread, in_reply_to);  
  206.     } else if (!(t->flags & TF_ONE_WAY)) {  
  207.         BUG_ON(t->buffer->async_transaction != 0);  
  208.         t->need_reply = 1;  
  209.         t->from_parent = thread->transaction_stack;   
  210.         thread->transaction_stack = t;  
  211.     } else {  
  212.         BUG_ON(target_node == NULL);  
  213.         BUG_ON(t->buffer->async_transaction != 1);  
  214.         if (target_node->has_async_transaction) {  
  215.             target_list = &target_node->async_todo;  
  216.             target_wait = NULL;  
  217.         } else  
  218.             target_node->has_async_transaction = 1;  
  219.     }  
  220.     t->work.type = BINDER_WORK_TRANSACTION;  
  221.     list_add_tail(&t->work.entry, target_list);//binder_work添加到SM进程Proc链表中  
  222.     tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;//type设置为BINDER_WORK_TRANSACTION_COMPLETE  
  223.     list_add_tail(&tcomplete->entry, &thread->todo);//待完成的工作加入的本线程的todo链表中  
  224.     if (target_wait)  
  225.         wake_up_interruptible(target_wait);//唤醒Service Manager进程  
  226.     return;  
  227.   
  228. ...}  

分析这个函数,可以知道和SM通信时,获取target_proc为SM进程的相关信息。然后是维护当前请求的binder实体,以免被crash。以binder_transaction t为C/S之间做为传递的信息,做初始化记录请求进程和服务进程到t中。最后做如下操作:

 t->work.type = BINDER_WORK_TRANSACTION;
 list_add_tail(&t->work.entry, target_list);//binder_work添加到SM进程Proc链表中
 tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;//type设置为BINDER_WORK_TRANSACTION_COMPLETE
 list_add_tail(&tcomplete->entry, &thread->todo);//待完成的工作加入的本线程的todo链表中
 if (target_wait)
  wake_up_interruptible(target_wait);//唤醒Service Manager进程

可以看到,将这个t加入到了服务进程SM的链表中,将待完成的tcomplete加入到当前MS的thread中,最后唤醒SM,做相关的处理。

MS继续执行binder_thread_read如下:

[plain] view plaincopy
  1. static int binder_thread_read(struct binder_proc *proc,  
  2.                   struct binder_thread *thread,  
  3.                   void  __user *buffer, int size,  
  4.                   signed long *consumed, int non_block)  
  5. {  
  6.     void __user *ptr = buffer + *consumed;  
  7.     void __user *end = buffer + size;  
  8.   
  9.     int ret = 0;  
  10.     int wait_for_proc_work;  
  11.   
  12.     if (*consumed == 0) {  
  13.         if (put_user(BR_NOOP, (uint32_t __user *)ptr))//添加BR_NOOP  
  14.             return -EFAULT;  
  15.         ptr += sizeof(uint32_t);  
  16.     }  
  17.   
  18. retry:  
  19.     wait_for_proc_work = thread->transaction_stack == NULL &&  
  20.                 list_empty(&thread->todo);// false  
  21.   
  22.     if (thread->return_error != BR_OK && ptr < end) {  
  23.         if (thread->return_error2 != BR_OK) {  
  24.             if (put_user(thread->return_error2, (uint32_t __user *)ptr))  
  25.                 return -EFAULT;  
  26.             ptr += sizeof(uint32_t);  
  27.             if (ptr == end)  
  28.                 goto done;  
  29.             thread->return_error2 = BR_OK;  
  30.         }  
  31.         if (put_user(thread->return_error, (uint32_t __user *)ptr))  
  32.             return -EFAULT;  
  33.         ptr += sizeof(uint32_t);  
  34.         thread->return_error = BR_OK;  
  35.         goto done;  
  36.     }  
  37.   
  38.   
  39.     thread->looper |= BINDER_LOOPER_STATE_WAITING;  
  40.     if (wait_for_proc_work)  
  41.         proc->ready_threads++;  
  42.     mutex_unlock(&binder_lock);  
  43.     if (wait_for_proc_work) {  
  44.         if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |  
  45.                     BINDER_LOOPER_STATE_ENTERED))) {  
  46.             binder_user_error("binder: %d:%d ERROR: Thread waiting "  
  47.                 "for process work before calling BC_REGISTER_"  
  48.                 "LOOPER or BC_ENTER_LOOPER (state %x)\n",  
  49.                 proc->pid, thread->pid, thread->looper);  
  50.             wait_event_interruptible(binder_user_error_wait,  
  51.                          binder_stop_on_user_error < 2);  
  52.         }  
  53.         binder_set_nice(proc->default_priority);  
  54.         if (non_block) {  
  55.             if (!binder_has_proc_work(proc, thread))  
  56.                 ret = -EAGAIN;  
  57.         } else  
  58.             ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));//binder_has_proc_work为false唤醒  
  59.     } else {  
  60.         if (non_block) {  
  61.             if (!binder_has_thread_work(thread))  
  62.                 ret = -EAGAIN;  
  63.         } else  
  64.             ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));  
  65.     }  
  66.     mutex_lock(&binder_lock);  
  67.     if (wait_for_proc_work)  
  68.         proc->ready_threads--;  
  69.     thread->looper &= ~BINDER_LOOPER_STATE_WAITING;  
  70.   
  71.     if (ret)  
  72.         return ret;  
  73.   
  74.     while (1) {  
  75.         uint32_t cmd;  
  76.         struct binder_transaction_data tr;  
  77.         struct binder_work *w;  
  78.         struct binder_transaction *t = NULL;  
  79.   
  80.         if (!list_empty(&thread->todo))  
  81.             w = list_first_entry(&thread->todo, struct binder_work, entry);  
  82.         else if (!list_empty(&proc->todo) && wait_for_proc_work)//在SM被唤醒时proc->todo为1且wait_for_proc_work等待进程有事情做  
  83.             w = list_first_entry(&proc->todo, struct binder_work, entry);//获取binder_work  
  84.         else {  
  85.             if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */  
  86.                 goto retry;  
  87.             break;  
  88.         }  
  89.   
  90.         if (end - ptr < sizeof(tr) + 4)  
  91.             break;  
  92.   
  93.         switch (w->type) {  
  94.         case BINDER_WORK_TRANSACTION: {//SM唤醒时带调用  
  95.             t = container_of(w, struct binder_transaction, work);//通过binder_transaction的指针变量work为w,获取binder_transaction  
  96.         } break;  
  97.         case BINDER_WORK_TRANSACTION_COMPLETE: {   
  98.             cmd = BR_TRANSACTION_COMPLETE;  
  99.             if (put_user(cmd, (uint32_t __user *)ptr))  //BR_TRANSACTION_COMPLETE命令写回  
  100.                 return -EFAULT;  
  101.             ptr += sizeof(uint32_t);  
  102.   
  103.             binder_stat_br(proc, thread, cmd);  
  104.             binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,  
  105.                      "binder: %d:%d BR_TRANSACTION_COMPLETE\n",  
  106.                      proc->pid, thread->pid);  
  107.   
  108.             list_del(&w->entry);//从thread->todo删除链表  
  109.             kfree(w);  
  110.             binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);  
  111.         } break;  

写会BR_NOOP和BR_TRANSACTION_COMPLETE给用户空间,相当于从内核读取了数据,同时也做list_del(&w->entry)的处理。

MS继续与binder交互,进入ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));进入睡眠等待SM的唤醒。

 

SM在被MS唤醒后所做的处理如下:

SM同样在binder_thread_read时处于ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));的睡眠当中,但是此时proc->todo已经有内容,在前面的MS write的过程进行了(list_add_tail(&t->work.entry, target_list);//binder_work添加到SM进程Proc链表中)操作,所以会执行:

 w = list_first_entry(&proc->todo, struct binder_work, entry);//获取binder_work

 t = container_of(w, struct binder_transaction, work);//通过binder_transaction的指针变量work为w,获取binder_transaction

最后获取binder_transaction t 用于SM和MS用来交互和中转信息。

有了从MS传递过来的t,将t的相关信息读取回SM的用户空间,传递给SM的命令为cmd=BR_TRANSACTION。

MS再次传递cmd=BC_REPLY,再次回到binder_thread_write

[plain] view plaincopy
  1. {  //reply=1,sevice回复给client  
  2.         in_reply_to = thread->transaction_stack;//获取当前事务性即原来MS传递给SM的binder_transaction变量t  
  3.         if (in_reply_to == NULL) {  
  4.             binder_user_error("binder: %d:%d got reply transaction "  
  5.                       "with no transaction stack\n",  
  6.                       proc->pid, thread->pid);  
  7.             return_error = BR_FAILED_REPLY;  
  8.             goto err_empty_call_stack;  
  9.         }  
  10.         binder_set_nice(in_reply_to->saved_priority);  
  11.         if (in_reply_to->to_thread != thread) {  
  12.             binder_user_error("binder: %d:%d got reply transaction "  
  13.                 "with bad transaction stack,"  
  14.                 " transaction %d has target %d:%d\n",  
  15.                 proc->pid, thread->pid, in_reply_to->debug_id,  
  16.                 in_reply_to->to_proc ?  
  17.                 in_reply_to->to_proc->pid : 0,  
  18.                 in_reply_to->to_thread ?  
  19.                 in_reply_to->to_thread->pid : 0);  
  20.             return_error = BR_FAILED_REPLY;  
  21.             in_reply_to = NULL;  
  22.             goto err_bad_call_stack;  
  23.         }  
  24.         thread->transaction_stack = in_reply_to->to_parent;  
  25.         target_thread = in_reply_to->from;//获取请求的线程  
  26.         if (target_thread == NULL) {  
  27.             return_error = BR_DEAD_REPLY;  
  28.             goto err_dead_binder;  
  29.         }  
  30.         if (target_thread->transaction_stack != in_reply_to) {  
  31.             binder_user_error("binder: %d:%d got reply transaction "  
  32.                 "with bad target transaction stack %d, "  
  33.                 "expected %d\n",  
  34.                 proc->pid, thread->pid,  
  35.                 target_thread->transaction_stack ?  
  36.                 target_thread->transaction_stack->debug_id : 0,  
  37.                 in_reply_to->debug_id);  
  38.             return_error = BR_FAILED_REPLY;  
  39.             in_reply_to = NULL;  
  40.             target_thread = NULL;  
  41.             goto err_dead_binder;  
  42.         }  
  43.         target_proc = target_thread->proc;//请教进程的相关信息  
  44.     }  

前期MS在执行时,将MS自己的thread信息记录在了t当中。

[plain] view plaincopy
  1. if (!reply && !(tr->flags & TF_ONE_WAY))  
  2.     t->from = thread;//事务性记录from binder进程,即记录下请求进程  

因此SM在执行binder_thread_write时,会获取到请求进程的thread,最终和前面MS唤醒SM一样,唤醒SM,只是现在的目标进程target_proc换成了MS的内容。

最终SM回互用户空间BR_TRANSACTION_COMPLETE,SM随后再次进行LOOP循环,睡眠等待其他请求进程的唤醒。

MS被唤醒后,所做的处理和SM被唤醒时相类似,在这里写会的cmd=BR_REPLY,以此完成了一次SM和MS的IPC.

 

2.3 binder 驱动C++层的机制简单介绍

可以简单的理解Binder IPC 实际就是C/S通过Linux的机制,对各自线程的信息进行维护,使SM和MS的用户空间不断和内核空间以ioctl进行读写的交互。服务端对信息进行解析完成相应的操作。客户度实际只需发送命令即可。作为应用程序的开发,Android很好的为我们做了各种封装,包括C++层次的binder和Java层次的binder驱动。

核心类:BpBinder(远程BinderProxy),BBinder(Native 本地Binder)

基于Binder C++层的机制,以SM和MS为例,在MS如果要和SM通信,就需要获得SM在MS进程中的一个Proxy,这里称之为BpServiceManager,BpServiceManager的操作函数分为addservice和getservice,需要的参量为一个Bpbinder(在这里就是SM远程的binder对象,相当于一个句柄,由于其特殊性,句柄数值为0)。

在2.2中分析的binder底层部分内容,就是基于用户空间的addservice开始的。在这里引用罗老师的UML图,方便自己的理解。

在这里只对BpServiceManager的addservice做解析,该类最终的实现其实还是调用BpBinder的transact来完成,而该函数的实现最终调用的是IPCThreadState的transact,在该transact代码如下:

[plain] view plaincopy
  1. status_t IPCThreadState::transact(int32_t handle,  
  2.                                   uint32_t code, const Parcel& data,  
  3.                                   Parcel* reply, uint32_t flags)  //handle=0,flags=0  
  4. {  
  5.     status_t err = data.errorCheck();  
  6.   
  7.     flags |= TF_ACCEPT_FDS;  
  8.   
  9.     IF_LOG_TRANSACTIONS() {  
  10.         TextOutput::Bundle _b(alog);  
  11.         alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "  
  12.             << handle << " / code " << TypeCode(code) << ": "  
  13.             << indent << data << dedent << endl;  
  14.     }  
  15.       
  16.     if (err == NO_ERROR) {  
  17.         LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),  
  18.             (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");  
  19.         err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//将要发送的数据整理成一个binder_transaction_data  
  20.     }  
  21.       
  22.     if (err != NO_ERROR) {  
  23.         if (reply) reply->setError(err);  
  24.         return (mLastError = err);  
  25.     }  
  26.       
  27.     if ((flags & TF_ONE_WAY) == 0) {  
  28.         #if 0  
  29.         if (code == 4) { // relayout  
  30.             LOGI(">>>>>> CALLING transaction 4");  
  31.         } else {  
  32.             LOGI(">>>>>> CALLING transaction %d", code);  
  33.         }  
  34.         #endif  
  35.         if (reply) {  
  36.             err = waitForResponse(reply);  
  37.         } else {  
  38.             Parcel fakeReply;  
  39.             err = waitForResponse(&fakeReply);  
  40.         }  
  41.         #if 0  
  42.         if (code == 4) { // relayout  
  43.             LOGI("<<<<<< RETURNING transaction 4");  
  44.         } else {  
  45.             LOGI("<<<<<< RETURNING transaction %d", code);  
  46.         }  
  47.         #endif  
  48.           
  49.         IF_LOG_TRANSACTIONS() {  
  50.             TextOutput::Bundle _b(alog);  
  51.             alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "  
  52.                 << handle << ": ";  
  53.             if (reply) alog << indent << *reply << dedent << endl;  
  54.             else alog << "(none requested)" << endl;  
  55.         }  
  56.     } else {  
  57.         err = waitForResponse(NULL, NULL);  
  58.     }  
  59.       
  60.     return err;  
  61. }  

在这里真正实现ioctl的内容在waitForResponse的talkWithDriver中实现。

SM作为Android系统中特殊的一部分,他即可用当做服务端,也管理着系统的所有Service。新的服务需要向他完成注册才可以正常的使用。因此在这里的addservice就是在远程通过Binder驱动和SM交互,完成了MS的注册,注册传入的是一个BBinder的实体BnMediaPlayService,name=MediaPlay。

在C++的binder机制中,Bpxxx对应的Bnxxx(Bpxxx继承自BpBinder,Bnxxx继承自BBinder),简单理解就是Bnxxx在向SM完成注册后,会自动启动一个线程来等待客户端的请求,而在客户端如果要请求服务,需要获取一个Bpxxx远程代理来完成。Bpxxx在getservice时还回xxx服务的binder句柄,存放在Bpxxx对应的BpBinder的mHandle中。在binder驱动的底层会根据这个mHandle,查找到对应的target服务进程,同理根据2.2中MS唤醒SM的过程,进行命令的处理。

因此总结出在客户端需要服务时,首先获得Bpxxx(new BpBinder(mHandle))。然后是最终调用BpBinder的remote()->transact。而在用户端以BBinder->ontransact完成命令的解析。

 

2.4 Binder驱动的Java机制

简单的说一下Java层的binder驱动,其实这部分的难点还是在于Java 中Native函数在JNI的转换,感谢Google的开发人员,实现了Java和C++层的Binder函数的转换。

简单的总结3个小点:

1.Java层拥有一个SM的远程接口SMProxy,句柄为0 的BinderProxy对象,BinderProxy相当于BpBinder,在JNI实现转换。

2,Ixxx接口定义一个stub和proxy,Stub(存根):理解为本地服务。proxy:远程的代理。与C++相对应的前者就是Bnxxx,后者就是Bpxxx。

3. xxx需要继承了Ixxx的Stub,才可以完成请求的处理。

 

2.5 总结

上面的内容,基本是自己的阅读和学习的感受,Binder驱动的复杂程度是难以想象的,源码量大。写完本文也没有全部读通,但是这也为深入的去了解整个android系统开辟了基础。其中有些内容都是参考罗老师的Android之旅来完成的,在这里表示感谢。在接下去的一端时间将在Android4.0.3 ICS上学习Android系统整个系统过程,主要关心的是3个开机画面,继续给力,最近身体不是很舒服,对着电脑头老是晕,效率下降了很多,但是依旧在继续努力,给自己加油。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:11372次
    • 积分:219
    • 等级:
    • 排名:千里之外
    • 原创:8篇
    • 转载:16篇
    • 译文:0篇
    • 评论:0条
    文章分类