三、相关结构体
1、listnode
listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了listnode结构体以及相关操作双向链表的方法,与kernel中的定义类似。
这个实现的核心思想是:在用户自定义的结构体xx中定义一个listnode类型的成员,
这个listnode类型成员的作用就是能将xx类型的变量组成一个双向链表。下面我们来看一下是listnode是怎么做到的。
//listnode类型里面只有两个指针prev,next
struct listnode
{
struct listnode *next;
struct listnode *prev;
};
//将链表中的一个node转换成自定义结构体中的一个对象
#define node_to_item(node, container, member) \
(container *) (((char*) (node)) - offsetof(container, member))
//初始化一个链表
void list_init(struct listnode *node)
{
node->next = node;
node->prev = node;
}
//将一个节点到链表
void list_add_tail(struct listnode *head, struct listnode *item)
{
item->next = head;
item->prev = head->prev;
head->prev->next = item;
head->prev = item;
}
//删除一个节点
void list_remove(struct listnode *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
}
理解node_to_item宏是理解listnode用法的关键,这个宏的作用是将一个listnode指针转换成了一个指定类型(自定义)的指针,这个宏先使用offsetof函数获取到指定结构体中指定成员变量的地址偏移量,然后通过指针运算获得listnode指针变量所在结构体变量的指针。
这种实现与我们课堂上所学的链表实现方法不太一样,教科书上的实现是在listnode中存储了自定义的数据,而这个实现是在自定义的数据当中存储listnode指针。
2、action结构体
前面已经讲过on类型的section解析之后会生成一个双向链表action_list, 这个action_list每个node表示就是action结构体的对象,也就是说一个on类型的section都会生成一个action结构体的对象。
action结构体定义如下:
struct action {
/* node in list of all actions */
struct listnode alist;
/* node in the queue of pending actions */
struct listnode qlist;
/* node in list of actions for a trigger */
struct listnode tlist;
unsigned hash;
const char *name;
struct listnode commands; //节点为command结构体的双向链表
struct command *current;
};
action结构体除了用在on类型的section, 也用在service类型的section,下面介绍service结构体时会说明。
3、command结构体
Command结构体定义如下:
struct command
{
/* list of commands in an action */
struct listnode clist;
int (*func)(int nargs, char **args);
int nargs;
char *args[1];
};
command结构体比较简单, 用于标识一个命令,包含双向链表指针、对应的执行函数、参数个数以及命令关键字。
4、service结构体
struct service {
/* list of all services */
struct listnode slist; //将结构体链接成service_list用
const char *name;
const char *classname;
unsigned flags;
pid_t pid;
time_t time_started; /* time of last start */
time_t time_crashed; /* first crash within inspection window */
int nr_crashed; /* number of times crashed within window */
uid_t uid;
gid_t gid;
gid_t supp_gids[NR_SVC_SUPP_GIDS];
size_t nr_supp_gids;
#ifdef HAVE_SELINUX
char *seclabel;
#endif
struct socketinfo *sockets;
struct svcenvinfo *envvars;
struct action onrestart; /* Actions to execute on restart. */
/* keycodes for triggering this service via /dev/keychord */
int *keycodes;
int nkeycodes;
int keychord_id;
int ioprio_class;
int ioprio_pri;
int nargs;
/* "MUST BE AT THE END OF THE STRUCT" */
char *args[1];
};
service结构体存储了service的相关信息, 包括进程号、启动时间、名字等, 字段onrestart
就用到了action结构体, onrestart这个option后面通常跟着一个命令,所以也用action结构体来表示。
注:本文基于android4.2的源代码分析
最后我们分析一下init.c中的main()函数
01 |
int main( int argc, char **argv) |
02 |
{ |
03 |
... ... |
04 |
/* Get the basic filesystem setup we need put |
05 |
* together in the initramdisk on / and then we'll |
06 |
* let the rc file figure out the rest. |
07 |
*/ |
08 |
// 创建一些linux根文件系统中的目录 |
09 |
mkdir( "/dev" , 0755); |
10 |
mkdir( "/proc" , 0755); |
11 |
mkdir( "/sys" , 0755); |
12 |
13 |
mount( "tmpfs" , "/dev" , "tmpfs" , MS_NOSUID, "mode=0755" ); |
14 |
mkdir( "/dev/pts" , 0755); |
15 |
mkdir( "/dev/socket" , 0755); |
16 |
mount( "devpts" , "/dev/pts" , "devpts" , 0, NULL); |
17 |
mount( "proc" , "/proc" , "proc" , 0, NULL); |
18 |
mount( "sysfs" , "/sys" , "sysfs" , 0, NULL); |
19 |
20 |
//open_devnull_stdio(); |
21 |
klog_init(); |
22 |
23 |
... ... |
24 |
25 |
printf ( "Parsing init.rc ...\n" ); |
26 |
// 读取并且解析init.rc文件 |
27 |
init_parse_config_file( "/init.rc" ); |
28 |
29 |
... ... |
30 |
31 |
// 取得硬件名 |
32 |
get_hardware_name(); |
33 |
snprintf(tmp, sizeof (tmp), "/init.%s.rc" , hardware); |
34 |
35 |
// 读取并且解析硬件相关的init脚本文件 |
36 |
parse_config_file(tmp); |
37 |
38 |
... ... |
39 |
40 |
# 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init |
41 |
action_for_each_trigger( "early-init" , action_add_queue_tail); |
42 |
43 |
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done" ); |
44 |
queue_builtin_action(property_init_action, "property_init" ); |
45 |
queue_builtin_action(keychord_init_action, "keychord_init" ); |
46 |
# 控制台相关初始化,在这里会加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。 |
47 |
queue_builtin_action(console_init_action, "console_init" ); |
48 |
queue_builtin_action(set_init_properties_action, "set_init_properties" ); |
49 |
50 |
/* execute all the boot actions to get us started */ |
51 |
# 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init |
52 |
action_for_each_trigger( "init" , action_add_queue_tail); |
53 |
54 |
/* skip mounting filesystems in charger mode */ |
55 |
if ( strcmp (bootmode, "charger" ) != 0) { |
56 |
action_for_each_trigger( "early-fs" , action_add_queue_tail); |
57 |
action_for_each_trigger( "fs" , action_add_queue_tail); |
58 |
action_for_each_trigger( "post-fs" , action_add_queue_tail); |
59 |
action_for_each_trigger( "post-fs-data" , action_add_queue_tail); |
60 |
} |
61 |
62 |
// 启动系统属性服务: system property service |
63 |
queue_builtin_action(property_service_init_action, "property_service_init" ); |
64 |
queue_builtin_action(signal_init_action, "signal_init" ); |
65 |
queue_builtin_action(check_startup_action, "check_startup" ); |
66 |
67 |
queue_builtin_action(queue_early_property_triggers_action, "queue_early_propety_triggers" ); |
68 |
69 |
if (! strcmp (bootmode, "charger" )) { |
70 |
action_for_each_trigger( "charger" , action_add_queue_tail); |
71 |
} else { |
72 |
// 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot |
73 |
action_for_each_trigger( "early-boot" , action_add_queue_tail); |
74 |
action_for_each_trigger( "boot" , action_add_queue_tail); |
75 |
} |
76 |
77 |
/* run all property triggers based on current state of the properties */ |
78 |
// 启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx |
79 |
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers" ); |
80 |
81 |
// 进入死循环 |
82 |
for (;;) { |
83 |
int nr, i, timeout = -1; |
84 |
85 |
execute_one_command(); |
86 |
// 启动所有init脚本中声明的service |
87 |
restart_processes(); |
88 |
... ... |
89 |
// 多路监听设备管理,子进程运行状态,属性服务 |
90 |
nr = poll(ufds, fd_count, timeout); |
91 |
... ... |
92 |
} |
93 |
94 |
return 0; |
95 |
} |
转载:http://blog.itpub.net/7232789/viewspace-758168/
http://blog.csdn.net/mk1111/article/details/16357327