浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路(2)

简介:

 继续分析这个函数之前,又要解释两个数据结构了,一个是struct binder_thread结构体,顾名思久,它表示一个线程,这里就是执行binder_become_context_manager函数的线程了。

 

 
 
  1. struct binder_thread {  
  2.     struct binder_proc *proc;  
  3.     struct rb_node rb_node;  
  4.     int pid;  
  5.     int looper;  
  6.     struct binder_transaction *transaction_stack;  
  7.     struct list_head todo;  
  8.     uint32_t return_error; /* Write failed, return error code in read buf */  
  9.     uint32_t return_error2; /* Write failed, return error code in read */  
  10.         /* buffer. Used when sending a reply to a dead process that */  
  11.         /* we are also waiting on */  
  12.     wait_queue_head_t wait;  
  13.     struct binder_stats stats;  
  14. }; 

  proc表示这个线程所属的进程。struct binder_proc有一个成员变量threads,它的类型是rb_root,它表示一查红黑树,把属于这个进程的所有线程都组织起来,struct binder_thread的成员变量rb_node就是用来链入这棵红黑树的节点了。looper成员变量表示线程的状态,它可以取下面这几个值:

 

 
 
  1. enum {  
  2.     BINDER_LOOPER_STATE_REGISTERED  = 0x01,  
  3.     BINDER_LOOPER_STATE_ENTERED     = 0x02,  
  4.     BINDER_LOOPER_STATE_EXITED      = 0x04,  
  5.     BINDER_LOOPER_STATE_INVALID     = 0x08,  
  6.     BINDER_LOOPER_STATE_WAITING     = 0x10,  
  7.     BINDER_LOOPER_STATE_NEED_RETURN = 0x20  
  8. }; 

  其余的成员变量,transaction_stack表示线程正在处理的事务,todo表示发往该线程的数据列表,return_error和return_error2表示操作结果返回码,wait用来阻塞线程等待某个事件的发生,stats用来保存一些统计信息。这些成员变量遇到的时候再分析它们的作用。

 

        另外一个数据结构是struct binder_node,它表示一个binder实体:

 

 
 
  1. struct binder_node {  
  2.     int debug_id;  
  3.     struct binder_work work;  
  4.     union {  
  5.         struct rb_node rb_node;  
  6.         struct hlist_node dead_node;  
  7.     };  
  8.     struct binder_proc *proc;  
  9.     struct hlist_head refs;  
  10.     int internal_strong_refs;  
  11.     int local_weak_refs;  
  12.     int local_strong_refs;  
  13.     void __user *ptr;  
  14.     void __user *cookie;  
  15.     unsigned has_strong_ref : 1;  
  16.     unsigned pending_strong_ref : 1;  
  17.     unsigned has_weak_ref : 1;  
  18.     unsigned pending_weak_ref : 1;  
  19.     unsigned has_async_transaction : 1;  
  20.     unsigned accept_fds : 1;  
  21.     int min_priority : 8;  
  22.     struct list_head async_todo;  
  23. }; 

   rb_node和dead_node组成一个联合体。 如果这个Binder实体还在正常使用,则使用rb_node来连入proc->nodes所表示的红黑树的节点,这棵红黑树用来组织属于这个进程的所有Binder实体;如果这个Binder实体所属的进程已经销毁,而这个Binder实体又被其它进程所引用,则这个Binder实体通过dead_node进入到一个哈希表中去存放。proc成员变量就是表示这个Binder实例所属于进程了。refs成员变量把所有引用了该Binder实体的Binder引用连接起来构成一个链表。internal_strong_refs、local_weak_refs和local_strong_refs表示这个Binder实体的引用计数。ptr和cookie成员变量分别表示这个Binder实体在用户空间的地址以及附加数据。其余的成员变量就不描述了,遇到的时候再分析。

 

        现在回到binder_ioctl函数中,首先是通过filp->private_data获得proc变量,这里binder_mmap函数是一样的。接着通过binder_get_thread函数获得线程信息,我们来看一下这个函数:

 

 
 
  1. static struct binder_thread *binder_get_thread(struct binder_proc *proc)  
  2. {  
  3.     struct binder_thread *thread = NULL;  
  4.     struct rb_node *parent = NULL;  
  5.     struct rb_node **p = &proc->threads.rb_node;  
  6.  
  7.     while (*p) {  
  8.         parent = *p;  
  9.         thread = rb_entry(parent, struct binder_thread, rb_node);  
  10.  
  11.         if (current->pid < thread->pid)  
  12.             p = &(*p)->rb_left;  
  13.         else if (current->pid > thread->pid)  
  14.             p = &(*p)->rb_right;  
  15.         else 
  16.             break;  
  17.     }  
  18.     if (*p == NULL) {  
  19.         thread = kzalloc(sizeof(*thread), GFP_KERNEL);  
  20.         if (thread == NULL)  
  21.             return NULL;  
  22.         binder_stats.obj_created[BINDER_STAT_THREAD]++;  
  23.         thread->proc = proc;  
  24.         thread->pid = current->pid;  
  25.         init_waitqueue_head(&thread->wait);  
  26.         INIT_LIST_HEAD(&thread->todo);  
  27.         rb_link_node(&thread->rb_node, parent, p);  
  28.         rb_insert_color(&thread->rb_node, &proc->threads);  
  29.         thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;  
  30.         thread->return_error = BR_OK;  
  31.         thread->return_error2 = BR_OK;  
  32.     }  
  33.     return thread;  

 这里把当前线程current的pid作为键值,在进程proc->threads表示的红黑树中进行查找,看是否已经为当前线程创建过了binder_thread信息。在这个场景下,由于当前线程是第一次进到这里,所以肯定找不到,即*p == NULL成立,于是,就为当前线程创建一个线程上下文信息结构体binder_thread,并初始化相应成员变量,并插入到proc->threads所表示的红黑树中去,下次要使用时就可以从proc中找到了。注意,这里的thread->looper = BINDER_LOOPER_STATE_NEED_RETURN。

 

        回到binder_ioctl函数,继续往下面,有两个全局变量binder_context_mgr_node和binder_context_mgr_uid,它定义如下:

 

 
 
  1. static struct binder_node *binder_context_mgr_node;  
  2. static uid_t binder_context_mgr_uid = -1; 

   binder_context_mgr_node用来表示Service Manager实体,binder_context_mgr_uid表示Service Manager守护进程的uid。在这个场景下,由于当前线程是第一次进到这里,所以binder_context_mgr_node为NULL,binder_context_mgr_uid为-1,于是初始化binder_context_mgr_uid为current->cred->euid,这样,当前线程就成为Binder机制的守护进程了,并且通过binder_new_node为Service Manager创建Binder实体:

 

 
 
  1. static struct binder_node *  
  2. binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie)  
  3. {  
  4.     struct rb_node **p = &proc->nodes.rb_node;  
  5.     struct rb_node *parent = NULL;  
  6.     struct binder_node *node;  
  7.  
  8.     while (*p) {  
  9.         parent = *p;  
  10.         node = rb_entry(parent, struct binder_node, rb_node);  
  11.  
  12.         if (ptr < node->ptr)  
  13.             p = &(*p)->rb_left;  
  14.         else if (ptr > node->ptr)  
  15.             p = &(*p)->rb_right;  
  16.         else 
  17.             return NULL;  
  18.     }  
  19.  
  20.     node = kzalloc(sizeof(*node), GFP_KERNEL);  
  21.     if (node == NULL)  
  22.         return NULL;  
  23.     binder_stats.obj_created[BINDER_STAT_NODE]++;  
  24.     rb_link_node(&node->rb_node, parent, p);  
  25.     rb_insert_color(&node->rb_node, &proc->nodes);  
  26.     node->debug_id = ++binder_last_id;  
  27.     node->proc = proc;  
  28.     node->ptr = ptr;  
  29.     node->cookie = cookie;  
  30.     node->work.type = BINDER_WORK_NODE;  
  31.     INIT_LIST_HEAD(&node->work.entry);  
  32.     INIT_LIST_HEAD(&node->async_todo);  
  33.     if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS)  
  34.         printk(KERN_INFO "binder: %d:%d node %d u%p c%p created\n",  
  35.                proc->pid, current->pid, node->debug_id,  
  36.                node->ptr, node->cookie);  
  37.     return node;  

 注意,这里传进来的ptr和cookie均为NULL。函数首先检查proc->nodes红黑树中是否已经存在以ptr为键值的node,如果已经存在,就返回NULL。在这个场景下,由于当前线程是第一次进入到这里,所以肯定不存在,于是就新建了一个ptr为NULL的binder_node,并且初始化其它成员变量,并插入到proc->nodes红黑树中去。

 

        binder_new_node返回到binder_ioctl函数后,就把新建的binder_node指针保存在binder_context_mgr_node中了,紧接着,又初始化了binder_context_mgr_node的引用计数值。

        这样,BINDER_SET_CONTEXT_MGR命令就执行完毕了,binder_ioctl函数返回之前,执行了下面语句:

 

 
 
  1. if (thread)  
  2.         thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; 

    回忆上面执行binder_get_thread时,thread->looper = BINDER_LOOPER_STATE_NEED_RETURN,执行了这条语句后,thread->looper = 0。

 

       回到frameworks/base/cmds/servicemanager/service_manager.c文件中的main函数,下一步就是调用binder_loop函数进入循环,等待Client来请求了。binder_loop函数定义在frameworks/base/cmds/servicemanager/binder.c文件中:

 

 
 
  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.     }  

  首先是通过binder_write函数执行BC_ENTER_LOOPER命令告诉Binder驱动程序, Service Manager要进入循环了。

 

       这里又要介绍一下设备文件/dev/binder文件操作函数ioctl的操作码BINDER_WRITE_READ了,首先看定义:

 

 
 
  1. #define BINDER_WRITE_READ           _IOWR('b', 1, struct binder_write_read) 

   这个io操作码有一个参数,形式为struct binder_write_read:

 

 
 
  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驱动程序交互大多数都是通过BINDER_WRITE_READ命令的,write_bufffer和read_buffer所指向的数据结构还指定了具体要执行的操作,write_bufffer和read_buffer所指向的结构体是struct binder_transaction_data:

 

 
 
  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. }; 

  有一个联合体target,当这个BINDER_WRITE_READ命令的目标对象是本地Binder实体时,就使用ptr来表示这个对象在本进程中的地址,否则就使用handle来表示这个Binder实体的引用。只有目标对象是Binder实体时,cookie成员变量才有意义,表示一些附加数据,由Binder实体来解释这个个附加数据。code表示要对目标对象请求的命令代码,有很多请求代码,这里就不列举了,在这个场景中,就是BC_ENTER_LOOPER了,用来告诉Binder驱动程序, Service Manager要进入循环了。其余的请求命令代码可以参考kernel/common/drivers/staging/android/binder.h文件中定义的两个枚举类型BinderDriverReturnProtocol和BinderDriverCommandProtocol。

 

       flags成员变量表示事务标志:

 

 
 
  1. enum transaction_flags {  
  2.     TF_ONE_WAY  = 0x01, /* this is a one-way call: async, no return */  
  3.     TF_ROOT_OBJECT  = 0x04, /* contents are the component's root object */  
  4.     TF_STATUS_CODE  = 0x08, /* contents are a 32-bit status code */  
  5.     TF_ACCEPT_FDS   = 0x10, /* allow replies with file descriptors */  
  6. }; 

   每一个标志位所表示的意义看注释就行了,遇到时再具体分析。

 

      sender_pid和sender_euid表示发送者进程的pid和euid。

      data_size表示data.buffer缓冲区的大小,offsets_size表示data.offsets缓冲区的大小。这里需要解释一下data成员变量,命令的真正要传输的数据就保存在data.buffer缓冲区中,前面的一成员变量都是一些用来描述数据的特征的。data.buffer所表示的缓冲区数据分为两类,一类是普通数据,Binder驱动程序不关心,一类是Binder实体或者Binder引用,这需要Binder驱动程序介入处理。为什么呢?想想,如果一个进程A传递了一个Binder实体或Binder引用给进程B,那么,Binder驱动程序就需要介入维护这个Binder实体或者引用的引用计数,防止B进程还在使用这个Binder实体时,A却销毁这个实体,这样的话,B进程就会crash了。所以在传输数据时,如果数据中含有Binder实体和Binder引和,就需要告诉Binder驱动程序它们的具体位置,以便Binder驱动程序能够去维护它们。data.offsets的作用就在这里了,它指定在data.buffer缓冲区中,所有Binder实体或者引用的偏移位置。每一个Binder实体或者引用,通过struct flat_binder_object 来表示:

 

 
 
  1. /*  
  2.  * This is the flattened representation of a Binder object for transfer  
  3.  * between processes.  The 'offsets' supplied as part of a binder transaction 
  4.  * contains offsets into the data where these structures occur.  The Binder  
  5.  * driver takes care of re-writing the structure type and data as it moves  
  6.  * between processes.  
  7.  */  
  8. struct flat_binder_object {  
  9.     /* 8 bytes for large_flat_header. */  
  10.     unsigned long       type;  
  11.     unsigned long       flags;  
  12.  
  13.     /* 8 bytes of data. */  
  14.     union {  
  15.         void        *binder;    /* local object */  
  16.         signed long handle;     /* remote object */  
  17.     };  
  18.  
  19.     /* extra data associated with local object */  
  20.     void            *cookie;  
  21. }; 

    type表示Binder对象的类型,它取值如下所示:

 

 
 
  1. enum {  
  2.     BINDER_TYPE_BINDER  = B_PACK_CHARS('s''b''*', B_TYPE_LARGE),  
  3.     BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w''b''*', B_TYPE_LARGE),  
  4.     BINDER_TYPE_HANDLE  = B_PACK_CHARS('s''h''*', B_TYPE_LARGE),  
  5.     BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w''h''*', B_TYPE_LARGE),  
  6.     BINDER_TYPE_FD      = B_PACK_CHARS('f''d''*', B_TYPE_LARGE),  
  7. }; 

  flags表示Binder对象的标志,该域只对第一次传递Binder实体时有效,因为此刻驱动需要在内核中创建相应的实体节点,有些参数需要从该域取出。

 

       type和flags的具体意义可以参考Android Binder设计与实现一文。

       最后,binder表示这是一个Binder实体,handle表示这是一个Binder引用,当这是一个Binder实体时,cookie才有意义,表示附加数据,由进程自己解释。

       数据结构分析完了,回到binder_loop函数中,首先是执行BC_ENTER_LOOPER命令:

 

 
 
  1. readbuf[0] = BC_ENTER_LOOPER;  
  2. binder_write(bs, readbuf, sizeof(unsigned)); 

     进入到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;  

   注意这里的binder_write_read变量bwr,write_size大小为4,表示write_buffer缓冲区大小为4,它的内容是一个BC_ENTER_LOOPER命令协议号,read_buffer为空。接着又是调用ioctl函数进入到Binder驱动程序的binder_ioctl函数,这里我们也只是关注BC_ENTER_LOOPER相关的逻辑:

 

 
 
  1. static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  2. {  
  3.     int ret;  
  4.     struct binder_proc *proc = filp->private_data;  
  5.     struct binder_thread *thread;  
  6.     unsigned int size = _IOC_SIZE(cmd);  
  7.     void __user *ubuf = (void __user *)arg;  
  8.  
  9.     /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/  
  10.  
  11.     ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);  
  12.     if (ret)  
  13.         return ret;  
  14.  
  15.     mutex_lock(&binder_lock);  
  16.     thread = binder_get_thread(proc);  
  17.     if (thread == NULL) {  
  18.         ret = -ENOMEM;  
  19.         goto err;  
  20.     }  
  21.  
  22.     switch (cmd) {  
  23.     case BINDER_WRITE_READ: {  
  24.         struct binder_write_read bwr;  
  25.         if (size != sizeof(struct binder_write_read)) {  
  26.             ret = -EINVAL;  
  27.             goto err;  
  28.         }  
  29.         if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {  
  30.             ret = -EFAULT;  
  31.             goto err;  
  32.         }  
  33.         if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  34.             printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",  
  35.             proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);  
  36.         if (bwr.write_size > 0) {  
  37.             ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);  
  38.             if (ret < 0) {  
  39.                 bwr.read_consumed = 0;  
  40.                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  41.                     ret = -EFAULT;  
  42.                 goto err;  
  43.             }  
  44.         }  
  45.         if (bwr.read_size > 0) {  
  46.             ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);  
  47.             if (!list_empty(&proc->todo))  
  48.                 wake_up_interruptible(&proc->wait);  
  49.             if (ret < 0) {  
  50.                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  51.                     ret = -EFAULT;  
  52.                 goto err;  
  53.             }  
  54.         }  
  55.         if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  56.             printk(KERN_INFO "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",  
  57.             proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size);  
  58.         if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {  
  59.             ret = -EFAULT;  
  60.             goto err;  
  61.         }  
  62.         break;  
  63.                             }  
  64.     ......  
  65.     default:  
  66.         ret = -EINVAL;  
  67.         goto err;  
  68.     }  
  69.     ret = 0;  
  70. err:  
  71.     if (thread)  
  72.         thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;  
  73.     mutex_unlock(&binder_lock);  
  74.     wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);  
  75.     if (ret && ret != -ERESTARTSYS)  
  76.         printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);  
  77.     return ret;  

  函数前面的代码就不解释了,同前面调用binder_become_context_manager是一样的,只不过这里调用binder_get_thread函数获取binder_thread,就能从proc中直接找到了,不需要创建一个新的。

 

       首先是通过copy_from_user(&bwr, ubuf, sizeof(bwr))语句把用户传递进来的参数转换成struct binder_write_read结构体,并保存在本地变量bwr中,这里可以看出bwr.write_size等于4,于是进入binder_thread_write函数,这里我们只关注BC_ENTER_LOOPER相关的代码:

 

 
 
  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_ENTER_LOOPER:  
  21.             if (binder_debug_mask & BINDER_DEBUG_THREADS)  
  22.                 printk(KERN_INFO "binder: %d:%d BC_ENTER_LOOPER\n",  
  23.                 proc->pid, thread->pid);  
  24.             if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {  
  25.                 thread->looper |= BINDER_LOOPER_STATE_INVALID;  
  26.                 binder_user_error("binder: %d:%d ERROR:" 
  27.                     " BC_ENTER_LOOPER called after " 
  28.                     "BC_REGISTER_LOOPER\n",  
  29.                     proc->pid, thread->pid);  
  30.             }  
  31.             thread->looper |= BINDER_LOOPER_STATE_ENTERED;  
  32.             break;  
  33.         ......  
  34.         default:  
  35.             printk(KERN_ERR "binder: %d:%d unknown command %d\n", proc->pid, thread->pid, cmd);  
  36.             return -EINVAL;  
  37.         }  
  38.         *consumed = ptr - buffer;  
  39.     }  
  40.     return 0;  

  回忆前面执行binder_become_context_manager到binder_ioctl时,调用binder_get_thread函数创建的thread->looper值为0,所以这里执行完BC_ENTER_LOOPER时,thread->looper值就变为BINDER_LOOPER_STATE_ENTERED了,表明当前线程进入循环状态了。

 

       回到binder_ioctl函数,由于bwr.read_size == 0,binder_thread_read函数就不会被执行了,这样,binder_ioctl的任务就完成了。

       回到binder_loop函数,进入for循环:

 

 
 
  1. for (;;) {  
  2.     bwr.read_size = sizeof(readbuf);  
  3.     bwr.read_consumed = 0;  
  4.     bwr.read_buffer = (unsigned) readbuf;  
  5.  
  6.     res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  
  7.  
  8.     if (res < 0) {  
  9.         LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));  
  10.         break;  
  11.     }  
  12.  
  13.     res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);  
  14.     if (res == 0) {  
  15.         LOGE("binder_loop: unexpected reply?!\n");  
  16.         break;  
  17.     }  
  18.     if (res < 0) {  
  19.         LOGE("binder_loop: io error %d %s\n", res, strerror(errno));  
  20.         break;  
  21.     }  

