Binder源码分析之ServiceManager(原)

来源:互联网 发布:2016年3月非农数据 编辑:程序博客网 时间:2024/05/21 09:22
        ServiceManager作为Native层Service的管理员,有着极其重要的作用,主要表现两个方面:
        1、对于服务端来说,系统所有的服务提供者都需要向ServiceManager注册。
        2、对于客户端来说,所有客户端如果想要获得某个系统服务的代理,必须向ServiceManager申请相应的服务端代理。

        下面从源码分析ServiceManager的启动流程和服务流程。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. @Service_manager.c(frameworks/base/cmds/servicemanager)  
  2. int main(int argc, char **argv) {  
  3.     struct binder_state *bs;  
  4.     void *svcmgr = BINDER_SERVICE_MANAGER;  
  5.     //打开binder设备  
  6.     bs = <span style="color:#ff0000;">binder_open</span>(128*1024);  
  7.     //成为Service manager  
  8.     if (<span style="color:#ff0000;">binder_become_context_manager</span>(bs)) {  
  9.         LOGE("cannot become context manager (%s)\n", strerror(errno));  
  10.         return -1;  
  11.     }  
  12.     svcmgr_handle = svcmgr;  
  13.     //在binder_loop中循环检测binder中是否有新的请求  
  14.     <span style="color:#ff0000;">binder_loop</span>(bs, svcmgr_handler);  
  15.     return 0;  
  16. }  
        main函数主要有三个功能:
        1、打开Binder设备文件;
        2、告诉Binder驱动程序自己是Binder上下文管理者;
        3、进入一个死循环,充当Service的角色,等待Client的请求。

        下面我们就分别介绍这三个步骤。


一、打开Binder设备

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. @binder.c(\frameworks\base\cmds\servicemanager\)  
  2. struct binder_state *binder_open(unsigned mapsize) {  
  3.     //创建binder_state结构体并分配内存  
  4.     struct binder_state *bs;  
  5.     bs = malloc(sizeof(*bs));  
  6.     //打开binder设备  
  7.     bs->fd = open("/dev/binder", O_RDWR);  
  8.     bs->mapsize = mapsize;  
  9.     //将binder物理空间映射为ServiceManager可用的虚拟空间  
  10.     bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);  
  11.     //将结构体返回给servicemanager  
  12.     return bs;  
  13. }  
        上面打开Binder设备的过程其实就是构建一个binder_state结构体对象,然后对其各个成员初始化的过程。我们来看一下binder_state数据结构:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. struct binder_state {  
  2.     //文件描述符,这里指的是/dev/binder设备文件描述符  
  3.     int fd;  
  4.     //把设备文件/dev/binder映射到进程空间的起始地址,这里就是128*1024  
  5.     void *mapped;  
  6.     //映射的空间大小  
  7.     unsigned mapsize;  
  8. };  
        这个结构体只有三个成员变量,其中fd是底层binder设备的文件描述符,mapped是ServiceManager得到的虚拟空间地址,这块虚拟空间映射了底层binder的物理地址,而mapsize是这块虚拟空间的大小,也就是128*1024。
        从上面可以看出,打开Binder的过程的过程分为两步:
        1、打开Binder设备;

        2、用Binder的物理地址映射为ServiceManager可用的虚拟地址;


二、ServiceManager成为服务管理员的过程

        在Android中,每个注册的Service,Binder都会给他分配一个唯一的int型的句柄,Client可以用该句柄向ServiceManager请求相应的Service,而负责这个管理任务的正是ServiceManager。也就是说,Service需要先向ServiceManager注册自己,并得到自己的服务句柄,然后Client需要拿这个int型的句柄向ServiceManager请求相应的Service,ServiceManager再把相应的Service代理对象发送给Client使用
        同时我们注意到,ServiceManager本身也是一个Service,他需要先向Binder注册自己,而且要把自己注册为“管理员”,那么这个注册过程是怎样的呢?我们来看源码:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int binder_become_context_manager(struct binder_state *bs)  
  2. {  
  3.     //向Binder驱动发送BINDER_SET_CONTEXT_MGR的消息  
  4.     return ioctl(bs->fd, <span style="color:#ff0000;">BINDER_SET_CONTEXT_MGR</span>, 0);  
  5. }  

    我们看到,当ServiceManager向Binder驱动发送BINDER_SET_CONTEXT_MGR的消息时,Binder就会把他注册为“管理员”


