引言

在博客Android Binder机制(3)本地服务注册过程这篇博客中我们详细讲解了本地服务的注册过程,除了一个地方之外,那就是IPCThreadState::waitForResponse()方法中的talkWithDriver(),而在talkWithDriver()中调用了binder_ioctl(),由于内容太多,所以专门写一篇博客进行分析。

实际上,不只是在服务注册过程中会调用到Binder Driver中的binder_ioctl(),在服务检索、服务使用阶段都会调用到binder_ioctl(),所以这篇博客将分这3个阶段详细讲解binder_ioctl()方法。

并且,这3个阶段均可按Binder数据的传递划分为6个阶段,如下所示:

本文中对于服务注册、服务检索、服务使用都分这6个阶段进行讲解。

另外,由于在博客Android Binder机制(2) ContextManager注册过程分析中详细分析过binder_open和binder_mmap()函数,这里就不再讲解了,不了解的小伙伴可以移步到那篇Blog中。

在开始之前,我们先补充一些基础知识。

0.1 ioctl的BINDER_WRITE_READ命令用来请求Binder Driver发送或接收IPC数据以及IPC应答数据

0.2 binder_ioctl()函数负责在两个进程间收发IPC数据以及IPC应答数据。因此,在分析binder_ioctl()函数时,必然要涉及到发送IPC数据和接收IPC数据的两个进程。

0.3 binder_write_read结构体的定义如下:

struct binder_write_read
1234567891011
 struct binder_write_read{  //bytes to write  signed long write_size;  //bytes consumed by driver  unsigned long write_buffer;  //bytes to read  signed long read_size;  //bytes consumed by driver  signed long read_consumed;  unsigned long read_buffer; } 
  • write_buffer成员变量用于发送IPC数据或IPC应答数据。而read_buffer成员变量用来接收来自Binder Driver的数据,即Binder Driver在接收IPC数据或IPC应答数据后,将它们保存到read_buffer中,而后再传递到用户空间中。
  • write_size与read_size分别用来指定write_buffer与read_buffer的数据大小
  • write_consumed与read_consumed分别用来设定write_buffer与read_buffer中被处理的数据大小
  • 在前面的学习中,我们知道IPC数据与IPC应答数据由Handle、RPC代码、RPC数据、Binder协议构成。其中Handle、RPC代码、RPC数据保存在名称为binder_transaction_data的结构体中。如下图所示:

  • 如上图所示,binder_write_read的write_buffer指向含有Binder协议和binder_transaction_data的内存区域,在Binder Driver处理IPC数据时它们被作为一个处理单元。通常这种处理单元能被连续加载到write_buffer中,但为了说明的方便,只考虑有一个IPC数据的情形。同样,read_buffer指向由Binder协议与binder_transaction_data指向的内存区域

  • binder_write_read结构体中包含着用户空间中生成的IPC数据,Binder Driver也拥有一个相同的结构体。用户空间设置完binder_write_read结构体的数据后,调用ioctl()函数传递给Binder Driver,Binder Driver调用copy_from_user()函数将用户空间中的数据拷贝到自身的binder_write_read结构体中。相反,在传递IPC应答数据时,Binder Driver将调用copy_to_user()函数,将自身binder_write_read结构体中的数据拷贝到用户空间。

1.服务注册

1.1 过程概览

服务注册过程的示意图如下所示:

通过前面的博客我们知道,Context Manager先于其他所有Service Server进行,它最先使用Binder Driver,进入待机状态,之后等待Service Server的服务注册请求或者Client的服务检索请求。
上图所示过程如下:
1)Context Manager通过open()函数调用binder_open()函数,Binder Driver使用该函数为Context Manager生成并初始化binder_proc结构体;

2)Context Manager在内核空间中开辟一块Buffer,用于接收IPC数据。Context Manager通过mmap()函数调用Binder Driver的binder_mmap()函数。Binder Driver使用binder_mmap()函数在内核空间中分配一块用于接收IPC数据的Buffer,其大小为调用mmap()函数时指定的大小,并被保存到binder_buffer结构体中。而后binder_buffer变量被注册到binder_proc结构体中;