又是执行一个ioctl命令,注意,这里的bwr参数各个成员的值:

 

 
 
  1. bwr.write_size = 0;  
  2. bwr.write_consumed = 0;  
  3. bwr.write_buffer = 0;  
  4. readbuf[0] = BC_ENTER_LOOPER;  
  5. bwr.read_size = sizeof(readbuf);  
  6. bwr.read_consumed = 0;  
  7. bwr.read_buffer = (unsigned) readbuf; 

  再次进入到binder_ioctl函数:

 

 
 
  1. static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  2. {  
  3.     int ret;  
  4.     struct binder_proc *proc = filp->private_data;  
  5.     struct binder_thread *thread;  
  6.     unsigned int size = _IOC_SIZE(cmd);  
  7.     void __user *ubuf = (void __user *)arg;  
  8.  
  9.     /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/  
  10.  
  11.     ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);  
  12.     if (ret)  
  13.         return ret;  
  14.  
  15.     mutex_lock(&binder_lock);  
  16.     thread = binder_get_thread(proc);  
  17.     if (thread == NULL) {  
  18.         ret = -ENOMEM;  
  19.         goto err;  
  20.     }  
  21.  
  22.     switch (cmd) {  
  23.     case BINDER_WRITE_READ: {  
  24.         struct binder_write_read bwr;  
  25.         if (size != sizeof(struct binder_write_read)) {  
  26.             ret = -EINVAL;  
  27.             goto err;  
  28.         }  
  29.         if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {  
  30.             ret = -EFAULT;  
  31.             goto err;  
  32.         }  
  33.         if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  34.             printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",  
  35.             proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);  
  36.         if (bwr.write_size > 0) {  
  37.             ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);  
  38.             if (ret < 0) {  
  39.                 bwr.read_consumed = 0;  
  40.                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  41.                     ret = -EFAULT;  
  42.                 goto err;  
  43.             }  
  44.         }  
  45.         if (bwr.read_size > 0) {  
  46.             ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);  
  47.             if (!list_empty(&proc->todo))  
  48.                 wake_up_interruptible(&proc->wait);  
  49.             if (ret < 0) {  
  50.                 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))  
  51.                     ret = -EFAULT;  
  52.                 goto err;  
  53.             }  
  54.         }  
  55.         if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)  
  56.             printk(KERN_INFO "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",  
  57.             proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size);  
  58.         if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {  
  59.             ret = -EFAULT;  
  60.             goto err;  
  61.         }  
  62.         break;  
  63.                             }  
  64.     ......  
  65.     default:  
  66.         ret = -EINVAL;  
  67.         goto err;  
  68.     }  
  69.     ret = 0;  
  70. err:  
  71.     if (thread)  
  72.         thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;  
  73.     mutex_unlock(&binder_lock);  
  74.     wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);  
  75.     if (ret && ret != -ERESTARTSYS)  
  76.         printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);  
  77.     return ret;  

  这次,bwr.write_size等于0,于是不会执行binder_thread_write函数,bwr.read_size等于32,于是进入到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.     if (thread->return_error != BR_OK && ptr < end) {  
  21.         if (thread->return_error2 != BR_OK) {  
  22.             if (put_user(thread->return_error2, (uint32_t __user *)ptr))  
  23.                 return -EFAULT;  
  24.             ptr += sizeof(uint32_t);  
  25.             if (ptr == end)  
  26.                 goto done;  
  27.             thread->return_error2 = BR_OK;  
  28.         }  
  29.         if (put_user(thread->return_error, (uint32_t __user *)ptr))  
  30.             return -EFAULT;  
  31.         ptr += sizeof(uint32_t);  
  32.         thread->return_error = BR_OK;  
  33.         goto done;  
  34.     }  
  35.  
  36.  
  37.     thread->looper |= BINDER_LOOPER_STATE_WAITING;  
  38.     if (wait_for_proc_work)  
  39.         proc->ready_threads++;  
  40.     mutex_unlock(&binder_lock);  
  41.     if (wait_for_proc_work) {  
  42.         if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |  
  43.             BINDER_LOOPER_STATE_ENTERED))) {  
  44.                 binder_user_error("binder: %d:%d ERROR: Thread waiting " 
  45.                     "for process work before calling BC_REGISTER_" 
  46.                     "LOOPER or BC_ENTER_LOOPER (state %x)\n",  
  47.                     proc->pid, thread->pid, thread->looper);  
  48.                 wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);  
  49.         }  
  50.         binder_set_nice(proc->default_priority);  
  51.         if (non_block) {  
  52.             if (!binder_has_proc_work(proc, thread))  
  53.                 ret = -EAGAIN;  
  54.         } else 
  55.             ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));  
  56.     } else {  
  57.         if (non_block) {  
  58.             if (!binder_has_thread_work(thread))  
  59.                 ret = -EAGAIN;  
  60.         } else 
  61.             ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));  
  62.     }  
  63.         .......  