三、Service_manager服务过程

3.1、Service_manager的执行流程

        经过前面两步的操作,我们不仅打开了Binder,而且把当前的ServiceManager注册成为了管理员,下面要做的就是去承担管理员的职责,也就是接收各种请求
        这一步的入口是binder_loop():
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. void binder_loop(struct binder_state *bs, binder_handler func) {  
  2.     int res;  
  3.     struct binder_write_read bwr;  
  4.     unsigned readbuf[32];  
  5.     bwr.write_size = 0;  
  6.     bwr.write_consumed = 0;  
  7.     bwr.write_buffer = 0;  
  8.     readbuf[0] = BC_ENTER_LOOPER;  
  9.     //告诉Binder,ServiceManager将要进入LOOPER状态了  
  10.     binder_write(bs, readbuf, sizeof(unsigned));  
  11.   
  12.     for (;;) {  
  13.         //准备要发送的数据  
  14.         bwr.read_size = sizeof(readbuf);  
  15.         bwr.read_consumed = 0;  
  16.         bwr.read_buffer = (unsigned) readbuf;  
  17.         //与底层Binder通讯,得到客户端的请求  
  18.         res = <span style="color:#ff0000;">ioctl</span>(bs->fd, BINDER_WRITE_READ, &bwr);  
  19.         //用func解析请求并构建应答返回给客户端  
  20.         res = <span style="color:#ff0000;">binder_parse</span>(bs, 0, readbuf, bwr.read_consumed, <span style="color:#ff0000;">func</span>);  
  21.     }  
  22. }  
        上面的过程表明了Service_manager进入循环的过程,主要分为三个步骤:
        1、先通过发送BC_ENTER_LOOPER消息告诉底层,ServiceManager将要进入循环了;
        2、在死循环中读取客户端的请求;
        3、处理请求;

        上面的第一步是通过向Binder发送BC_ENTER_LOOPER消息实现的,第二步通过BINDER_WRITE_READ可以读取Binder中的数据(请求);第三步需要调用binder_parse去处理客户端的请求,我们主要看一下这个过程。

3.2、ServiceManager处理请求并回应客户端的过程

        ServiceManager是通过binder_parse()的函数来处理请求的:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int binder_parse(struct binder_state *bs,struct binder_io *bio,uint32_t *ptr,uint32_t size,binder_handler func){  
  2.     while (ptr < end) {  
  3.         uint32_t cmd = *ptr++;  
  4.         switch(cmd) {  
  5.             case BR_NOOP:  
  6.             case BR_TRANSACTION_COMPLETE:  
  7.             case BR_INCREFS:  
  8.             case BR_ACQUIRE:  
  9.             case BR_RELEASE:  
  10.             case BR_DECREFS:  
  11.                 break;  
  12.             <span style="color:#ff0000;">case BR_TRANSACTION</span>: {  
  13.                 struct binder_txn *txn = (void *) ptr;  
  14.                 binder_dump_txn(txn);  
  15.                 if (func) {  
  16.                     unsigned rdata[256/4];  
  17.                     struct binder_io msg;  
  18.                     struct binder_io reply;  
  19.                     bio_init(&reply, rdata, sizeof(rdata), 4);  
  20.                     bio_init_from_txn(&msg, txn);  
  21.                     //调用service_manager.c中的svcmgr_handler去处理数据  
  22.                     res = func(bs, txn, &msg, &reply);  
  23.                     //将Service_manager对客户端的回应数据(reply)返回给Binder驱动  
  24.                     binder_send_reply(bs, &reply, txn->data, res);  
  25.                 }  
  26.                 ptr += sizeof(*txn) / sizeof(uint32_t);  
  27.                 break;  
  28.             }  
  29.             case BR_REPLY:   
  30.             case BR_DEAD_BINDER:   
  31.             case BR_FAILED_REPLY:  
  32.             case BR_DEAD_REPLY:  
  33.             default:  
  34.         }  
  35.     }  
  36.     return r;  
  37. }  
        这个函数中我们只关心BR_TRANSACTION分支,通过调用func去解析拿到的请求,然后把返回值作为回应通过binder_send_reply()函数返回给客户端。

