分享

Android-IPC-Binder(3)

 mandrave 2012-01-06

Transaction in Binder Kernel Driver

当任何进程打开/dev/binder驱动时,会分配相应的binder_proc结构(给进程)。

  1. // drivers/misc/binder.c   
  2. static int binder_open(struct inode *nodp, struct file *filp)  
  3. {  
  4.   struct binder_proc *proc;  
  5.   if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)  
  6.     printk(KERN_INFO "binder_open: %d:%d/n", current->group_leader->pid, current->pid);  
  7.   proc = kzalloc(sizeof(*proc), GFP_KERNEL);  
  8.   if (proc == NULL)  
  9.     return -ENOMEM;  
  10.   get_task_struct(current);  
  11.   proc->tsk = current;  
  12.   INIT_LIST_HEAD(&proc->todo);  
  13.   init_waitqueue_head(&proc->wait);  
  14.   proc->default_priority = task_nice(current);  
  15.   mutex_lock(&binder_lock);  
  16.   binder_stats.obj_created[BINDER_STAT_PROC]++;  
  17.   hlist_add_head(&proc->proc_node, &binder_procs);  
  18.   proc->pid = current->group_leader->pid;  
  19.   INIT_LIST_HEAD(&proc->delivered_death);  
  20.   filp->private_data = proc;  
  21.   mutex_unlock(&binder_lock);  
  22.   if (binder_proc_dir_entry_proc) {  
  23.     char strbuf[11];  
  24.     snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);  
  25.     create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc);  
  26.   }  
  27.   return 0;  
  28. }  

当任何ioctl调用时,驱动能够知道进程的信息。事务数据通过BINDER_WRITE_READ ioctl传递。

  1. // drivers/misc/binder.c   
  2. static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  3. {  
  4.   ......  
  5.   switch (cmd) {  
  6.   case BINDER_WRITE_READ: {  
  7.     struct binder_write_read bwr;  
  8.     if (size != sizeof(struct binder_write_read)) {  
  9.       ret = -EINVAL;  
  10.       goto err;  
  11.     }  
  12.     if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {  
  13.       ret = -EFAULT;  
  14.       goto err;  
  15.     }  
  16.     if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  17.       printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx/n",  
  18.             proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);  
  19.     if (bwr.write_size > 0) {  
  20.       ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);  
  21.       if (ret < 0) {  
  22.         bwr.read_consumed = 0;  
  23.         if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  24.           ret = -EFAULT;  
  25.     goto err;  
  26.       }  
  27.     }  
  28.     if (bwr.read_size > 0) {  
  29.       ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);  
  30.       if (!list_empty(&proc->todo))  
  31.         wake_up_interruptible(&proc->wait);  
  32.       if (ret < 0) {  
  33.         if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  34.           ret = -EFAULT;  
  35.         goto err;  
  36.       }  
  37.     }  
  38.     if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  39.       printk(KERN_INFO "binder: %d:%d wrote %ld of %ld, read return %ld of %ld/n",  
  40.              proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size);  
  41.     if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {  
  42.       ret = -EFAULT;  
  43.       goto err;  
  44.     }  
  45.     break;  
  46.   }  
  47.   ......  
  48. }  

驱动首先处理写,然后读。让我们先看看binder_thread_write()函数。该函数的核心是一个从写缓冲中解析命令并执行该命令的循环。

  1. // drivers/misc/binder.c   
  2. int  
  3. binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,  
  4.         void __user *buffer, int size, signed long *consumed)  
  5. {  
  6.   uint32_t cmd;  
  7.   void __user *ptr = buffer + *consumed;  
  8.   void __user *end = buffer + size;  
  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.     case ***:  
  20.     ......  
  21.     default:  
  22.       printk(KERN_ERR "binder: %d:%d unknown command %d/n", proc->pid, thread->pid, cmd);  
  23.       return -EINVAL;  
  24.     }  
  25.     *consumed = ptr - buffer;  
  26.   }  
  27.   return 0;  
  28. }  