3)Context Manager通过ioctl()调用Binder Driver的binder_ioctl()函数。在binder_ioctl()函数中,Context Manager将处于待机状态,直到另一个进程(在服务注册阶段是指Service Server)向共发送IPC数据;

4)Service Server通过open()调用Binder Driver的binder_open()函数,Binder Driver为Service Server生成binder_proc结构体,并将其初始化;

5)Service Server通过mmap()调用Binder Driver的binder_mmap()函数.Binder Driver开辟一块用于接收IPC应答数据的Buffer,并将其保存到binder_buffer结构体中。而后Service Server生成IPC数据,用来调用Context Manager的服务注册函数;

6)为了注册服务,Service Server将IPC数据传递给Binder Driver。Binder Driver将根据IPC数据中的Handle查找到Context Manager的binder_node结构体,以及binder_proc结构体;

7)为Service Server要注册的服务生成binder_node结构体。Binder Driver将binder_node分别注册到Service Server的binder_proc结构体以及Context Manager的binder_proc结构体中;

8)Binder Driver将在6)中查找到的Context Manager的binder_proc结构体中查找注册在binder_buffer结构体中的Buffer,并传递IPC数据;

9)Binder Driver会记下IPC数据发送进程(Service Server)的binder_proc结构体,以便在Context Manager向Service Server发送应答数据时查找Serivce Server的binder_proc结构体;

10)Binder Driver让Service Server处于待机状态,并将Context Manager从待机状态中唤醒,传递IPC数据。从待机状态中唤醒的Context Manager经由Binder Driver接收来自Service Server的IPC数据。Context Manager根据接收的IPC数据注册指定的服务,而后生成IPC应答数据(通知服务注册完成),并将其传递给Binder Driver;

11)Binder Driver会在9)中的Service Server的binder_proc结构体中查找注册在binder_buffer结构体中的Buffer,并传送IPC应答数据,唤醒接收端的Service Server。Service Server被唤醒后,接收IPC应答数据,并根据接收的IPC应答数据进行相应处理。

1.2 传递Binder数据的阶段1

Context Manager调用binder_open()与binder_mmap()函数,初始化binder_proc结构体,创建用于接收IPC数据的binder_buffer结构体。

在用户空间中生成一块Buffer,将read_buffer注册到binder_write_read结构体中,而后调用ioctl()函数,此时,binder_write_read结构体的read_size指的是用户空间的Buffer的大小。此时binder_ioctl()中调用的主要代码如下:

