现在的位置: 首页 > 综合 > 正文

Android之binder驱动个人学习小结

2012年10月22日 ⁄ 综合 ⁄ 共 6924字 ⁄ 字号 评论关闭

转载:http://blog.csdn.net/gzzaigcn/article/details/7859740

主要描述的底层驱动部分代码。

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。

欢迎和大家交流。qq:1037701636 email: gzzaigcn2009@163.comgzzaigcn2012@gmail.com

 

前言:

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
plain
copy

  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
plain
copy

  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
plain
copy

  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 *)));//内存中的偏移量  

抱歉!评论已关闭.