传入的参数*consumed == 0,于是写入一个值BR_NOOP到参数ptr指向的缓冲区中去,即用户传进来的bwr.read_buffer缓冲区。这时候,thread->transaction_stack == NULL,并且thread->todo列表也是空的,这表示当前线程没有事务需要处理,于是wait_for_proc_work为true,表示要去查看proc是否有未处理的事务。当前thread->return_error == BR_OK,这是前面创建binder_thread时初始化设置的。于是继续往下执行,设置thread的状态为BINDER_LOOPER_STATE_WAITING,表示线程处于等待状态。调用binder_set_nice函数设置当前线程的优先级别为proc->default_priority,这是因为thread要去处理属于proc的事务,因此要将此thread的优先级别设置和proc一样。在这个场景中,proc也没有事务处理,即binder_has_proc_work(proc, thread)为false。如果文件打开模式为非阻塞模式,即non_block为true,那么函数就直接返回-EAGAIN,要求用户重新执行ioctl;否则的话,就通过当前线程就通过wait_event_interruptible_exclusive函数进入休眠状态,等待请求到来再唤醒了。

 

        至此,我们就从源代码一步一步地分析完Service Manager是如何成为Android进程间通信(IPC)机制Binder守护进程的了。总结一下,Service Manager是成为Android进程间通信(IPC)机制Binder守护进程的过程是这样的:

        1. 打开/dev/binder文件:open("/dev/binder", O_RDWR);

        2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);

        3. 通知Binder驱动程序它是守护进程:binder_become_context_manager(bs);

        4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);

        在这个过程中,在Binder驱动程序中建立了一个struct binder_proc结构、一个struct  binder_thread结构和一个struct binder_node结构,这样,Service Manager就在Android系统的进程间通信机制Binder担负起守护进程的职责了。





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