binder_ioctl()
12345678910111213141516171819202122
static long binder_ioctl(struct file*flip,unsigned int cmd,unsigned long arg){  struct binder_proc*proc=flip->private_data;  void __user*ubuf=(void __user*)arg;  thread=binder_get_thread(proc);  switch(cmd){  case BINDER_WRITE_READ:  struct binder_write_read bwr;  if(copy_from_user(&bwr,ubuf,sizeof(bwr)))  if(bwr.write_size>0){  ret=binder_thread_write(proc,thread,  (void __user*)bwr.write_buffer,bwr.write_size,  &bwr.write_consumed);  }  if(bwr.read_size>0){  ret=binder_thread_read(proc,thread,  (void __user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,  flip->f_flags & O_NONBLOCK);  }   ...  } } 

binder_ioctl()函数的第二个参数cmd是ioctl()的命令,第三个参数arg是binder_write_read结构体,它是调用ioctl()函数时使用的参数。

  • flip->private_data是在binder_open()函数中创建的binder_proc结构体
  • 由于proc的线程红黑树中还没有新建相应的线程,故在binder_get_thread()函数中新建一个binder_thread结构体
  • 分析ioctl()命令,前面已经说过,此时传递的命令是BINDER_WRITE_READ
  • 调用copy_from_user()方法将Context Manager持有的用户空间的binder_write_read结构体复制到内核空间中。而后根据read_size与write_size变量判断是发送IPC数据,还是接收IPC应答数据。Context Manager在接收IPC数据时,将生成相应的read_buffer,并且read_size的值将大于0
  • 由于read_size>0,故调用binder_thread_read()函数

1.2.1 binder_thread_read()分析

binder_thread_read()中调用到的代码如下所示:

binder_thread_read()
123456789
static int binder_thread_read(struct binder_proc *proc,  struct binder_thread *thread,void __user*buffer,int size,  signed long *consumed,int non_block) {  ...  ret=wait_event_interruptible_exclusive(proc->wait,  binder_has_proc_work(proc,thread));  ... } 

Context Manager在binder_thread_read()函数中调用wait_event_interruptible_exclusive()函数。wait_event_interruptible_exclusive()函数通过当前进程的binder_proc结构体的wait变量将当前任务注册到待机队列中。而后将task_struct结构体内的state变量由TASK_RUNNING更改为TASK_INTERRUPTIBLE,再调用schedule()函数。当Context Manager的任务阙云太为TASK_INTERRUPTIBLE时,Context Manager就不再继续运行,它将进入待机状态,直至接收到IPC数据。

1.3 传递Binder数据的阶段2

这个阶段其实对应的是诸如MediaPlayerService::instantiate();这样的过程,只不过我们这里只从Binder Driver的角度考虑问题,所以只讨论ioctl()函数。

这个阶段的示意图如下:

Service Server也会生成binder_write_read结构体,包含write_buffer与read_buffer两个成员变量。其中,read_buffer变量用于接收IPC应答数据,write_buffer变量用于发送IPC数据。binder_write_read结构体内容如下图所示:

此时binder_ioctl()函数中执行的主要代码如下:

binder_ioctl()
1234567891011121314151617181920
static long binder_ioctl(struct file*filp, unsigned int cmd,unsigned long arg) {  struct binder_proc*proc=filp->private_data;  void __user *ubuf=(void __user*)arg;  thread=binder_get_thread(proc);  switch(cmd){  case BINDER_WRITE_READ:{  struct binder_write_read bwr;  if(copy_from_user(&bwr,ubuf,sizeof(bwr))){  ret=-EFAULT;  goto err;  }  if(bwr.write_size>0){  ret=binder_write(proc,thread,(void __user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed);  }  if(bwr.read_size>0)  ret=binder_thread_read(proc,thread,(void __user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed);  }  } } 
  • Service Server调用binder_get_thread()函数生成binder_thread对象
  • 调用copy_from_user()函数,将调用空间的binder_write_read结构体拷贝至内核空间中。为了传递IPC数据,Service Server保存了binder_write_read结构体的write_buffer数据,故write_size>0
  • 由于write_size>0,故调用binder_thread_write()函数

binder_thread_write()函数的主要代码如下:

binder_thread_write()
12345678910111213141516171819202122232425262728293031323334
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,  void __user *buffer, int size, signed long *consumed) {  uint32_t cmd;  void __user *ptr = buffer + *consumed;  void __user *end = buffer + size;  while (ptr < end && thread->return_error == BR_OK) {  if (get_user(cmd, (uint32_t __user *)ptr))  return -EFAULT;  ptr += sizeof(uint32_t);   ...   switch (cmd) {   ...   case BC_TRANSACTION:  case BC_REPLY: {  struct binder_transaction_data tr;  if (copy_from_user(&tr, ptr, sizeof(tr)))  return -EFAULT;  ptr += sizeof(tr);  binder_transaction(proc, thread, &tr, cmd == BC_REPLY);  break;  }   ...   }  *consumed = ptr - buffer;  }  return 0; } 
  • buffer+*consumed指向的是当前write_buffer中要处理的数据;buffer+size则指向缓冲区的末尾
  • 调用get_user()函数的目的是将IPC数据中的Binder协议拷贝至内核空间中。在服务注册时,所使用的Binder协议是BC_TRANSACTION
  • 调用copy_from_user()函数,将IPC数据中不包含Binder协议的binder_transaction_data结构体复制到内核空间中
  • 调用binder_transaction()函数,binder_transaction)函数使用binder_transaction_data结构体中的数据来执行Binder寻址、复制Binder IPC数据、生成及检索Binder节点等操作

binder_transaction()方法的主要代码如下:

binder_transaction()
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
static void binder_transaction(struct binder_proc *proc,  struct binder_thread *thread,  struct binder_transaction_data *tr, int reply) {  struct binder_transaction *t;  struct binder_work *tcomplete;  size_t *offp, *off_end;  struct binder_proc *target_proc;  struct binder_thread *target_thread = NULL;  struct binder_node *target_node = NULL;  struct list_head *target_list;  wait_queue_head_t *target_wait;  struct binder_transaction *in_reply_to = NULL;  struct binder_transaction_log_entry *e;  uint32_t return_error;  e = binder_transaction_log_add(&binder_transaction_log);  e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);  e->from_proc = proc->pid;  e->from_thread = thread->pid;  e->target_handle = tr->target.handle;  e->data_size = tr->data_size;  e->offsets_size = tr->offsets_size;  if (reply) {  in_reply_to = thread->transaction_stack;  if (in_reply_to == NULL) {   ...   }  binder_set_nice(in_reply_to->saved_priority);  if (in_reply_to->to_thread != thread) {   ...   return_error = BR_FAILED_REPLY;  in_reply_to = NULL;  goto err_bad_call_stack;  }  thread->transaction_stack = in_reply_to->to_parent;  target_thread = in_reply_to->from;   ...   if (target_thread->transaction_stack != in_reply_to) {   ...   return_error = BR_FAILED_REPLY;  in_reply_to = NULL;  target_thread = NULL;  goto err_dead_binder;  }  target_proc = target_thread->proc;  } else {  if (tr->target.handle) {  struct binder_ref *ref;  ref = binder_get_ref(proc, tr->target.handle);   ...   target_node = ref->node;  } else {  target_node = binder_context_mgr_node;   ...  }  e->to_node = target_node->debug_id;  target_proc = target_node->proc;  if (target_proc == NULL) {  return_error = BR_DEAD_REPLY;  goto err_dead_binder;  }  if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {  struct binder_transaction *tmp;  tmp = thread->transaction_stack;   ...   while (tmp) {  if (tmp->from && tmp->from->proc == target_proc)  target_thread = tmp->from;  tmp = tmp->from_parent;  }  }  }  if (target_thread) {  e->to_thread = target_thread->pid;  target_list = &target_thread->todo;  target_wait = &target_thread->wait;  } else {  target_list = &target_proc->todo;  target_wait = &target_proc->wait;  }  e->to_proc = target_proc->pid;  /* TODO: reuse incoming transaction for reply */  t = kzalloc(sizeof(*t), GFP_KERNEL);   ...   binder_stats_created(BINDER_STAT_TRANSACTION);  tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);   ...   binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);  t->debug_id = ++binder_last_id;  e->debug_id = t->debug_id;   ...   if (!reply && !(tr->flags & TF_ONE_WAY))  t->from = thread;  else  t->from = NULL;  t->sender_euid = proc->tsk->cred->euid;  t->to_proc = target_proc;  t->to_thread = target_thread;  t->code = tr->code;  t->flags = tr->flags;  t->priority = task_nice(current);  t->buffer = binder_alloc_buf(target_proc, tr->data_size,  tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));   ...   t->buffer->allow_user_free = 0;  t->buffer->debug_id = t->debug_id;  t->buffer->transaction = t;  t->buffer->target_node = target_node;  if (target_node)  binder_inc_node(target_node, 1, 0, NULL);  offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));  if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {   ...   }  if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {   ...   }  if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {   ...   return_error = BR_FAILED_REPLY;  goto err_bad_offset;  }  off_end = (void *)offp + tr->offsets_size;  for (; offp < off_end; offp++) {  struct flat_binder_object *fp;   ...   fp = (struct flat_binder_object *)(t->buffer->data + *offp);  switch (fp->type) {  case BINDER_TYPE_BINDER:  case BINDER_TYPE_WEAK_BINDER: {  struct binder_ref *ref;  struct binder_node *node = binder_get_node(proc, fp->binder);  if (node == NULL) {  node = binder_new_node(proc, fp->binder, fp->cookie);  if (node == NULL) {  return_error = BR_FAILED_REPLY;  goto err_binder_new_node_failed;  }  node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  }   ...   ref = binder_get_ref_for_node(target_proc, node);  if (ref == NULL) {  return_error = BR_FAILED_REPLY;  goto err_binder_get_ref_for_node_failed;  }  if (fp->type == BINDER_TYPE_BINDER)  fp->type = BINDER_TYPE_HANDLE;  else  fp->type = BINDER_TYPE_WEAK_HANDLE;  fp->handle = ref->desc;  binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,  &thread->todo);   ...   } break;   ...   }  }  if (reply) {  BUG_ON(t->buffer->async_transaction != 0);  binder_pop_transaction(target_thread, in_reply_to);  } else if (!(t->flags & TF_ONE_WAY)) {  BUG_ON(t->buffer->async_transaction != 0);  t->need_reply = 1;  t->from_parent = thread->transaction_stack;  thread->transaction_stack = t;  } else {  BUG_ON(target_node == NULL);  BUG_ON(t->buffer->async_transaction != 1);  if (target_node->has_async_transaction) {  target_list = &target_node->async_todo;  target_wait = NULL;  } else  target_node->has_async_transaction = 1;  }  t->work.type = BINDER_WORK_TRANSACTION;  list_add_tail(&t->work.entry, target_list);  tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;  list_add_tail(&tcomplete->entry, &thread->todo);  if (target_wait)  wake_up_interruptible(target_wait);  return;   ...  } 
  • 首先,由于tr->target.handle为0,故执行另一个分支,从而target_node=binder_context_mgr_node;即为Context Manager对应的binder_node,从而target_proc对应的是Context Manager的proc

  • 由于target_thread为NULL,故执行else中的内容,从而将binder_proc数据结构中的todo变量赋给target_list,以指定要执行的任务;同时将target_proc的等待队列赋给target_wait;

  • 变量t是一个指向binder_transactoin结构体的指针