让我们看看与本文例子相关的两个命令。一个是C_INCREFS。

  1. // drivers/misc/binder.c   
  2. case BC_INCREFS:  
  3. case BC_ACQUIRE:  
  4. case BC_RELEASE:  
  5. case BC_DECREFS: {  
  6.   uint32_t target;  
  7.   struct binder_ref *ref;  
  8.   const char *debug_string;  
  9.   if (get_user(target, (uint32_t __user *)ptr))  
  10.     return -EFAULT;  
  11.   ptr += sizeof(uint32_t);  
  12.   if (target == 0 && binder_context_mgr_node &&  
  13.     (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {  
  14.     ref = binder_get_ref_for_node(proc,  
  15.        binder_context_mgr_node);  
  16.     if (ref->desc != target) {  
  17.       binder_user_error("binder: %d:"  
  18.           "%d tried to acquire "  
  19.           "reference to desc 0, "  
  20.           "got %d instead/n",  
  21.           proc->pid, thread->pid,  
  22.           ref->desc);  
  23.     }  
  24.   } else  
  25.     ref = binder_get_ref(proc, target);  
  26.   if (ref == NULL) {  
  27.     binder_user_error("binder: %d:%d refcou"  
  28.           "nt change on invalid ref %d/n",  
  29.           proc->pid, thread->pid, target);  
  30.     break;  
  31.   }  
  32.   switch (cmd) {  
  33.   case BC_INCREFS:  
  34.     debug_string = "IncRefs";  
  35.     binder_inc_ref(ref, 0, NULL);  
  36.     break;  
  37.   case ***:  
  38.   ......  
  39.   }  
  40. }  

我们在前面说过,在我们这个例子中,target为0。当system_manager调用BINDER_SET_CONTEXT_MGR ioctl时会自创建binder_context_mgr_node代表handle 0。所以这里仅仅是增加了一个指向binder_context_mgr_node的弱引用(weak reference)。

  1. binder_context_mgr_node = binder_new_node(proc, NULL);  

另外是一个是BC_TRANSACTION命令。

  1. case BC_TRANSACTION:  
  2. case BC_REPLY: {  
  3.   struct binder_transaction_data tr;  
  4.   if (copy_from_user(&tr, ptr, sizeof(tr)))  
  5.     return -EFAULT;  
  6.   ptr += sizeof(tr);  
  7.   binder_transaction(proc, thread, &tr, cmd == BC_REPLY);  
  8.   break;  
  9. }  

当包包含一个BINDER_TYPE_BINDER flattened对象时,binder_transaction()函数会创建一个新的binder节点。

  1. // drivers/misc/binder.c   
  2. static void  
  3. binder_transaction(struct binder_proc *proc, struct binder_thread *thread,  
  4.     struct binder_transaction_data *tr, int reply)  
  5. {  
  6.   ......  
  7.   off_end = (void *)offp + tr->offsets_size;  
  8.   for (; offp < off_end; offp++) {  
  9.     struct flat_binder_object *fp;  
  10.     if (*offp > t->buffer->data_size - sizeof(*fp)) {  
  11.       binder_user_error("binder: %d:%d got transaction with "  
  12.           "invalid offset, %d/n",  
  13.           proc->pid, thread->pid, *offp);  
  14.       return_error = BR_FAILED_REPLY;  
  15.       goto err_bad_offset;  
  16.     }  
  17.     fp = (struct flat_binder_object *)(t->buffer->data + *offp);  
  18.     switch (fp->type) {  
  19.     case BINDER_TYPE_BINDER:  
  20.     case BINDER_TYPE_WEAK_BINDER: {  
  21.       struct binder_ref *ref;  
  22.       struct binder_node *node = binder_get_node(proc, fp->binder);  
  23.       if (node == NULL) {  
  24.         node = binder_new_node(proc, fp->binder, fp->cookie);  
  25.         if (node == NULL) {  
  26.           return_error = BR_FAILED_REPLY;  
  27.           goto err_binder_new_node_failed;  
  28.         }  
  29.         node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  
  30.         node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  
  31.       }  
  32.       if (fp->cookie != node->cookie) {  
  33.         binder_user_error("binder: %d:%d sending u%p "  
  34.             "node %d, cookie mismatch %p != %p/n",  
  35.             proc->pid, thread->pid,  
  36.             fp->binder, node->debug_id,  
  37.             fp->cookie, node->cookie);  
  38.             goto err_binder_get_ref_for_node_failed;  
  39.       }  
  40.       ref = binder_get_ref_for_node(target_proc, node);  
  41.       if (ref == NULL) {  
  42.         return_error = BR_FAILED_REPLY;  
  43.         goto err_binder_get_ref_for_node_failed;  
  44.       }  
  45.       if (fp->type == BINDER_TYPE_BINDER)  
  46.         fp->type = BINDER_TYPE_HANDLE;  
  47.       else  
  48.         fp->type = BINDER_TYPE_WEAK_HANDLE;  
  49.       fp->handle = ref->desc;  
  50.       binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);  
  51.       if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)  
  52.         printk(KERN_INFO "        node %d u%p -> ref %d desc %d/n",  
  53.             node->debug_id, node->ptr, ref->debug_id, ref->desc);  
  54.     } break;  
  55.     ......  
  56.     } end of switch  
  57.   } // end of for   
  58.   ......  
  59. }  