3.2.1、处理请求过程

        我们先来看一下请求的处理过程,也就是func()的流程,这里的func来自于调用binder_loop()时的参数:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. binder_loop(bs, svcmgr_handler);  
        因此func()就是svcmgr_handler():
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int svcmgr_handler(struct binder_state *bs,struct binder_txn *txn,struct binder_io *msg,struct binder_io *reply){  
  2.     switch(txn->code) {  
  3.         case SVC_MGR_GET_SERVICE:  
  4.         case SVC_MGR_CHECK_SERVICE:  
  5.             //得到一个Service  
  6.             s = bio_get_string16(msg, &len);  
  7.             ptr = do_find_service(bs, s, len, txn->sender_euid);  
  8.             bio_put_ref(reply, ptr);  
  9.             return 0;  
  10.   
  11.         case SVC_MGR_ADD_SERVICE:  
  12.             //添加一个Service  
  13.             s = bio_get_string16(msg, &len);  
  14.             ptr = bio_get_ref(msg);  
  15.             allow_isolated = bio_get_uint32(msg) ? 1 : 0;  
  16.             if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))  
  17.                 return -1;  
  18.             break;  
  19.   
  20.         case SVC_MGR_LIST_SERVICES: {  
  21.             //得到当前所有的Service  
  22.             unsigned n = bio_get_uint32(msg);  
  23.   
  24.             si = svclist;  
  25.             while ((n-- > 0) && si)  
  26.                 si = si->next;  
  27.             if (si) {  
  28.                 bio_put_string16(reply, si->name);  
  29.                 return 0;  
  30.             }  
  31.             return -1;  
  32.         }  
  33.     }  
  34.     return 0;  
  35. }  
        从svcmgr_handler的case分支我们可以看出,作为Service_manager主要完成三个功能:
        1、得到一个Service;
        2、添加一个Service;
        3、列出所有的Service;

        下面我们分别看一下这三个功能的实现方式,我们先从add一个Service开始:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int do_add_service(struct binder_state *bs,uint16_t *s,unsigned len,void *ptr,unsigned uid,int allow_isolated) {  
  2.     struct svcinfo *si;  
  3.     //检查当前注册的Service的uid和注册的服务名称是否有权限  
  4.     if (!svc_can_register(uid, s)) {  
  5.         return -1;  
  6.     }  
  7.     //查看是否已经add过了  
  8.     si = find_svc(s, len);  
  9.     if (si) {  
  10.         if (si->ptr) {  
  11.             svcinfo_death(bs, si);  
  12.         }  
  13.         si->ptr = ptr;  
  14.     } else {  
  15.         si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));  
  16.         si->ptr = ptr;  
  17.         si->len = len;  
  18.         memcpy(si->name, s, (len + 1) * sizeof(uint16_t));  
  19.         si->name[len] = '\0';  
  20.         si->death.func = svcinfo_death;  
  21.         si->death.ptr = si;  
  22.         si->allow_isolated = allow_isolated;  
  23.         si->next = svclist;  
  24.         //把当前需要注册的Service添加到svclist中,完成注册过程  
  25.         svclist = si;  
  26.     }  
  27. }  
        从add的过程可以看出,所谓向ServiceManager注册一个服务,其实就是为当前的Service创建svcinfo的结构体,并把该结构体添加到svclist中
        那么我们可以推测,find的过程无非就是去svclist中查找svcinfo的过程:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid) {  
  2.     struct svcinfo *si;  
  3.     //从svclist链表中得到当前请求的Service信息  
  4.     si = find_svc(s, len);  
  5.     if (si && si->ptr) {  
  6.         //得到一个Service需要这个Service的许可  
  7.         if (!si->allow_isolated) {  
  8.             //还要检查申请者的uid是否匹配  
  9.             unsigned appid = uid % AID_USER;  
  10.             if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {  
  11.                 return 0;  
  12.             }  
  13.         }  
  14.         return si->ptr;  
  15.     } else {  
  16.         return 0;  
  17.     }  
  18. }  
        这个过程确实如我们所料,需要通过find_svc()在svclist中寻找需要的Service并把该Service节点发送给请求的Client。
        那么list Service的请求只需要把svclist返回给Client即可:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. case SVC_MGR_LIST_SERVICES: {  
  2.     unsigned n = bio_get_uint32(msg);  
  3.   
  4.     si = svclist;  
  5.     while ((n-- > 0) && si)  
  6.         si = si->next;  
  7.     if (si) {  
  8.         //把svclist返回给请求者  
  9.         bio_put_string16(reply, si->name);  
  10.         return 0;  
  11.     }  
  12.     return -1;  
  13. }  
        经过这些过程,ServiceManager就完成了解析数据的过程,下面就需要把相应的数据返回给客户端。