IPC数据发送端与接收端通过struct binder_transaction来收发IPC数据,该结构体的定义如下:

struct binder_transaction
1234567891011121314151617
struct binder_transaction {  int debug_id;  struct binder_work work;  struct binder_thread *from;  struct binder_transaction *from_parent;  struct binder_proc *to_proc;  struct binder_thread *to_thread;  struct binder_transaction *to_parent;  unsigned need_reply:1;  /* unsigned is_dead:1; */ /* not used at the moment */  struct binder_buffer *buffer;  unsigned int code;  unsigned int flags;  long priority;  long saved_priority;  uid_t sender_euid; }; 
  • t->from=thread;中的目的是查找发送IPC数据的进程,以便发送IPC应答数据,在收发Binder数据的第5个阶段中会用到

  • t->code=tr->code;目的是将IPC数据的RPC代码赋给binder_transaction结构体的code变量

  • binder_alloc_buf()函数的作用是分配一块空间,用于从接收端的IPC数据接收缓冲区中复制IPC数据。该接收缓冲空间由接收端在binder_mmap()函数中确定,binder_proc结构体的free_buffers指向该区域

  • copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size);的作用是拷贝RPC数据到binder_buffer结构体的data变量中

至此,Binder数据发送端设置binder_transaction结构体的过程结束了。接下来,接收端将从待机状态中苏醒。并从该结构体中获取数据。

  • 调用binder_get_node()函数,在注册至binder_proc结构体中的Binder节点中,确认当前的Binder节点是否已经存在。由于首次注册,故不存在,从而新建节点。

  • 调用binder_new_node()函数不仅会创建新的binder_node,新生成的节点还会被注册到当前进程的binder_proc结构体中

  • 调用binder_get_ref_for_node()函数,检查指定的Binder节点是否已经存在于指定的binder_proc结构体中。若存在,则返回Binder节点所在的binder_ref结构体,否则新建binder_ref结构体并将指定的Binder节点注册其中,而后将其返回。另外,binder_get_ref_for_node()函数也将binder_ref结构体注册到binder_proc中的refs_by_node中

  • 接下来将BINDER_WORK_TRANSACTION赋值给t->work.type,这个值在第4个阶段会用到。当将type设置为BINDER_WORK_TRANSACTION时,Context Manager从binder_transaction结构体中获取Service Server传递而来的IPC数据,在第4阶段会详细讲解

  • 调用wake_up_interruptible()函数,并使用之前赋值过的target_wait作为参数,将Context Manager从待机状态中唤醒。在接下来的进程调度中,Context Manager将执行第4阶段的相应任务。