binder_transaction()会知道target为handle 0,因此它会执行以下代码分支去获取target_node,target_proc和target_thread。

  1. else {  
  2.   target_node = binder_context_mgr_node;  
  3.   if (target_node == NULL) {  
  4.     return_error = BR_DEAD_REPLY;  
  5.     goto err_no_context_mgr_node;  
  6.   }  
  7. }  
  8. e->to_node = target_node->debug_id;  
  9. target_proc = target_node->proc;  
  10. if (target_proc == NULL) {  
  11.   return_error = BR_DEAD_REPLY;  
  12.   goto err_dead_binder;  
  13. }  
  14. if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {  
  15.   struct binder_transaction *tmp;  
  16.   tmp = thread->transaction_stack;  
  17.   while (tmp) {  
  18.     if (tmp->from && tmp->from->proc == target_proc)  
  19.       target_thread = tmp->from;  
  20.     tmp = tmp->from_parent;  
  21.   }  
  22. }  

最终,binder_transaction()会将请求放入链表,并唤醒binder_thread_read()中的等待线程。

  1. // drivers/misc/binder.c   
  2. static void  
  3. binder_transaction(struct binder_proc *proc, struct binder_thread *thread,  
  4.     struct binder_transaction_data *tr, int reply)  
  5. {  
  6.   ......  
  7.   t->work.type = BINDER_WORK_TRANSACTION;  
  8.   list_add_tail(&t->work.entry, target_list);  
  9.   tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;  
  10.   list_add_tail(&tcomplete->entry, &thread->todo);  
  11.   if (target_wait)  
  12.     wake_up_interruptible(target_wait);  
  13.   return;  
  14.   ......  
  15. }  

现在,让我们来看看binder_thread_read()函数。当service_manager运行时,它会在这里等待,直到有请求到达。

  1. // drivers/misc/binder.c   
  2. static int  
  3. binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,  
  4.     void  __user *buffer, int size, signed long *consumed, int non_block)  
  5. {  
  6.   ......  
  7.   ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));  
  8.   ......  
  9. }  

因为media_server之前的写操作唤醒了它,于是binder_thread_read()函数开始执行。下面的命令将media_server的写缓冲区的数据拷贝到system_manager的读缓冲区。

  1. tr.data_size = t->buffer->data_size;  
  2. tr.offsets_size = t->buffer->offsets_size;  
  3. tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset);  
  4. tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));  
  5. if (put_user(cmd, (uint32_t __user *)ptr))  
  6.   return -EFAULT;  
  7. ptr += sizeof(uint32_t);  
  8. if (copy_to_user(ptr, &tr, sizeof(tr)))  
  9.   return -EFAULT;  
  10. ptr += sizeof(tr);  

小结:

本节展示了数据如何从RPC调用的client端流到RPC的服务端。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多