现在的位置: 首页 > 综合 > 正文

Binder机制之Service Manager(大内总管)

2018年06月10日 ⁄ 综合 ⁄ 共 6579字 ⁄ 字号 评论关闭

一、Service Manager是android系统核心程序,在系统启动后,自动运行,在系统的初始化配置文件init.rc中配置

该文件在out/target/product/generic/root,文件中有如下内容:

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart zygote
    onrestart restart media

二、Service Manager的如何成为大内总管的源代码分析

源码位于frameworks\base\cmds\servicemanager\service_manager.c

1、代表Binder设备的结构

struct binder_state
{
    int fd;           //设备描述符                  
    void *mapped;     //设备内存映射区指针
    unsigned mapsize; //内存映射区大小
};

2、打开设备

struct binder_state *binder_open(unsigned mapsize)
{
    struct binder_state *bs;               //binder设备结构
    bs = malloc(sizeof(*bs));              //分配空间
    bs->fd = open("/dev/binder", O_RDWR);  //打开设备    
    bs->mapsize = mapsize;                 //空间大小赋值
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//设备文件映射进内存,并返回映射区指针
 
}

3、大内总管申请函数

int binder_become_context_manager(struct binder_state *bs)
{  
   //ioctl是binder驱动程序提供的设备控制函数,传递BINDER_SET_CONTEXT_MGR这个参数,告诉驱动,我这个节点要成为管理者
   return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

4、驱动控制函数ioctl

Binder驱动源代码目录:kernel/goldfish/drivers/staging/android

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
        //系统允许多个进程打开binder驱动,都会有一个专门的结构binder_proc管理当前进程的信息,
        //包括进程的ID,当前进程由mmap所映射出的buffer信息,以及当前进程所允许的最大线程量。
        //同时这个binder_proc会加入到系统的全局链表binder_procs中去,方便在不同进程之间可以查找信息。
        struct binder_proc *proc = filp->private_data;//获得了Service Manager进程进程信息
	
        //在当前进程下存在多线程,因此binder驱动使用binder_thread来管理对应的线程信息,
        //主要包括线程所属的binder_proc、当前状态looper以及一个transaction_stack(负责着实际进程间通信交互的源头和目的地)
        struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;

        //获得了Service Manager线程信息
	thread = binder_get_thread(proc);
	
        //处理控制命令
	switch (cmd) 
       {
             //读写命令,则进行读写操作
             case BINDER_WRITE_READ: 
             { ...
		break;
	      }
	     case BINDER_SET_MAX_THREADS:		
		break;
	     
             //请求成为Service Manager命令
             case BINDER_SET_CONTEXT_MGR:
		if (binder_context_mgr_node != NULL)
                {//已经存在则返回错误
		   printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");		
		}
		if (binder_context_mgr_uid != -1) 
                {//其他的判断
		   ....	
		} 
               else
		 binder_context_mgr_uid = current->cred->euid;//设置Sevice Manager守护进程的uid
		 //创建一个新的Service Manager实体节点
                 binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
		//添加节点信息
		 binder_context_mgr_node->local_weak_refs++;
		 binder_context_mgr_node->local_strong_refs++;
		 binder_context_mgr_node->has_strong_ref = 1;
		 binder_context_mgr_node->has_weak_ref = 1;
		break;
	case BINDER_THREAD_EXIT://线程退出命令
		break;
	case BINDER_VERSION://版本信息命令
		
		break;
	default:
		ret = -EINVAL;
		goto err;
	}

}

5、main函数分析:

int main(int argc, char **argv)
{
    struct binder_state *bs;//binder设备结构
    void *svcmgr = BINDER_SERVICE_MANAGER; //服务管理指针

    bs = binder_open(128*1024);//打开binder设备,并分配128K的内存映射空间
    //申请成为大内总管
    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

//调用binder_loop进入到循环状态,并提供了一个回调函数,等待用户的请求
    //用户请求包括,客户端:查询和获取服务;服务端:注册服务
    svcmgr_handle = svcmgr; //回调函数指针
    
//binder消息分发的关键循环,循环等待请求,回调函数svcmgr_handler
 binder_loop(bs, svcmgr_handler);
    return 0;
}

6、binder_loop函数分析

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    unsigned readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    
  //通过binder_write函数执行BC_ENTER_LOOPER命令告诉Binder驱动程序, Service Manager要进入循环了
    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(unsigned));

    for (;;) 
    {//一直循环下去,为所有service工作
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;
        

// 一般阻塞再此,直到有消息送达,等待有客户端的通过binder驱动的请求
//与binder驱动对话,先写再读,不过这里写的size为0(bwr.write_size = 0),所以这里是只读binder端的数据 
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
//分析读回来的数据,记住这里的func传入的参数是svcmgr_handler
 res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func); }}