1.4 传递Binder数据的阶段3

在传递Binder数据的第1个阶段中,Context Manager通过binder_write_read结构体的read_buffer进入到待机状态中。类似地,Service Server完成写入数据后,在binder_thread_read()中进入待机状态。Service Server将在收发Binder数据的第6个阶段中苏醒,接收IPC应答数据。

1.5 传递Binder数据的阶段4

Context Manager被唤醒后,将执行binder_thread_read()中接下来的动作。如下所示:

1234567891011121314
while(1){  uint32_t cmd;  struct binder_transacton_data tr;  struct binder_work *w;  struct binder_transaction *t=NULL;  if(!list_empty(&proc->todo)&&wait_for_proc_work)  w=list_first_entry(&proc->todo,struct binder_work,entry);  switch(w->type){  case BINDER_WORK_TRANSACTION:{  t=container_of(w,struct binder_transaction,work);  }break;  }  } 
  • 调用list_first_entry()函数,查找Service Server在前面代码中注册的binder_work结构体,并将查找到的binder_work结构体返回。list_first_entry()函数是container_of()函数的引用函数,container_of()函数将根据首个参数查找到包含该参数的结构体的首地址。

  • 若binder_work结构体的type成员变量值为BINDER_WORK_TRANSACTION,则继续调用container_of()函数,查找持有binder_work结构体的binder_transaction结构体

