浅谈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,如需转载请自行联系原作者

目录
相关文章
|
21天前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
20 0
Linux c/c++之IPC进程间通信
|
29天前
|
消息中间件 存储 网络协议
操作系统的心脏:深入理解进程间通信(IPC)机制
在现代计算机系统中,操作系统扮演着至关重要的角色,而进程间通信(IPC)作为操作系统的核心功能之一,极大地影响着系统的性能和稳定性。本文将通过浅显易懂的语言,详细探讨进程间通信的基本原理、主要类型及其实际应用,旨在为读者提供一个清晰且全面的理解和认识。 ##
81 1
|
21天前
|
Linux C++
Linux c/c++进程之僵尸进程和守护进程
这篇文章介绍了Linux系统中僵尸进程和守护进程的概念、产生原因、解决方法以及如何创建守护进程。
15 0
|
2月前
|
消息中间件 Python
深入理解操作系统的进程间通信(IPC)机制
本文将探讨操作系统中的核心概念——进程间通信(IPC),揭示其在系统运作中的重要性及实现方式。通过分析不同类型的IPC手段,如管道、信号、共享内存等,帮助读者更好地理解操作系统的内部工作原理及其在实际应用中的表现。
89 1
|
2月前
|
Python
惊!Python进程间通信IPC,让你的程序秒变社交达人,信息畅通无阻
【9月更文挑战第13天】在编程的世界中,进程间通信(IPC)如同一场精彩的社交舞会,每个进程通过优雅的IPC机制交换信息,协同工作。本文将带你探索Python中的IPC奥秘,了解它是如何让程序实现无缝信息交流的。IPC如同隐形桥梁,连接各进程,使其跨越边界自由沟通。Python提供了多种IPC机制,如管道、队列、共享内存及套接字,适用于不同场景。通过一个简单的队列示例,我们将展示如何使用`multiprocessing.Queue`实现进程间通信,使程序如同社交达人般高效互动。掌握IPC,让你的程序在编程舞台上大放异彩。
20 3
|
2月前
|
消息中间件 Unix
操作系统的心脏:深入理解进程间通信(IPC)
在现代计算中,操作系统扮演着至关重要的角色,它不仅管理着硬件资源,还负责协调和优化应用程序之间的交互。本文将深入探讨操作系统中的一个核心概念——进程间通信(IPC),揭示其背后的机制以及在实际应用中的重要性。通过通俗易懂的语言和条理清晰的解释,本文旨在为读者提供一个关于IPC的全面了解,从基本定义到高级应用,带领大家走进操作系统的神秘世界。
|
2月前
|
消息中间件 存储 大数据
深入理解操作系统中的进程间通信(IPC)机制
本文旨在探讨操作系统中进程间通信(IPC)的核心机制与其重要性。通过对不同IPC手段如管道、信号、消息队列及共享内存等的详细解析,揭示它们如何高效地促进进程间的信息交换与同步。文章不仅阐述各种IPC技术的实现原理,还探讨了它们在实际系统应用中的场景与优化策略,为系统开发者提供全面而深入的理解。
|
2月前
|
消息中间件 程序员 数据处理
探究操作系统中的进程间通信(IPC)机制及其在现代软件开发中的应用
本文深入探讨了操作系统中的核心概念——进程间通信(IPC),揭示了其在现代软件开发中的关键作用。通过对各种IPC机制如管道、消息队列、共享内存等的详细分析,本文旨在为读者提供一个清晰的理解框架,帮助他们掌握如何在实际应用中有效利用这些技术以实现进程间的协同工作。此外,文章还将探讨IPC在高并发环境下的性能优化策略,以及如何避免常见的IPC编程错误。通过结合理论与实践,本文不仅适合希望深入了解操作系统原理的技术人员阅读,也对那些致力于提升软件质量和开发效率的程序员具有重要参考价值。
38 0
|
6月前
|
安全 Java 定位技术
Android 浅度解析:AIDL & Binder (1)
Android 浅度解析:AIDL & Binder (1)
194 0
|
4月前
|
缓存 安全 Java
Android深入Binder拦截问题分析
【7月更文挑战第1天】Android Binder 拦截可实现虚拟化、测试、SDK检测、逆向分析及ROM扩展。通过Java层aidl代理,利用IBinder接口规范来拦截通信。拦截步骤包括:替换Binder服务缓存对象,如ActivityManagerService;代理ServiceManager以控制服务获取。此操作需系统权限,可能涉及安全风险和版本差异,非必要时应谨慎。

相关实验场景

更多