天天看点

《Android的设计与实现:卷I》——第3章 3.4.4解析Servicedefine list_declare(name) \

3.4.4 解析service

1.parse_service

解析service先从parse_service开始,代码如下:

static void parse_service(struct parse_state state,int nargs, charargs)

{

struct servicesvc;//service结构体,用于保存当前解析出的service

……//省略错误处理代码

nargs -= 2;

/为service分配存储空间/

svc = calloc(1, sizeof(svc) + sizeof(char) nargs);

/用解析到的内容构造service结构体/

svc->name = args[1];

svc->classname = "default";

memcpy(svc->args, args + 2, sizeof(char) nargs);

svc->args[nargs] = 0;

svc->nargs = nargs;

svc->onrestart.name = "onrestart";

/初始化service中restart option的commands链表,然后

将servic的节点slist放入service_list双向链表/

list_init(&svc->onrestart.commands);

/将service节点的指针部分放入service_list中/

list_add_tail(&service_list, &svc->slist);

return svc;

}

parse_service函数主要做了三项工作:1)为新建的service分配存储空间,2)初始化service,

3)将service放入一个service_list链表。其中涉及几个重要的数据类型和函数:service_list、list_init和list_add_tail,以及service结构体。

(1)service_list

service_list由list_declare定义,list_declare实际上是一个宏,位于/system/core/include/cutils/list.h。其源码如下:

service_list声明了一个双向链表,存储了前向和后向指针。

(2)list_init和list_add_tail

list_init和list_add_tail的实现代码位于/system/core/libcutils/list.c中,提供了基本的双向链表操作。list_init的源码如下:

void list_init(struct listnode node)

node->next = node;

node->prev = node;

list_add_tail的源码如下:

void list_add_tail(struct listnode head, struct listnode item)

item->next = head;

item->prev = head->prev;

head->prev->next = item;

head->prev = item;

list_add_tail只是将item加入到双向链表的尾部。

注意 android借鉴了linux内核中常用的链表实现方法。把链表的指针部分和数据部分分离。

   首先定义了node结构体:

   struct listnode

   {

   struct listnode *next;

   struct listnode *prev;

   };

   将链表的前向指针和后项指针放入这个struct listnode的结构中。当需要处理不同数据节点时,就把这个listnode嵌入不同的数据节点中。这样操作链表就是操作这个listnode,与具体的数据无关。如parse_service函数中,list_add_tail(&service_list, &svc->slist);便是将service节点的listnode指针部分放入service_list链表。当需要操作listnode对应的数据时,就可通过成员偏移量找到对应的数据,这部分以后分析。

(3)service结构体

parse_service中最重要的一个数据类型便是service,它存储了service这个section的内容。service结构体定义在/system/core/init/init.h中,代码如下:

struct service {

/ list of all services /

struct listnode slist;

const char *name; //service的名字

const char *classname; //service的分类名

unsigned flags; //service的属性标志

pid_t pid; //service的进程号

time_t time_started; //上次启动时间

time_t time_crashed; //上次异常退出的时间

int nr_crashed; //异常退出的次数

uid_t uid; //用户id

gid_t gid; //组id

gid_t supp_gids[nr_svc_supp_gids];

size_t nr_supp_gids;

struct socketinfo sockets; //service使用的socket

struct svcenvinfo esnvvars; //service使用的环境变量

/service重启时要执行的action。这里其实是由关键字onrestart声明的option。由于onrestart

}; /args 必须位于结构体末端 /

可见,service需要填充的内容很多,parse_service函数只是初始化了service的基本信息,详细信息需要由parse_line_service填充。

2.parse_line_service

parse_line_service的源码如下:

static void parse_line_service(struct parse_state state, int nargs, charargs)

……//省略部分case语句

default: //只支持固定的关键字,否则出错

到这里service就解析完了,接着分析action的解析过程。

继续阅读