之后,Context Manager通过Service Server创建的binder_transaction结构体获取IPC数据,并将IPC数据保存到binder_transaction_data结构体,以便将IPC数据传递到用户空间中,代码如下所示:

1234
tr.code=t->code; tr.data_size=t->buffer->data_size; //code_1 tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset; 

前面的代码都很好理解,关键是code_1处。内核空间接收Buffer的地址为t->buffer->data,而proc->user_buffer_offset则指用户空间的接收Buffer与内核空间的接收Buffer间的地址偏移。因此tr.data.ptr.buffer保存的是用户空间中接收Buffer的地址。binder_write_read结构体存在于用户空间中,read_buffer是binder_write_read结构体的成员变量,它可以引用保存在tr.data.ptr.buffer所指的用户空间中的IPC数据。在向接收端传递数据时,Binder IPC也采用相同的方法,将内核空间中的数据传递到用户空间中,而不需要调用copy_to_user()函数。通过这种方式,可以避免在内核空间与用户空间之间拷贝数据,从而提升IPC动作的效率。

接下来,就要将binder_transaction_data中的数据传递到用户空间中。从该阶段开始,数据将被保存到Context Manager的read_buffer中,相应的代码如下:

1234567891011
cmd=BR_TRANSACTION; if(put_user(cmd,(uint32_t __user*)ptr))  return -EFAULT; ptr+=sizeof(uint32_t);\ if(copy_to_user(ptr,&tr,sizeof(tr)))  return -EFAULT; if(cmd==BR_TRANSACTION && !(t->flags & TF_ONE_WAY)){  t->to_parent=thread->transaction_stack;  t->to_thread=thread;  thread->transaction_stack=t; } 
  • 首先设置Binder协议为BR_TRANSACTION,准备处理Context Manager的IPC数据

  • *ptr指向binder_write_read结构体的read_buffer成员变量,在传递Binder数据的第1个阶段中,Context Manager在进入待机状态前调用ioctl()函数时,它作为一个参数被传入函数中

  • *ptr指向binder_write_read结构体的read_buffer成员变量

  • 利用copy_to_user()将之前生成的binder_transaction_data结构体拷贝到read_buffer中

  • thread->transaction_stack=t;的目的是将当前的binder_transaction结构体注册到binder_thread结构体的transaction_stack中。binder_transaction结构体在传递Binder IPC数据的第5个阶段中用于查找IPC应答数据的接收端

1.6 传递Binder数据的阶段5