3.2.2、回应客户端的过程

        在3.2.1中的三个请求处理过程中,特别是get和list Service的请求,最终都需要给客户端相应回应的,我们看到在这两个请求的处理最后,都将相应的回应数据放入了reply的指针中,当从svcmgr_handler()返回后,就把数据带到了binder_parse()中,我们再来回顾一下这里的代码:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int binder_parse(struct binder_state *bs,struct binder_io *bio,uint32_t *ptr,uint32_t size,binder_handler func){  
  2.     while (ptr < end) {  
  3.         switch(cmd) {  
  4.             case BR_TRANSACTION: {  
  5.                 struct binder_txn *txn = (void *) ptr;  
  6.                 binder_dump_txn(txn);  
  7.                 if (func) {  
  8.                     //reply就是svcmgr_handler()中得到的回应  
  9.                     res = func(bs, txn, &msg, &reply);  
  10.                     //将回应数据(reply)返回给Binder驱动  
  11.                     binder_send_reply(bs, &reply, txn->data, res);  
  12.                 }  
  13.                 ptr += sizeof(*txn) / sizeof(uint32_t);  
  14.                 break;  
  15.             }  
  16.         }  
  17.     }  
  18.     return r;  
  19. }  
        在binder_parse()中又调用binder_send_reply()函数完成回应的操作:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. void binder_send_reply(struct binder_state *bs, struct binder_io *reply, void *buffer_to_free, int status) {  
  2.     struct {  
  3.         uint32_t cmd_free;  
  4.         void *buffer;  
  5.         uint32_t cmd_reply;  
  6.         struct binder_txn txn;  
  7.     } __attribute__((packed)) data;  
  8.   
  9.     data.cmd_free = BC_FREE_BUFFER;  
  10.     data.buffer = buffer_to_free;  
  11.     data.cmd_reply = BC_REPLY;  
  12.     data.txn.target = 0;  
  13.     data.txn.cookie = 0;  
  14.     data.txn.code = 0;  
  15.     if (status) {  
  16.         data.txn.flags = TF_STATUS_CODE;  
  17.         data.txn.data_size = sizeof(int);  
  18.         data.txn.offs_size = 0;  
  19.         data.txn.data = &status;  
  20.         data.txn.offs = 0;  
  21.     } else {  
  22.         data.txn.flags = 0;  
  23.         data.txn.data_size = reply->data - reply->data0;  
  24.         data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0);  
  25.         data.txn.data = reply->data0;  
  26.         data.txn.offs = reply->offs0;  
  27.     }  
  28.     //向Binder写回应的数据  
  29.     binder_write(bs, &data, sizeof(data));  
  30. }  
        在给Binder发送返回值时,构建了data的数据,并把reply放入其中,并标记了数据的大小,最后通过binder_write()函数将数据写到Binder中,而且写的方法仍然是调用ioctl()。
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int binder_write(struct binder_state *bs, void *data, unsigned len) {  
  2.     struct binder_write_read bwr;  
  3.     int res;  
  4.     bwr.write_size = len;  
  5.     bwr.write_consumed = 0;  
  6.     bwr.write_buffer = (unsigned) data;  
  7.     bwr.read_size = 0;  
  8.     bwr.read_consumed = 0;  
  9.     bwr.read_buffer = 0;  
  10.     //向Binder写数据  
  11.     res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  
  12.     if (res < 0) {  
  13.         fprintf(stderr,"binder_write: ioctl failed (%s)\n", strerror(errno));  
  14.     }  
  15.     return res;  
  16. }  

        经过以上步骤,就完成了一次完整的请求调用过程。


四、总结

        我们用两张图来总结ServiceManager提供服务的过程。

4.1、ServiceManager初始化流程



4.2、ServiceManager处理事务的流程



原文地址:http://blog.csdn.net/u010961631/article/details/19838637

0 0
原创粉丝点击