目录
相关文章
|
2天前
|
消息中间件 存储 Linux
|
25天前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
22 0
Linux c/c++之IPC进程间通信
|
1月前
|
消息中间件 存储 网络协议
操作系统的心脏:深入理解进程间通信(IPC)机制
在现代计算机系统中,操作系统扮演着至关重要的角色,而进程间通信(IPC)作为操作系统的核心功能之一,极大地影响着系统的性能和稳定性。本文将通过浅显易懂的语言,详细探讨进程间通信的基本原理、主要类型及其实际应用,旨在为读者提供一个清晰且全面的理解和认识。 ##
88 1
|
2月前
|
人工智能 Kubernetes 算法
探究操作系统的心脏——进程管理机制
本文深入探讨了操作系统核心组件之一——进程管理机制。进程管理作为操作系统的基础功能,负责协调和控制计算机系统内运行的所有进程,确保系统资源的有效分配与利用。通过详细介绍进程的定义、状态转换、调度算法以及多线程技术等关键概念,本文揭示了进程管理如何支撑起整个操作系统的运行框架,并保障用户任务的顺利执行。同时,文章还讨论了现代操作系统在进程管理方面的创新与挑战,为读者提供了一个全面而深入的理解视角。
43 1
|
5月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
118 13
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
4月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
144 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
3月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
4月前
|
存储 缓存 安全
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
167 1
|
4月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作

相关实验场景

更多