在此阶段中,Context Manager将处理接收到的IPC数据,而后向Service Server发送IPC数据,告知处理已经完成。该阶段 数据传递过程与传递Binder数据的第2个阶段类似,涉及到的Binder协议分别是BC_REPLY(Contxt Manager–>Binder Driver)和BR_REPLY(Binder Driver–>Context Manager).

123456
if(reply){  in_reply_to=thread->transaction_stack;  thread->transaction_stack=in_reply_to->to_parent;  target_thread=in_reply_to->from;  target_proc=target_thread->proc; } 
  • 首先由thread->transaction_stack获取前面刚刚讲解过的注册的binder_transaction结构体

  • 之后由in_reply_to->from获取Service Server的binder_thread结构体

  • 由binder_thread即可获取Service Server的binder_proc,从而可以获得Service Server的接收端Buffer.之后将IPC应答数据保存到binder_transaction中。然后Service Server从待机状态中苏醒,查找相应的结构体,将IPC应答数据传递到用户空间中。由于该吉祥平安福且贵与传递Binder数据的阶段2类似,故不再赘述。

1.7 传递Binder数据的阶段6

Service Server从待机状态中苏醒后,其行为动作与传递Binder数据第4个阶段类似,不同的是所使用的Binder协议为BR_REPLY.Service Server接收完IPC应答数据后将在用户空间中进行一系列与IPC应答数据相关的动作。

2.服务检索阶段

在服务检索阶段,调用binder_ioctl()函数,将服务客户端的IPC数据发送到Context Manager,并将Context Manager的IPC应答数据发送到客户端。

2.1 传递Binder数据的阶段1

该阶段类似注册服务时传递Binder数据的第1个阶段,Context Manager进入待机状态,等待接收IPC数据。

2.2 传递Binder数据的阶段2

在该阶段中Binder Driver的行为动作类似于注册服务时传递Binder数据的第2个阶段。但是发送IPC数据的进程不是Service Server,而是服务客户端。
服务客户端并不注册服务,所以在其RPC数据中不会存在flat_binder_object结构体。在服务客户端生成的IPC数据中包含Context Manager的Handle(0),RPC代码(服务检索函数)以及请求的服务名称。
需要注意的是,由于IPC数据中不包含flag_binder_object对象,所以不会创建binder_node对象。其他动作与服务注册传递Binder的阶段2是一样的。

2.3 传递Binder数据的阶段3
与Service Server类似,服务客户端既发送IPC数据,又接收IPC应答数据,它会使用binder_write_read结构体的write_buffer与read_buffer两个成员变量。同服务注册阶段的传递IPC数据的第3个阶段一样,服务客户端将进入待机状态中,等待接收IPC应答数据。

2.4 传递Bindder数据的阶段4
该阶段与服务注册阶段的阶段4类似。Context Manager接收IPC数据后,会在服务目录中生成binder_object结构体,该结构体中包含着与服务名称相对应的服务目录编号。并且,将结构体中的type变量设置为BINDER_TYPE_HANDLE,生成IPC应答数据。binder_object会被复制到Binder Driver的flat_binder_object中,用来查找Binder节点。在下一个阶段中,通过binder_object数据,将Binder节点传递给服务客户端。

2.5 传递Binder数据的阶段5
在该阶段中,服务客户端将获取所用服务的Binder节点。在服务注册阶段,flat_binder_object结构体的type变量为BINDER_TYPE_BINDER,继而生成Binder节点。但是在服务检索阶段,type为BINDER_TYPE_HANDLE,Binder节点被传递给服务客户端,主要代码如下:

