Service Manager

上篇文章android binder机制之--(我是binder)介绍了binder机制的概念,特点,应用模式和框架组成,这篇文章我们来介绍一下Android系统Binder机制的服务总管--Service Manager,service Manager在android binder机制中的低位那是相当重要了,所有的Server(System Server)都需要向他注册,应用程序需要向其查询相应的服务。

Service Manager这么厉害,那也不是谁都能成为这位大管家的。要想成为Service Manager,那自然要有两把刷子,下面就来分析这位服务管家是如何诞生的。我这里没有画出流程图,所以只能以代码展示出来了,因为每个文件都有很多代码,所以我只贴出重要的部分,说到哪里,就贴出哪里的代码,(你也可以参考源码来分析)这样会更容易理解所说的内容。在Android系统中,Service Manager的源码位于:

frameworks\base\cmds\servicemanager\service_manager.c

int main(int argc, char **argv)

{

struct binder_state *bs;/*定义一个binder驱动结构表示驱动状态的一个数据结构,里面记录了打开驱动的句柄即文件描述符,分配的内存空间以及内存空间的大小。*/

void *svcmgr = BINDER_SERVICE_MANAGER; /*服务管理进程的句柄被定义为0,如下所示:#define BINDER_SERVICE_MANAGER ((void*) 0)*/

bs = binder_open(128*1024);

if (binder_become_context_manager(bs)) {

LOGE("cannot become context manager (%s)\n", strerror(errno));

return -1;

}

svcmgr_handle = svcmgr;

binder_loop(bs, svcmgr_handler);

return 0;

}

没错,你看到了,这就是传说中的main函数,这说明ServiceManager就是一个进程,如果你不相信,在android的启动脚本init.rc里,我们可以找到答案:

service servicemanager /system/bin/servicemanager #一个系统服务服务

user system #用户

critical

onrestart restart zygote

onrestart restart media

上面的启动代码说明ServiceManager是Android的核心程序,可执行文件就是/system/bin/servicemanager,开机后就会自动运行。main函数是一个进程的入口,下面就让我从进程的入口出分析这段代码吧!我们以函数的调用流程为主线,来介绍Service Manager,会列出主要数据结构的定义。

(1)binder_open()

我们看到它先调用binder_open()函数,这个函数的主要功能:打开binder设备(/dev/binder),然后将该文件映射到内存中,并返回这块内存的首地址。这样我们就可以像操作内存一样,来操作这个文件了。

struct binder_state *binder_open(unsigned mapsize)

{

struct binder_state *bs;

bs = malloc(sizeof(*bs)); /*向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。void* 类型可以强制转换为任何其它类型的指针。*/

if (!bs) {

errno = ENOMEM;

return 0;

}

bs->fd = open("/dev/binder", O_RDWR); /*打开/dev/binder设备节点,返回一个文件描述符,这个描述符很重要,在后面的通讯中会频繁用到*/

if (bs->fd < 0) {

fprintf(stderr,"binder: cannot open device (%s)\n",

strerror(errno));

goto fail_open;

}

bs->mapsize = mapsize;

bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);

/*将一个文件或者其它对象映射进内存,NULL表示映射区的开始地址;mapsize 表示映射区的长度;PROT_READ为期望的内存保护标志,表示页内容可以被读取;MAP_PRIVATE 为指定映射对象的类型;bs->fd表示有效的文件描述符;0表示被映射对象内容的起点。*/

if (bs->mapped == MAP_FAILED) {

fprintf(stderr,"binder: cannot map device (%s)\n",

strerror(errno));

goto fail_map;

}

/* TODO: check version */

return bs;

fail_map:

close(bs->fd);// 关闭文件句柄关闭文件描述符

fail_open:

free(bs);//释放内存

return 0;

}

binder_state是表示驱动状态的一个数据结构,里面记录了打开驱动的句柄即文件描述符,分配的内存空间以及内存空间的大小。我们看看它的定义:

frameworks\base\cmds\servicemanager\binder.c

struct binder_state

{

int fd; //设备文件描述符

void *mapped; //文件映射的内存地址

unsigned mapsize; //文件映射内存的大小

};

(2)binder_become_context_manager()

就是这个函数使他自己变为了android binder机制的服务管家,其代码如下:

frameworks\base\cmds\servicemanager\binder.c

int binder_become_context_manager(struct binder_state *bs)

{

return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);

/*发送设置服务管家的命令到binder驱动,binder驱动做相应的处理,使其成为服务大管家,这里对binder的驱动部分不做详细介绍了*/

}

binder.c文件也是framework框架的内容,它是与binder驱动交互的接口。

这个函数通知binder kernel驱动程序这个进程将作为SystemService Manager,使它自己变为了Server管理者,告诉Binder Kernel驱动程序这是一个服务管理进程。ioctl函数对BINDER_SET_CONTEXT_MGR的具体底层操作不做详细介绍,我们只要知道驱动为我们做了什么事就好:设置驱动中的全局变量binder_context_mgr_uid为当前进程的uid,并初始化一个binder_node赋值给全局变量binder_context_mgr_node。完成了注册Service Manager的工作。

(3)binder_loop()

从上一篇文章可以看出Service Manager是一个系统守护进程,作为一个Server大总管,本身也是一个server,它管理着系统的各个服务。

