深入理解Android(03)——深入理解init初始化函数

来源:互联网 发布:mac 命令行安装mysql 编辑:程序博客网 时间:2024/06/05 23:40

1、概述

init是一个进程,确切地说,它是Linux系统中用户空间地第一个进程。由于Android是基于Linux内核地,所以init也是Android系统中用户空间地第一个进程,它的进程号是1。

init进程有几个重要地职责:

1)init进程负责创建系统中的几个关键进程。

2)Android系统有很多属性,init提供了一个property service(属性服务)来管理他们。

2、init分析

init进程的入口函数是main,代码如下:

int main(int argc, char **argv){    int fd_count = 0;    struct pollfd ufds[4];    char *tmpdev;    char* debuggable;    char tmp[32];    int property_set_fd_init = 0;    int signal_fd_init = 0;    int keychord_fd_init = 0;    if (!strcmp(basename(argv[0]), "ueventd"))        return ueventd_main(argc, argv);    /* clear the umask */    umask(0);    // 创建一些文件夹    mkdir("/dev", 0755);    mkdir("/proc", 0755);    mkdir("/sys", 0755);    mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");    mkdir("/dev/pts", 0755);    mkdir("/dev/socket", 0755);    mount("devpts", "/dev/pts", "devpts", 0, NULL);    mount("proc", "/proc", "proc", 0, NULL);    mount("sysfs", "/sys", "sysfs", 0, NULL);        /* We must have some place other than / to create the         * device nodes for kmsg and null, otherwise we won't         * be able to remount / read-only later on.         * Now that tmpfs is mounted on /dev, we can actually         * talk to the outside world.         */    open_devnull_stdio();    log_init();        INFO("reading config file\n");    init_parse_config_file("/init.rc");    /* pull the kernel commandline and ramdisk properties file in */    import_kernel_cmdline(0);    get_hardware_name(hardware, &revision);    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);    init_parse_config_file(tmp);    action_for_each_trigger("early-init", action_add_queue_tail);    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");    queue_builtin_action(property_init_action, "property_init");    queue_builtin_action(keychord_init_action, "keychord_init");    queue_builtin_action(console_init_action, "console_init");    queue_builtin_action(set_init_properties_action, "set_init_properties");        /* execute all the boot actions to get us started */    action_for_each_trigger("init", action_add_queue_tail);    action_for_each_trigger("early-fs", action_add_queue_tail);    action_for_each_trigger("fs", action_add_queue_tail);    action_for_each_trigger("post-fs", action_add_queue_tail);    queue_builtin_action(property_service_init_action, "property_service_init");    queue_builtin_action(signal_init_action, "signal_init");    queue_builtin_action(check_startup_action, "check_startup");    /* execute all the boot actions to get us started */    action_for_each_trigger("early-boot", action_add_queue_tail);    action_for_each_trigger("boot", action_add_queue_tail);        /* run all property triggers based on current state of the properties */    queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");//初始化的操作//.........    return 0;}


init的代码还是很长的,主要是用来做初始化操作,init的工作流程精简之后,大概是如下四点:

1)解析两个配置文件,重点是init.rc文件解析

2)执行各个阶段的动作,创建zygote的工作就是在这里完成的

3)调用property_init初始化属性相关的资源,并且通过property_start_service启动属性服务

4)init进入一个无限循环,并且等待一些事情的发生。重点是init如何处理来自socket和来自属性服务器的相关事情。


3、解析配置文件

3.1 init的配置文件

        init中会解析两个配置文件,其中一个是系统配置文件init.rc,另外一个是与硬件平台相关的配置文件。虽然解析的是不同的配置文件,但是调用的是同一个函数,代码如下:

int init_parse_config_file(const char *fn){    char *data;    data = read_file(fn, 0);  //读取配置文件,这里是init.rc    if (!data) return -1;    parse_config(fn, data); //调用方法解析文件    DUMP();    return 0;}


        读取完配置文件之后,调用方法解析,函数代码如下所示:

static void parse_config(const char *fn, char *s){    struct parse_state state;    char *args[INIT_PARSER_MAXARGS];    int nargs;    nargs = 0;    state.filename = fn;    state.line = 1;    state.ptr = s;    state.nexttoken = 0;// 设置解析函数,不同的内容用不同的解析函数    state.parse_line = parse_line_no_op;      for (;;) {        switch (next_token(&state)) {        case T_EOF:            state.parse_line(&state, 0, 0);            return;        case T_NEWLINE:            if (nargs) {// 得到关键字的类型                int kw = lookup_keyword(args[0]);// 判断关键字类型是不是SECTION                if (kw_is(kw, SECTION)) {                    state.parse_line(&state, 0, 0);// 解析这个SECTION                    parse_new_section(&state, kw, nargs, args);                } else {                    state.parse_line(&state, nargs, args);                }                nargs = 0;            }            break;        case T_TEXT:            if (nargs < INIT_PARSER_MAXARGS) {                args[nargs++] = state.text;            }            break;        }    }}

        这里的SECTION是一个关键字,自定义的关键字,都存放在keywords.h中。


3.2 解析init.rc

init.rc的内容如下所示:

system/core/rootdir/init.rc

#on关键字表示是一个section,这里表示init,下面的内容全部是这个section,直到下一个on关键字结束
on init# setup the global environment    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin    export LD_LIBRARY_PATH /vendor/lib:/system/lib    export ANDROID_BOOTLOGO 1    export ANDROID_ROOT /system    export ANDROID_ASSETS /system/app    export ANDROID_DATA /data    export EXTERNAL_STORAGE /mnt/sdcard    export ASEC_MOUNTPOINT /mnt/asec    export LOOP_MOUNTPOINT /mnt/obb    export BOOTCLASSPATH......# 省略部分

#开始boot这个section
on boot# basic network init    ifup lo    hostname localhost    domainname localdomain


#service关键字也表示是一个section,这里表示zygote

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    socket zygote stream 666    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netd


#section,这里表示media
service media /system/bin/mediaserver    user media    group system audio camera graphics inet net_bt net_bt_admin net_raw    ioprio rt 4


4、解析service

zygote对应的service section内容是:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    socket zygote stream 666    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netd


init_parser.c

解析section的入口函数是parse_new_section,如下所示:

void parse_new_section(struct parse_state *state, int kw, int nargs, char **args){    printf("[ %s %s ]\n", args[0],           nargs > 1 ? args[1] : "");    switch(kw) {    case K_service:        state->context = parse_service(state, nargs, args);        if (state->context) {            state->parse_line = parse_line_service;            return;        }        break;    case K_on:        state->context = parse_action(state, nargs, args);        if (state->context) {            state->parse_line = parse_line_action;            return;        }        break;    }    state->parse_line = parse_line_no_op;}


5、init控制service

5.1 启动service

init.rc中有这样一句话:

class_start defaultclass_start是一个COMMAND,对应的函数为do_class_start,它位于boot section中。//  将boot section节中的command加入到执行队列中    action_for_each_trigger("early-boot", action_add_queue_tail);    action_for_each_trigger("boot", action_add_queue_tail);

// 执行队列里的命令,class是一个COMMAND,所以它对应的do_class_start会被执行

queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");

这里是do_class_start方法的代码:

int do_class_start(int nargs, char **args){        /* Starting a class does not start services         * which are explicitly disabled.  They must         * be started individually.         */    service_for_each_class(args[1], service_start_if_not_disabled);    return 0;}


0 0