12345678910111213
fp=(struct flat_binder_object*)(t->buffer->data+*offp); switch(fp->type){  case BINDER_TYPE_HANDLE:  case BINDER_TYPE_WEAK_HANDLE:  struct binder_ref*ref=binder_get_ref(proc,fp->handle);  if(ref->node->proc==target_proc){  }  else{  struct binder_ref*new_ref;  new_ref=binder_get_ref_for_node(target_proc,ref->node);  fp->handle=new_ref->desc;  }break; } 
  • 调用binder_get_ref()函数,其第一个参数proc为Context Manager的binder_proc,第二个参数fp->handle是服务客户端要使用的服务编号。服务编号即binder_ref结构体中desc变量的值。将desc的值传入binder_get_ref()函数后,即可获得与服务编号相对应的binder_ref结构体,此结构体由Context Manager持有

  • 调用binder_get_ref_for_node()函数,其中第一个参数target_proc是服务客户端的binder_proc结构体,第二个参数ref->node是ref对应的binder_node对象。在该函数内部,将为接收的binder_node结构体创建新的binder_ref结构体,并将其指向binder_node结构体

  • 修改RPC数据中flat_binder_object结构体内的服务编号,将其设置为当前binder_ref结构体的desc编号。而后在下一个阶段中,将包含修改后的RPC数据的IPC应答数据发送到服务客户端

2.6 传递Binder数据的阶段6

该阶段与服务注册阶段的第6个阶段类似。服务客户端使用IPC应答数据中的Binder节点编号,进入服务使用阶段。

3.服务使用阶段

在服务使用阶段,服务客户端与拥有服务的Service Server进行IPC通信。通过在服务检索阶段获得的Binder节点编号,向Service Server发送IPC数据。在服务使用阶段中,发送IPC数据的进程是服务客户端,而接收端是Service Server.

3.1 传递Binder数据的阶段1

在服务使用阶段,Service Server进入待机状态,等待接收IPC数据。

3.2 传递Binder数据的阶段2

在服务使用阶段中,IPC数据包含与所用服务函数相关的RPC代码与RPC数据。在服务检索传递的Binder数据的第6个阶段中已经获取了服务的Binder节点编号,IPC数据中的Handle即是该Binder节点编号。

该阶段与服务注册的传递Binder数据的第2个阶段类似,但是与binder_transaction()函数查找接收端binder_proc结构体的过程有所不同。

12345678
if(tr->target.handle){  struct binder_ref*ref;  ref=binder_get_ref(proc,tr->target.handle);  target_node=ref->node; }else{  target_node=binder_context_mgr_node; } target_proc=target_node->proc; 

在服务注册阶段,Handle值为0,查找到的是Context Manager的binder_proc结构体;而在服务使用阶段则使用target.handle,查找对应进程的binder_proc结构体。

  • 调用binder_get_ref()函数,查找desc值为指定Handle的binder_ref结构体。查找到指定的结构体后,将binder_ref结构体的node指向Service Server的binder_node结构体

  • binder_node结构体的proc指向Service Server的binder_proc结构体,即接收IPC数据的进程

3.3 传递Binder数据的阶段3

该阶段与服务注册阶段类似,但接收IPC数据的不是Context Manager,而是Service Server. Service Server调用IPC数据中RPC代码所指的函数,并将RPC数据作为参数传入该函数中。此后的过程与Binder服务注册的传递Binder数据的第4,5,6阶段相同,不再赘述.

最后,欢迎大家关注我的微信公众号:AndroidGeek.  AndroidGeek专注于Android源码解析、框架设计、最新技术分享以及职位招聘和内推

Android Binder机制分析(5) Binder_ioctl()分析_第1张图片


更多相关文章

  1. Android activity的DecorView的层次结构
  2. android 3d游戏研究(二)(边学边写,多谢高手指正,鞠躬) :数据库
  3. android 目录结构说明
  4. 基于FFmpeg的音频编码(PCM数据编码成AAC android)
  5. Android利用JDBC连接服务器数据库
  6. Android 本地数据存储 API(二)
  7. Android 数据存储四种方式
  8. 赵雅智_使用sqlite创建数据库
  9. Android利用系统提供的函数或常量判断版本大小

随机推荐

  1. Android(安卓)源码编译
  2. Android中使用listview实现qq/微信好友列
  3. Android中使用ormlite实现持久化--HelloO
  4. Android(安卓)中ShapeDrawable的使用
  5. 图文详解Android属性动画
  6. android读取sim卡联系人
  7. Android 解析jwt遇到java.lang.IllegalAr
  8. 在做Android中GIF遇到不能显示的问题
  9. 谈实现Android定时执行
  10. Android高手应该精通哪些内容?