既然是一个server就要时刻准备为客户端提供服务,可不能忘了自己的责任那!它负责监听是否有其他程序向其发送请求,如果有请求就响应。每个服务都要在ServiceManager中注册,而请求服务的客户端去ServiceManager请求服务。要是Service Manager能调用一个循环函数进入到循环状态,再提供一个回调处理函数,用于处理不同的请求那就好了!

没错,这个服务大管家就是这么干的,Binder_loop()就是这个守护进程的核心—循环体,而svcmgr_handler()就是这个回调函数。

这里多说一句,有木有想过服务端和客户端是怎么与Service Manager通讯,请求服务的呢?实际上它们需要在自己进程中创建一个服务代理,才能与服务管家通讯,那么客户端(对于Serivce Manger来说,我们所说的)怎样它的才能怎样生成他的服务代理对象呢?答案是binder设备(/devbinder)为每一个服务维护一个句柄,调用binder_become_context_manager函数变为“Server大总管”的服务,他的句柄永远是0,是一个“众所周知”的句柄,这样每个程序都可以通过binder机制在自己的进程空间中创建一个Service Manager代理对象了。其他的服务在binder设备在设备中的句柄是不定的,需要向“Server大总管”查询才能知道。

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;

readbuf[0] = BC_ENTER_LOOPER; //控制命令

binder_write(bs, readbuf, sizeof(unsigned));

for (;;) {

bwr.read_size = sizeof(readbuf);

bwr.read_consumed = 0;

bwr.read_buffer = (unsigned) readbuf;

//通过设备描述符,将数据发给binder驱动

res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

if (res < 0) {

LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));

break;

}

//解析驱动发来的数据,调用回调函数func

res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);

if (res == 0) {

LOGE("binder_loop: unexpected reply?!\n");

break;

}

if (res < 0) {

LOGE("binder_loop: io error %d %s\n", res, strerror(errno));

break;

}

}

}

Binder_loop()中传递了一个回调函数,这个回调函数在binder_parse()函数中被调用,用来处理驱动发来的消息,消息的解析这里就不介绍了,我们重点看看这个回调函数都干了什么?

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;

……

……

return 0;

}

从上面的代码很容易看出,守护进程(服务管家)循环从binder设备文件读取数据,然后解析并响应请求,包括服务端的添加服务请求和客户端的查询,获取服务的请求。现在有两个主要的调用分支,应该先说那个?是先有蛋还是先有鸡?咱不去讨论,那是现有服务端,还是现有客户端呢?一般来说,系统会先启动服务,服务向管家请求注册服务,然后才有客户端的服务请求。不过,还是有服务端没了,客户端还是存在的情况,最多查询不到呗!咱也不必纠结,还是按照一般思路来讲解吧!

1)do_add_service()

int do_add_service(struct binder_state *bs,

uint16_t *s, unsigned len,

void *ptr, unsigned uid)

{

struct svcinfo *si;

if (!ptr || (len == 0) || (len > 127))

return -1;

if (!svc_can_register(uid, s)) { //查看该服务是否有注册权限

LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",

str8(s), ptr, uid);

return -1;

}

si = find_svc(s, len); //在服务列表中查找服务,查看该服务是否已经注册

if (si) {

if (si->ptr) {

LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",

str8(s), ptr, uid);

return -1; //如果已经注册,拒绝添加

}

si->ptr = ptr;

} else {

si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));

if (!si) {

LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",

str8(s), ptr, uid);

return -1;

}

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就是服务管家维护的服务列表,它是一个全局变量,这里完成服务在服务链表中添加的操作*/

svclist = si;

}

binder_acquire(bs, ptr);

binder_link_to_death(bs, ptr, &si->death);

return 0;

}

我们看到这个函数,首先检查是否有权限注册service,没权限就对不起了,出错返回;然后检查是否已经注册过,注册过的service将不能再次注册。然后构造一个svcinfo对象,并加入一个全局链表中svclist中。最后通知binder设备:有一个service注册进来。

2)do_find_services()

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)

{

struct svcinfo *si;

si = find_svc(s, len);

// LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);

if (si && si->ptr) {

return si->ptr;

} else {

return 0;

}

}

Do_find_services()函数中调用了find_svc(),find_svc()函数定义如下:

struct svcinfo *find_svc(uint16_t *s16, unsigned 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 0;

}

在Service Manager维护的服务链表中,查找指定服务的名字和大小,如果找到,返回对应的svcinfo结构的一个指针,否则,返回空。

本文只是简单分析了一下Service Manager,更多的细节没有设计,只是从整体框架进行了简略的分析,如果要详细了解,请参考源码。在后面,我们会继续分析Android binder机制之--(我是系统服务server)。

更多相关文章

  1. Android多媒体扫描过程(Android(安卓)Media Scanner Prosess)
  2. android sdk Content Loader's has encountered a problem
  3. Android开发之动态加载,运行未安装apk
  4. [置顶] 彻底解决Android(安卓)应用方法数不能超过65K的问题
  5. SqliteDatabase
  6. SqliteDatabase
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python技巧匿名函数、回调函数和高阶函数

随机推荐

  1. Android智能电视开发之明星UI---Recycler
  2. android实现电子数字显示
  3. Android(安卓)Studio的一些配置(去拼写检
  4. MWC2012开幕在即:看现场 猜趋势
  5. [置顶] Android之路——第一个上线 APP项
  6. Android键盘系统——改变按键功能(2)
  7. Android中AES加密解密。解决密文不唯一、
  8. android 群英传笔记----Android(安卓)scr
  9. android app --- 快速接入云片网短信验证
  10. Android一键分享至社交平台