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

目录
相关文章
|
5天前
|
算法 Linux 调度
深入探索安卓系统的多任务处理机制
【10月更文挑战第21天】 本文旨在为读者提供一个关于Android系统多任务处理机制的全面解析。我们将从Android操作系统的核心架构出发,探讨其如何管理多个应用程序的同时运行,包括进程调度、内存管理和电量优化等方面。通过深入分析,本文揭示了Android在处理多任务时所面临的挑战以及它如何通过创新的解决方案来提高用户体验和设备性能。
9 1
|
10天前
|
存储 安全 Android开发
探索Android与iOS的隐私保护机制
在数字化时代,移动设备已成为我们生活的一部分,而隐私安全是用户最为关注的问题之一。本文将深入探讨Android和iOS两大主流操作系统在隐私保护方面的策略和实现方式,分析它们各自的优势和不足,以及如何更好地保护用户的隐私。
|
1月前
|
消息中间件 存储 Java
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
41 2
|
21天前
|
消息中间件 存储 Linux
|
29天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
1月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
49 1
|
1月前
|
存储 安全 数据安全/隐私保护
探索安卓与iOS的隐私保护机制####
【10月更文挑战第15天】 本文深入剖析了安卓和iOS两大操作系统在隐私保护方面的策略与技术实现,旨在揭示两者如何通过不同的技术手段来保障用户数据的安全与隐私。文章将逐一探讨各自的隐私控制功能、加密措施以及用户权限管理,为读者提供一个全面而深入的理解。 ####
56 1
|
1月前
|
消息中间件 存储 Java
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
45 2
|
1月前
|
消息中间件 存储 网络协议
操作系统的心脏:深入理解进程间通信(IPC)机制
在现代计算机系统中,操作系统扮演着至关重要的角色,而进程间通信(IPC)作为操作系统的核心功能之一,极大地影响着系统的性能和稳定性。本文将通过浅显易懂的语言,详细探讨进程间通信的基本原理、主要类型及其实际应用,旨在为读者提供一个清晰且全面的理解和认识。 ##
131 1
|
2月前
|
存储 缓存 Android开发
Android RecyclerView 缓存机制深度解析与面试题
本文首发于公众号“AntDream”,详细解析了 `RecyclerView` 的缓存机制,包括多级缓存的原理与流程,并提供了常见面试题及答案。通过本文,你将深入了解 `RecyclerView` 的高性能秘诀,提升列表和网格的开发技能。
71 8