Android系统服务

  Android框架层提供了本地系统服务和java系统服务,那么这些服务是如何检索的呢,下面简要分析一下这个过程。

一、服务检索 

服务检索是指调用服务的客户端向Context Manager(service manager中第一个注册的节点)请求指定服务的Handle的过程。调用服务的客户端把包含服务请求信息的IPC数据发送给Context Manager,然后Context Manager通过IPC应答数据将指定服务的Handle发送给它。Binder Driver将把调用服务的客户端请求的服务的binder_node结构体注册到客户端的bind_proc结构体中。 

针对上面这段话有三点需要解释一下:

1service_manager如何查找指定服务的handle,如下代码:

struct svcinfo  
{  
    struct svcinfo *next;  
    uint32_t handle;  
    struct binder_death death;  
    int allow_isolated;  
    size_t len;  
    uint16_t name[0];  
};  
  
struct svcinfo *svclist = NULL;  
  
struct svcinfo *find_svc(const uint16_t *s16, size_t len)  
{  
    struct svcinfo *si;  
  
    for (si = svclist; si; si = si->next) {  
        if ((len == si->len) &&  
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {  
            return si;  
        }  
    }  
    return NULL;  
}  

上面就是service_manager.c中的检索服务代码,可以看出service_manager维护一张服务表svclist,可以根据服务名查找对应的结构体svcinfo,这个结构体里面就包含了需要的handle变量

 

2、binder_node是什么?下面是一段服务注册过程中的代码:

扫描二维码关注公众号,回复: 1830560 查看本文章
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);
      }
     ref = binder_get_ref_for_node(target_proc, node);
     fp->handle = ref->desc;
    }
所以 binder_node 就是服务注册时传入的服务对象,其中第一个参数 proc 是代表 Service Server binder_proc ,因为所有的服务实体都是注册到 Service Server ,而后面的 binder_get_ref_for_node 则是将该实体对应的引用注册到 Context Manager ,即 Context Manager 拥有所有服务实体对应的引用,而 Service Server 拥有所有实体

 

3、什么是binder_proc?首先看一下binder_open函数:

static int binder_open(struct inode *nodp, struct file *filp){
  struct binder_proc *proc;
  proc = kzalloc(sizeof(*proc), GFP_KERNEL);
  if(proc == NULL)
    return -ENOMEM;
  get_task_struct(current);
  proc->tsk = current;
  INIT_LIST_HEAD(&proc->todo);
  init_waitqueue_head(&proc->wait);
  proc->default_priority = task_nice(current);
  mutex_lock(&binder_lock);
  binder_stats.obj_created[BINDER_STAT_PROC]++;
  hlist_add_head(&proc->proc_node, &binder_procs);
  proc->pid = current->group_leader->pid;
  INIT_LIST_HEAD(&proc->delivered_death);
  filp->private_data = proc;
  mutex_unlock(&binder_lock);
  if(binder_proc_dir_entry_proc){
    snprintf(strbufm sizeof(strbuf), "%u", proc->pid);
    create_proc_read_entry(strbuf,S_IRUGO,binder_proc_dir_entry_proc,   binder_read_proc_proc, proc);
    return 0;
  }
 ...
}
 
struct binder_proc{
  struct rb_root threads,//拥有binder_thread结构体的红黑树的根
  struct rb_root nodes,//带有binder_node结构体的红黑树的根
  struct rb_root refs_by_desc,//带有binder_ref结构体的红黑树的根,使用desc区分各个binder_ref结构体
  int pid,//创建binder_proc结构体的进程id
  struct vm_area_struct *vms,//调用binder_mmap()函数的进程的用户空间信息(用来保证内核空间内存)
  struct task_struct *tsk,//指生成binder_proc结构体的进程的task_struct结构体
  void *buffer,//接收IPC数据binder_buffer结构体指针
  size_t user_buffer_offset,//映射为接收IPC数据的buffer的内核空间与用户空间的地址偏移量,用来将接收到IPC数据传递到用户空间
  struct list_head buffers,//为接收IPC数据而分配的binder_buffer结构体列表
  struct rb_root free_buffers,//接收IPC数据后要释放的binder_buffer结构体列表
  size_t buffer_size,//进程在内核空间开辟的buffer大小
  struct list_head todo,//进程从待机状态唤醒后要做的事情
  wait_queue_head_t wait//用来让进程进入待机状态
}

从上面函数可以看出每个进程调用binder_open都会生成自己的binder_proc,从binder_proc结构体可以看出进程间通信主要是靠每个进程在内核空间开辟的一块buffer,通信时一方会把自己的数据传到自己开辟的Buffer里面,然后binder driver负责将这些数据拷贝到目标进程的buffer里,然后唤醒目标进程处理数据就行了。 

 

服务检索过程

1) Context Manager进入待机状态,等待接收IPC数据。

2) 调用服务的客户端生成并初始化binder_proc结构体,而后开辟一块buffer用于接收IPC应答数据

3) 调用服务的客户端通过ioctl()调用binder driverbinder_ioctl()函数。与注册服务时一样,binder driver会查找Context Managerbinder_proc结构体。但与注册服务不同的是,它并不生成binder_node结构体,只是将IPC数据拷贝到Context Manager的接收buffer中。并且记下调用服务客户端的binder_proc结构体,以便查找IPC应答数据的接收端。

4) Binder driver让调用服务的客户端处于待机状态,并唤醒处于待机状态的Context Manager,而后接收IPC数据。从待机状态苏醒的Context Manager在服务目录中查找请求的服务,把服务编号插入到IPC应答数据中,并把IPC应答数据传递给binder driver.

5) Binder dirver将(4)中接收到服务编号查找相应的binder_node结构体(先查找对应结构体的引用,引用里的一个属性就是binder_node),而后将查找到binder_node结构体注册到调用服务的客户端的binder_proc中。binder_node结构体用于在调用服务时查找Service Serverbinder_proc结构体.

6) Binder driver将(5)中注册的binder_node结构体的编号插入到IPC应答数据中,传递给客户端,然后唤醒客户端。在使用服务时,客户端将编号作为handle使用。 

 

二、服务使用 

经过服务检索,客户端获得了Service Server所拥有服务的binder_node,在生成IPC数据时,它就可以把要使用服务的binder节点编号设置到IPC数据的handle中,取代原来值为0handle

 

服务使用过程

7) Service Server处于待机状态,等待接收IPC数据。

8) 客户端将从服务检索中获取的binder节点编号保存到IPC数据的handle中,生成IPC数据后传递给binder driverbinder driver根据IPC数据中的handle查找相应的binder_node结构体,并据此查找到注册有binder_node结构体的Service Serverbinder_proc结构体。然后,通过注册在binder_proc结构体中binder_buffer结构体,将IPC数据拷贝到buffer中。

9) Binder driver让客户端进入待机状态,唤醒处于待机状态的Service ServerService Server从待机状态苏醒后接受IPC数据,并通过IPC数据中的RPC代码、RPC数据调用相应的服务函数。

10) 在服务函数执行完毕后,Service Server会生成IPC应答数据,并将其传递给binder driverbinder driver执行的动作与服务注册阶段相同,将IPC数据传递给客户端。至此,客户端调用服务的整个IPC过程就完成了。


三、其他

android context.getSystemService方法获取的是注册在SystemServiceRegistry里面的服务,里面的服务有的是来自系统服务,有的不是,比如Context.WINDOW_SERVICE就不是系统的,而是return new WindowManagerImpl(ctx);



 

猜你喜欢

转载自blog.csdn.net/u012292247/article/details/71162244