我们再看binder_parse(bs, 0, readbuf, bwr.read_consumed, func):

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uint32_t *ptr, uint32_t size, binder_handler func)
{
    int r = 1;
    uint32_t *end = ptr + (size / 4);
   
    //循环解析由binder驱动传递过来的命令
    while (ptr < end) 
    {  
        //循环取得一个命令
        uint32_t cmd = *ptr++;
        
        //对各种命令进行处理
        switch(cmd)
        {
           case BR_NOOP:
              break;
           case BR_TRANSACTION_COMPLETE:
            break;
           case BR_INCREFS:
           case BR_ACQUIRE:
           case BR_RELEASE:
           case BR_DECREFS:
           
           //当是这个命令时,调用回调函数svcmgr_handler      
           case BR_TRANSACTION: 
           {
             struct binder_txn *txn = (void *) ptr;           
             binder_dump_txn(txn);
             if (func) 
             {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn);
 
                //终于在此调用回调处理函数了
                res = func(bs, txn, &msg, &reply);
                binder_send_reply(bs, &reply, txn->data, res);
             }
              ptr += sizeof(*txn) / sizeof(uint32_t);
              break;
           }
        ...
        }
    }

    return r;
}

三、服务器程序如何向Service Manager注册服务

当server向binder设备写入请求注册Service时,main函数中的binder_loop循环,会获取到该server程序通过binder驱动发来的请求,通过解析binder_parse函数调用回调函数svrmgr_handle,这个函数是服务管理器各种请求的处理函数,看下这个函数:

int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    //省略部分代码
    switch(txn->code)
    {
      //获取服务和查询服务  
      case SVC_MGR_GET_SERVICE:
      case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len);
        if (!ptr)
            break;
        bio_put_ref(reply, ptr);
        return 0;
      
      //添加注册服务
      case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = bio_get_ref(msg);
        //调用添加服务函数
        if (do_add_service(bs, s, len, ptr, txn->sender_euid))
            return -1;
        break;

       //服务列表
       case SVC_MGR_LIST_SERVICES: 
       {
        unsigned n = bio_get_uint32(msg);

        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
      }  
    }
}

服务器的注册,通过do_add_service函数来实现,我们仔细看看do_add_service函数的实现

int do_add_service(struct binder_state *bs,
                   uint16_t *s, unsigned len,
                   void *ptr, unsigned uid)
{
      struct svcinfo *si;//要注册的service信息结构
      
     //首先检查是否有权限注册service,没权限就对不起了,出错返回
      if (!svc_can_register(uid, s)) //根据进程的uid来判断是否是服务
      {
        return -1;
      }
  
      //然后检查是否已经注册过,注册过的service将不能再次注册
       si = find_svc(s, len);
       if (si) 
       {
          if (si->ptr) 
          {
               svcinfo_death(bs, si);
          }
        si->ptr = ptr;
       } 
       else //否则的话可以进行注册
       {
          //然后构造一个svcinfo对象,并加入一个全局链表中svclist中
          si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));       
          si->ptr = ptr;
          si->len = len;
          memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
          si->name[len] = '\0';
          si->death.func = svcinfo_death;
          si->death.ptr = si;
          si->next = svclist;
          svclist = si;
      }
      
    //最后通知binder设备:有一个service注册进来
     binder_acquire(bs, ptr);
     binder_link_to_death(bs, ptr, &si->death);
     return 0;
}

四、客户端程序如何获取服务

当客户端程序向binder设备写入查询service的请求后,main函数中的binder_loop循环,会获取到该client程序通过binder驱动发来的请求,通过解析binder_parse函数调用回调函数svrmgr_handle,回调函数中有如下代码:

 //查询获取服务
  case SVC_MGR_GET_SERVICE:
  case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len);
        if (!ptr)
            break;
      //如果查找到的话,写入reply中返回给客户端  
      bio_put_ref(reply, ptr);
        return 0;

通过do_find_service函数,查询获取服务,代码如下:

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
{
    struct svcinfo *si;
    si = find_svc(s, len);

    if (si && si->ptr)
    {
        return si->ptr;
    }
   else
   {
        return 0;
    }
}

   总结:

   Service Manager是成为守护进程的过程是这样的:

        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担负起守护进程的职责了。

抱歉!评论已关闭.