Android init.rc文件解析过程详解(三)

Android init.rc文件解析过程详解(三)

 

三、相关结构体

 

     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()函数

01int 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值