Android Framework学习(一)之init进程解析

来源:互联网 发布:知乎日报rss地址 编辑:程序博客网 时间:2024/05/16 15:28

转自

http://blog.csdn.net/u012124438/article/details/70990816


init进程是Android系统中用户空间的第一个进程,它被赋予了很多极其重要的工作职责,init进程相关源码位于system/core/init,本篇博客我们就一起来学习init进程(基于Android 7.0)。

init入口函数分析

init的入口函数为main,位于system/core/init/init.cpp

int main(int argc, char** argv) {    if (!strcmp(basename(argv[0]), "ueventd")) {        return ueventd_main(argc, argv);    }    if (!strcmp(basename(argv[0]), "watchdogd")) {        return watchdogd_main(argc, argv);    }    // Clear the umask.    umask(0);    add_environment("PATH", _PATH_DEFPATH);    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);    // Get the basic filesystem setup we need put together in the initramdisk    // on / and then we'll let the rc file figure out the rest.    //1.创建一些文件夹,并挂载设备,这些都是与Linux相关    if (is_first_stage) {        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");        mkdir("/dev/pts", 0755);        mkdir("/dev/socket", 0755);        mount("devpts", "/dev/pts", "devpts", 0, NULL);        #define MAKE_STR(x) __STRING(x)        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));        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.    //2.重定向标准输入,输出,错误输出到/dev/_null_    open_devnull_stdio();    3.初始化内核log系统     klog_init();    klog_set_level(KLOG_NOTICE_LEVEL);    NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");    if (!is_first_stage) {        // Indicate that booting is in progress to background fw loaders, etc.        close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));        //4.初始化和属性相关资源        property_init();        // If arguments are passed both on the command line and in DT,        // properties set in DT always have priority over the command-line ones.        process_kernel_dt();        process_kernel_cmdline();        // Propagate the kernel variables to internal variables        // used by init as well as the current required properties.        export_kernel_boot_props();    }    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.    5.完成SELinux相关工作    selinux_initialize(is_first_stage);    // If we're in the kernel domain, re-exec init to transition to the init domain now    // that the SELinux policy has been loaded.    if (is_first_stage) {        6.重新设置属性        if (restorecon("/init") == -1) {            ERROR("restorecon failed: %s\n", strerror(errno));            security_failure();        }        char* path = argv[0];        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };        if (execv(path, args) == -1) {            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));            security_failure();        }    }    // These directories were necessarily created before initial policy load    // and therefore need their security context restored to the proper value.    // This must happen before /dev is populated by ueventd.    NOTICE("Running restorecon...\n");    restorecon("/dev");    restorecon("/dev/socket");    restorecon("/dev/__properties__");    restorecon("/property_contexts");    restorecon_recursive("/sys");    7.创建epoll句柄     epoll_fd = epoll_create1(EPOLL_CLOEXEC);    if (epoll_fd == -1) {        ERROR("epoll_create1 failed: %s\n", strerror(errno));        exit(1);    }    8.装载子进程信号处理器    signal_handler_init();    property_load_boot_defaults();    export_oem_lock_status();    //9.启动属性服务    start_property_service();    const BuiltinFunctionMap function_map;    Action::set_function_map(&function_map);    Parser& parser = Parser::GetInstance();    parser.AddSectionParser("service",std::make_unique<ServiceParser>());    parser.AddSectionParser("on", std::make_unique<ActionParser>());    parser.AddSectionParser("import", std::make_unique<ImportParser>());    //10.解析init.rc配置文件    parser.ParseConfig("/init.rc");    ActionManager& am = ActionManager::GetInstance();    am.QueueEventTrigger("early-init");    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");    // ... so that we can start queuing up actions that require stuff from /dev.    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");    am.QueueBuiltinAction(keychord_init_action, "keychord_init");    am.QueueBuiltinAction(console_init_action, "console_init");    // Trigger all the boot actions to get us started.    am.QueueEventTrigger("init");    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random    // wasn't ready immediately after wait_for_coldboot_done    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    // Don't mount filesystems or start core system services in charger mode.    std::string bootmode = property_get("ro.bootmode");    if (bootmode == "charger") {        am.QueueEventTrigger("charger");    } else {        am.QueueEventTrigger("late-init");    }    // Run all property triggers based on current state of the properties.    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");    while (true) {        if (!waiting_for_exec) {            am.ExecuteOneCommand();            restart_processes();        }        int timeout = -1;        if (process_needs_restart) {            timeout = (process_needs_restart - gettime()) * 1000;            if (timeout < 0)                timeout = 0;        }        if (am.HasMoreCommands()) {            timeout = 0;        }        bootchart_sample(&timeout);        epoll_event ev;        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));        if (nr == -1) {            ERROR("epoll_wait failed: %s\n", strerror(errno));        } else if (nr == 1) {            ((void (*)()) ev.data.ptr)();        }    }    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171

从上面代码中可以精简归纳init的main方法做的事情: 
1.创建文件系统目录并挂载相关的文件系统 
2.屏蔽标准的输入输出 
3.初始化内核log系统 
4.调用property_init初始化属性相关的资源 
5.完成SELinux相关工作 
6.重新设置属性 
7.创建epoll句柄 
8.装载子进程信号处理器 
9.通过property_start_service启动属性服务 
10.通过parser.ParseConfig(“/init.rc”)来解析init.rc 
接下来对上述部分步骤,进行详细解析。

1.创建文件系统目录并挂载相关的文件系统

//清除屏蔽字(file mode creation mask),保证新建的目录的访问权限不受屏蔽字影响。umask(0);add_environment("PATH", _PATH_DEFPATH);bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);// Get the basic filesystem setup we need put together in the initramdiskif (is_first_stage) {    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");    mkdir("/dev/pts", 0755);    mkdir("/dev/socket", 0755);    mount("devpts", "/dev/pts", "devpts", 0, NULL);    #define MAKE_STR(x) __STRING(x)    mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));    mount("sysfs", "/sys", "sysfs", 0, NULL);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

该部分主要用于创建和挂载启动所需的文件目录。 
需要注意的是,在编译Android系统源码时,在生成的根文件系统中,并不存在这些目录,它们是系统运行时的目录,即当系统终止时,就会消失。

在init初始化过程中,Android分别挂载了tmpfs,devpts,proc,sysfs这4类文件系统。

2.屏蔽标准的输入输出

open_devnull_stdio();
  • 1
  • 1

前文生成/dev目录后,init进程将调用open_devnull_stdio函数,屏蔽标准的输入输出。 
open_devnull_stdio函数会在/dev目录下生成null设备节点文件,并将标准输入、标准输出、标准错误输出全部重定向到null设备中。

void open_devnull_stdio(void){    // Try to avoid the mknod() call if we can. Since SELinux makes    // a /dev/null replacement available for free, let's use it.    int fd = open("/sys/fs/selinux/null", O_RDWR);    if (fd == -1) {        // OOPS, /sys/fs/selinux/null isn't available, likely because        // /sys/fs/selinux isn't mounted. Fall back to mknod.        static const char *name = "/dev/__null__";        if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {            fd = open(name, O_RDWR);            unlink(name);        }        if (fd == -1) {            exit(1);        }    }    dup2(fd, 0);    dup2(fd, 1);    dup2(fd, 2);    if (fd > 2) {        close(fd);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

open_devnull_stdio函数定义于system/core/init/util.cpp中。

这里需要说明的是,dup2函数的作用是用来复制一个文件的描述符,通常用来重定向进程的stdin、stdout和stderr。它的函数原形是:

int dup2(int oldfd, int targetfd)

该函数执行后,targetfd将变成oldfd的复制品。

因此上述过程其实就是:创建出null设备后,将0、1、2绑定到null设备上。因此init进程调用open_devnull_stdio函数后,通过标准的输入输出无法输出信息。

4.初始化属性域

if (!is_first_stage) {    .......    property_init();    .......}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

调用property_init初始化属性域。在Android平台中,为了让运行中的所有进程共享系统运行时所需要的各种设置值,系统开辟了属性存储区域,并提供了访问该区域的API。

需要强调的是,在init进程中有部分代码块以is_first_stage标志进行区分,决定是否需要进行初始化,而is_first_stage的值,由init进程main函数的入口参数决定。 其原因在于,在引入selinux机制后,有些操作必须要在内核态才能完成; 
但init进程作为android的第一个进程,又是运行在用户态的。 
于是,最终设计为用is_first_stage进行区分init进程的运行状态。init进程在运行的过程中,会完成从内核态到用户态的切换。

void property_init() {    if (__system_property_area_init()) {        ERROR("Failed to initialize property area\n");        exit(1);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

property_init函数定义于system/core/init/property_service.cpp中,如上面代码所示,最终调用_system_property_area_init函数初始化属性域。

5.完成SELinux相关工作

// Set up SELinux, including loading the SELinux policy if we're in the kernel domain.selinux_initialize(is_first_stage);
  • 1
  • 2
  • 1
  • 2

init进程进程调用selinux_initialize启动SELinux。从注释来看,init进程的运行确实是区分用户态和内核态的。

static void selinux_initialize(bool in_kernel_domain) {    Timer t;    selinux_callback cb;    //用于打印log的回调函数    cb.func_log = selinux_klog_callback;    selinux_set_callback(SELINUX_CB_LOG, cb);    //用于检查权限的回调函数    cb.func_audit = audit_callback;    selinux_set_callback(SELINUX_CB_AUDIT, cb);    if (in_kernel_domain) {        //内核态处理流程        INFO("Loading SELinux policy...\n");        //用于加载sepolicy文件。该函数最终将sepolicy文件传递给kernel,这样kernel就有了安全策略配置文件,后续的MAC才能开展起来。        if (selinux_android_load_policy() < 0) {            ERROR("failed to load policy: %s\n", strerror(errno));            security_failure();        }        //内核中读取的信息        bool kernel_enforcing = (security_getenforce() == 1);        //命令行中得到的数据        bool is_enforcing = selinux_is_enforcing();        if (kernel_enforcing != is_enforcing) {            //用于设置selinux的工作模式。selinux有两种工作模式:            //1、”permissive”,所有的操作都被允许(即没有MAC),但是如果违反权限的话,会记录日志            //2、”enforcing”,所有操作都会进行权限检查。在一般的终端中,应该工作于enforing模式            if(security_setenforce(is_enforcing)) {                ........                //将重启进入recovery mode                security_failure();            }        }        if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {            security_failure();        }        NOTICE("(Initializing SELinux %s took %.2fs.)\n",               is_enforcing ? "enforcing" : "non-enforcing", t.duration());    } else {        selinux_init_all_handles();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

6.重新设置属性

// If we're in the kernel domain, re-exec init to transition to the init domain now that the SELinux policy has been loaded.if (is_first_stage) {    //按selinux policy要求,重新设置init文件属性    if (restorecon("/init") == -1) {        ERROR("restorecon failed: %s\n", strerror(errno));        security_failure();    }    char* path = argv[0];    char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };    //这里就是前面所说的,启动用户态的init进程,即second-stage    if (execv(path, args) == -1) {        ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));        security_failure();    }}// These directories were necessarily created before initial policy load// and therefore need their security context restored to the proper value.// This must happen before /dev is populated by ueventd.INFO("Running restorecon...\n");restorecon("/dev");restorecon("/dev/socket");restorecon("/dev/__properties__");restorecon_recursive("/sys");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

上述文件节点在加载Sepolicy之前已经被创建了,因此在加载完Sepolicy后,需要重新设置相关的属性。

9.启动配置属性的服务端

start_property_service();
  • 1
  • 1

init进程在共享内存区域中,创建并初始化属性域。其它进程可以访问属性域中的值,但更改属性值仅能在init进程中进行。这就是init进程调用start_property_service的原因。其它进程修改属性值时,要预先向init进程提交值变更申请,然后init进程处理该申请,并修改属性值。在访问和修改属性时,init进程都可以进行权限控制。

void start_property_service() {    //创建了一个非阻塞socket    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0666, 0, 0, NULL);    if (property_set_fd == -1) {        ERROR("start_property_service socket creation failed: %s\n", strerror(errno));        exit(1);    }    //调用listen函数监听property_set_fd, 于是该socket变成一个server    listen(property_set_fd, 8);    //监听server socket上是否有数据到来    register_epoll_handler(property_set_fd,  handle_property_set_fd);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我们知道,在create_socket函数返回套接字property_set_fd时,property_set_fd是一个主动连接的套接字。此时,系统假设用户会对这个套接字调用connect函数,期待它主动与其它进程连接。

由于在服务器编程中,用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来连接,于是需要调用listen函数使用主动连接套接字变为被连接套接字,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。

因此,调用listen后,init进程成为一个服务进程,其它进程可以通过property_set_fd连接init进程,提交设置系统属性的申请。

listen函数的第二个参数,涉及到一些网络的细节。

在进程处理一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态。有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。

因此,内核会在自己的进程空间里维护一个队列,以跟踪那些已完成连接但服务器进程还没有接手处理的用户,或正在进行的连接的用户。这样的一个队列不可能任意大,所以必须有一个上限。listen的第二个参数就是告诉内核使用这个数值作为上限。因此,init进程作为系统属性设置的服务器,最多可以同时为8个试图设置属性的用户提供服务。

在启动配置属性服务的最后,调用函数register_epoll_handler。该函数将利用之前创建出的epoll句柄监听property_set_fd。当property_set_fd中有数据到来时,init进程将利用handle_property_set_fd函数进行处理。

static void handle_property_set_fd() {    ..........    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {        return;    }    ........    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));    .........    switch(msg.cmd) {    .........    }    .........}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

handle_propery_set_fd函数实际上是调用accept函数监听连接请求,接收property_set_fd中到来的数据,然后利用recv函数接受到来的数据,最后根据到来数据的类型,进行设置系统属性等相关操作,在此不做深入分析。

介绍一下系统属性改变的一些用途。 
在init.rc中定义了一些与属性相关的触发器。当某个条件相关的属性被改变时,与该条件相关的触发器就会被触发。举例来说,如下面代码所示,debuggable属性变为1时,将执行启动console进程等操作。

on property:ro.debuggable=1    # Give writes to anyone for the trace folder on debug builds.    # The folder is used to store method traces.    chmod 0773 /data/misc/trace    start console
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

总结一下,其它进程修改系统属性时,大致的流程如下图所示:其它的进程像init进程发送请求后,由init进程检查权限后,修改共享内存区。 
这里写图片描述

10.解析配置文件init.rc

init.rc是系统配置文件,位于system/core/rootdir/init.rc,Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。

init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。在Android系统中,使用init.rc和init.{ hardware }.rc两个文件。

其中init.rc文件在Android系统运行过程中用于通用的环境设置与进程相关的定义,init.{hardware}.rc(例如,高通有init.qcom.rc,MTK有init.mediatek.rc)用于定义Android在不同平台下的特定进程和环境设置等。

init.rc文件大致分为两大部分,一部分是以“on”关键字开头的动作列表(action list):

on early-init    # Set init and its forked children's oom_adj.    write /proc/1/oom_score_adj -1000    .........    start ueventd
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

另一部分是以“service”关键字开头的服务列表(service list):

service ueventd /sbin/ueventd    class core    critical    seclabel u:r:ueventd:s0
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

动作列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一些子进程。如上面代码所示,service关键字后的第一个字符串表示服务(子进程)的名称,第二个字符串表示服务的执行路径。

接下来,我们从ParseConfig函数入手,逐步分析整个解析过程(函数定义于system/core/init/ Init_parser.cpp中):

bool Parser::ParseConfig(const std::string& path) {    if (is_dir(path.c_str())) {        //传入参数为目录地址        return ParseConfigDir(path);    }    //传入参数为文件地址    return ParseConfigFile(path);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
bool Parser::ParseConfigDir(const std::string& path) {    ...........    std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);    ..........    //看起来很复杂,其实就是递归目录    while ((current_file = readdir(config_dir.get()))) {        std::string current_path = android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);        if (current_file->d_type == DT_REG) {            //最终还是靠ParseConfigFile来解析实际的文件            if (!ParseConfigFile(current_path)) {                .............            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

从上面的代码可以看出,解析init.rc文件的函数是ParseConfigFile:

bool Parser::ParseConfigFile(const std::string& path) {    INFO("Parsing file %s...\n", path.c_str());    Timer t;    std::string data;    //读取路径指定文件中的内容,保存为字符串形式    if (!read_file(path.c_str(), &data)) {        return false;    }    data.push_back('\n'); // TODO: fix parse_config.    //解析获取的字符串    ParseData(path, data);    for (const auto& sp : section_parsers_) {        sp.second->EndFile(path);    }    // Turning this on and letting the INFO logging be discarded adds 0.2s to    // Nexus 9 boot time, so it's disabled by default.    if (false) DumpState();    NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

ParseData函数定义于system/core/init/init_parser.cpp中,根据关键字解析出服务和动作。动作与服务会以链表节点的形式注册到service_list与action_list中,service_list与action_list是init进程中声明的全局结构体

void Parser::ParseData(const std::string& filename, const std::string& data) {    .......    parse_state state;    .......    std::vector<std::string> args;    for (;;) {        //next_token以行为单位分割参数传递过来的字符串        //最先走到T_TEXT分支        switch (next_token(&state)) {        case T_EOF:            if (section_parser) {                //EOF,解析结束                section_parser->EndSection();            }            return;        case T_NEWLINE:            state.line++;            if (args.empty()) {                break;            }            //创建parser时,会为init.rc中以service,on,import开头的都定义了对应的解析parser             //这里就是根据第一个参数,判断是否有对应的parser            if (section_parsers_.count(args[0])) {                if (section_parser) {                    //结束上一个parser的工作,将构造出的对象加入到对应的service_list与action_list中                    section_parser->EndSection();                }                //获取参数对应的parser                section_parser = section_parsers_[args[0]].get();                std::string ret_err;                //调用实际parser的ParseSection函数                if (!section_parser->ParseSection(args, &ret_err)) {                    parse_error(&state, "%s\n", ret_err.c_str());                    section_parser = nullptr;                }            } else if (section_parser) {                std::string ret_err;                //如果第一个参数不是service,on,import                //则调用前一个parser的ParseLineSection函数                //这里相当于解析一个参数块的子项                if (!section_parser->ParseLineSection(args, state.filename, state.line, &ret_err)) {                    parse_error(&state, "%s\n", ret_err.c_str());                }            }            //清空本次解析的数据            args.clear();            break;        case T_TEXT:            //将本次解析的内容写入到args中            args.emplace_back(state.text);            break;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

这里的解析看起来比较复杂,在6.0以前的版本中,整个解析是面向过程的。init进程统一调用一个函数来进行解析,然后在该函数中利用switch-case的形式,根据解析的内容进行相应的处理。 
在Android 7.0中,为了更好地封装及面向对象,对于不同的关键字定义了不同的parser对象,每个对象通过多态实现自己的解析操作。

在init进程main函数中,创建各种parser的代码如下:

...........Parser& parser = Parser::GetInstance();parser.AddSectionParser("service",std::make_unique<ServiceParser>());parser.AddSectionParser("on", std::make_unique<ActionParser>());parser.AddSectionParser("import", std::make_unique<ImportParser>());...........
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

看看三个Parser的定义:

class ServiceParser : public SectionParser {......}class ActionParser : public SectionParser {......}class ImportParser : public SectionParser {.......}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

可以看到三个Parser均是继承SectionParser,具体的实现各有不同,我们以比较常用的ServiceParser和ActionParser为例

ServiceParser 
ServiceParser定义于system/core/init/service.cpp中。从前面的代码,我们知道,解析一个service块,首先需要调用ParseSection函数,接着利用ParseLineSection处理子块,解析完所有数据后,调用EndSection。 
因此,我们着重看看ServiceParser的这三个函数:

bool ServiceParser::ParseSection(.....) {    .......    const std::string& name = args[1];    .......    std::vector<std::string> str_args(args.begin() + 2, args.end());    //主要根据参数,构造出一个service对象    service_ = std::make_unique<Service>(name, "default", str_args);    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
//注意这里已经在解析子项了bool ServiceParser::ParseLineSection(......) const {    //调用service对象的HandleLine    return service_ ? service_->HandleLine(args, err) : false;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
bool Service::HandleLine(.....) {    ........    //OptionHandlerMap继承自keywordMap<OptionHandler>    static const OptionHandlerMap handler_map;    //根据子项的内容,找到对应的handler函数    //FindFunction定义于keyword模块中,FindFunction方法利用子类生成对应的map中,然后通过通用的查找方法,即比较键值找到对应的处理函数    auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);    if (!handler) {        return false;    }    //调用handler函数    return (this->*handler)(args, err);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
class Service::OptionHandlerMap : public KeywordMap<OptionHandler> {    ...........    Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();    static const Map option_handlers = {        {"class",       {1,     1,    &Service::HandleClass}},        {"console",     {0,     0,    &Service::HandleConsole}},        {"critical",    {0,     0,    &Service::HandleCritical}},        {"disabled",    {0,     0,    &Service::HandleDisabled}},        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},        {"ioprio",      {2,     2,    &Service::HandleIoprio}},        {"keycodes",    {1,     kMax, &Service::HandleKeycodes}},        {"oneshot",     {0,     0,    &Service::HandleOneshot}},        {"onrestart",   {1,     kMax, &Service::HandleOnrestart}},        {"seclabel",    {1,     1,    &Service::HandleSeclabel}},        {"setenv",      {2,     2,    &Service::HandleSetenv}},        {"socket",      {3,     6,    &Service::HandleSocket}},        {"user",        {1,     1,    &Service::HandleUser}},        {"writepid",    {1,     kMax, &Service::HandleWritepid}},    };    return option_handlers;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
//以class对应的处理函数为例,可以看出其实就是填充service对象对应的域bool Service::HandleClass(const std::vector<std::string>& args, std::string* err) {    classname_ = args[1];    return true;}//注意此时service对象已经处理完毕void ServiceParser::EndSection() {    if (service_) {        ServiceManager::GetInstance().AddService(std::move(service_));    }}void ServiceManager::AddService(std::unique_ptr<Service> service) {    Service* old_service = FindServiceByName(service->name());    if (old_service) {        ERROR("ignored duplicate definition of service '%s'",              service->name().c_str());        return;    }    //将service对象加入到services_里    //7.0里,services_已经是个vector了    services_.emplace_back(std::move(service));}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

总结一下:ServiceParser中,首先根据第一行的名字和参数创建出service对象,然后根据选项域的内容填充service对象,最后将创建出的service对象加入到vector类型的service链表中。

ActionParser 
ActionParser定义于system/core/init/action.cpp中。Action的解析过程,其实与Service一样,也是先后调用ParseSection, ParseLineSection和EndSection。

bool ActionParser::ParseSection(....) {    ........    //创建出新的action对象    auto action = std::make_unique<Action>(false);    //根据参数,填充action的trigger域,不详细分析了    if (!action->InitTriggers(triggers, err)) {        return false;    }    .........}bool ActionParser::ParseLineSection(.......) const {    //构造Action对象的command域    return action_ ? action_->AddCommand(args, filename, line, err) : false;}bool Action::AddCommand(.....) {    ........    //找出action对应的执行函数    auto function = function_map_->FindFunction(args[0], args.size() - 1, err);    ........    //利用所有信息构造出command,加入到action对象中    AddCommand(function, args, filename, line);    return true;}void Action::AddCommand(......) {    commands_.emplace_back(f, args, filename, line);}void ActionParser::EndSection() {    if (action_ && action_->NumCommands() > 0) {        ActionManager::GetInstance().AddAction(std::move(action_));    }}void ActionManager::AddAction(.....) {    ........    auto old_action_it = std::find_if(actions_.begin(),                     actions_.end(),                     [&action] (std::unique_ptr<Action>& a) {                         return action->TriggersEqual(*a);                     });    if (old_action_it != actions_.end()) {        (*old_action_it)->CombineAction(*action);    } else {        //加入到action链表中,类型也是vector,其中装的是指针        actions_.emplace_back(std::move(action));    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

可以看出,加载action块的逻辑和service一样,不同的是需要填充trigger和command域。当然,最后解析出的action也需要加入到action链表中。

这里最后还剩下一个问题,那就是哪里定义了Action中command对应处理函数? 
答案就是在init.cpp的main函数中:

.......const BuiltinFunctionMap function_map;Action::set_function_map(&function_map);.......
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Action中调用function_map_->FindFunction时,实际上调用的是BuiltinFunctionMap的FindFunction函数。FindFunction是keyword定义的通用函数,重点是重构的map函数。所以需要看BuiltinFunctionMap,其定义在system/core/init/builtins.cpp:

BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();    static const Map builtin_functions = {        {"bootchart_init",          {0,     0,    do_bootchart_init}},        {"chmod",                   {2,     2,    do_chmod}},        {"chown",                   {2,     3,    do_chown}},        {"class_reset",             {1,     1,    do_class_reset}},        {"class_start",             {1,     1,    do_class_start}},        {"class_stop",              {1,     1,    do_class_stop}},        {"copy",                    {2,     2,    do_copy}},        {"domainname",              {1,     1,    do_domainname}},        {"enable",                  {1,     1,    do_enable}},        {"exec",                    {1,     kMax, do_exec}},        {"export",                  {2,     2,    do_export}},        {"hostname",                {1,     1,    do_hostname}},        {"ifup",                    {1,     1,    do_ifup}},        {"init_user0",              {0,     0,    do_init_user0}},        {"insmod",                  {1,     kMax, do_insmod}},        {"installkey",              {1,     1,    do_installkey}},        {"load_persist_props",      {0,     0,    do_load_persist_props}},        {"load_system_props",       {0,     0,    do_load_system_props}},        {"loglevel",                {1,     1,    do_loglevel}},        {"mkdir",                   {1,     4,    do_mkdir}},        {"mount_all",               {1,     kMax, do_mount_all}},        {"mount",                   {3,     kMax, do_mount}},        {"powerctl",                {1,     1,    do_powerctl}},        {"restart",                 {1,     1,    do_restart}},        {"restorecon",              {1,     kMax, do_restorecon}},        {"restorecon_recursive",    {1,     kMax, do_restorecon_recursive}},        {"rm",                      {1,     1,    do_rm}},        {"rmdir",                   {1,     1,    do_rmdir}},        {"setprop",                 {2,     2,    do_setprop}},        {"setrlimit",               {3,     3,    do_setrlimit}},        {"start",                   {1,     1,    do_start}},        {"stop",                    {1,     1,    do_stop}},        {"swapon_all",              {1,     1,    do_swapon_all}},        {"symlink",                 {2,     2,    do_symlink}},        {"sysclktz",                {1,     1,    do_sysclktz}},        {"trigger",                 {1,     1,    do_trigger}},        {"verity_load_state",       {0,     0,    do_verity_load_state}},        {"verity_update_state",     {0,     0,    do_verity_update_state}},        {"wait",                    {1,     2,    do_wait}},        {"write",                   {2,     2,    do_write}},    };    return builtin_functions;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

上述代码的第四项就是Action每个command对应的执行函数。

11.向执行队列中添加其它action

ActionManager& am = ActionManager::GetInstance();am.QueueEventTrigger("early-init");// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...m.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");// ... so that we can start queuing up actions that require stuff from /dev.am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");am.QueueBuiltinAction(keychord_init_action, "keychord_init");am.QueueBuiltinAction(console_init_action, "console_init");// Trigger all the boot actions to get us started.am.QueueEventTrigger("init");// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random// wasn't ready immediately after wait_for_coldboot_doneam.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");// Don't mount filesystems or start core system services in charger mode.std::string bootmode = property_get("ro.bootmode");if (bootmode == "charger") {    am.QueueEventTrigger("charger");} else {    am.QueueEventTrigger("late-init");}// Run all property triggers based on current state of the properties.    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

从上面的代码可以看出,接下来init进程中调用了大量的QueueEventTrigger和QueueBuiltinAction函数。

void ActionManager::QueueEventTrigger(const std::string& trigger) {    trigger_queue_.push(std::make_unique<EventTrigger>(trigger));}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

此处QueueEventTrigger函数就是利用参数构造EventTrigger,然后加入到trigger_queue_中。后续init进程处理trigger事件时,将会触发相应的操作。根据前文的分析,我们知道实际上就是将action_list中,对应trigger与第一个参数匹配的action,加入到运行队列action_queue中。

void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {    //创建action    auto action = std::make_unique<Action>(true);    std::vector<std::string> name_vector{name};    //保证唯一性    if (!action->InitSingleTrigger(name)) {        return;    }    //创建action的cmd,指定执行函数和参数    action->AddCommand(func, name_vector);    trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));    actions_.emplace_back(std::move(action));}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

QueueBuiltinAction函数中构造新的action加入到actions_中,第一个参数作为新建action携带cmd的执行函数;第二个参数既作为action的trigger name,也作为action携带cmd的参数。

12.处理添加到运行队列的事件

while (true) {    //判断是否有事件需要处理    if (!waiting_for_exec) {        //依次执行每个action中携带command对应的执行函数        am.ExecuteOneCommand();        //重启一些挂掉的进程        restart_processes();    }    //以下决定timeout的时间,将影响while循环的间隔    int timeout = -1;    //有进程需要重启时,等待该进程重启    if (process_needs_restart) {        timeout = (process_needs_restart - gettime()) * 1000;        if (timeout < 0)            timeout = 0;    }    //有action待处理,不等待    if (am.HasMoreCommands()) {        timeout = 0;    }    //bootchart_sample应该是进行性能数据采样    bootchart_sample(&timeout);    epoll_event ev;    //没有事件到来的话,最多阻塞timeout时间    int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));    if (nr == -1) {        ERROR("epoll_wait failed: %s\n", strerror(errno));    } else if (nr == 1) {        //有事件到来,执行对应处理函数        //epoll句柄(即epoll_fd)主要监听子进程结束,及其它进程设置系统属性的请求。        ((void (*)()) ev.data.ptr)();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

init进程将所有需要操作的action加入运行队列后, 进入无限循环过程,不断处理运行队列中的事件,同时进行重启service等操作。

ExecuteOneCommand中的主要部分如下所示

void ActionManager::ExecuteOneCommand() {    // Loop through the trigger queue until we have an action to execute    //当有可执行action或trigger queue为空时结束    while (current_executing_actions_.empty() && !trigger_queue_.empty()) {        //轮询actions链表        for (const auto& action : actions_) {            //依次查找trigger表            if (trigger_queue_.front()->CheckTriggers(*action)) {                //当action与trigger对应时,就可以执行当前action                //一个trigger可以对应多个action,均加入current_executing_actions_                current_executing_actions_.emplace(action.get());            }        }        //trigger event出队        trigger_queue_.pop();    }    if (current_executing_actions_.empty()) {        return;    }    //每次只执行一个action,下次init进程while循环时,跳过上面的while循环,接着执行    auto action = current_executing_actions_.front();    if (current_command_ == 0) {        std::string trigger_name = action->BuildTriggersString();        INFO("processing action (%s)\n", trigger_name.c_str());    }    //实际的执行过程,此处仅处理当前action中的一个cmd    action->ExecuteOneCommand(current_command_);    //适当地清理工作,注意只有当前action中所有的command均执行完毕后,才会将该action从current_executing_actions_移除    // If this was the last command in the current action, then remove    // the action from the executing list.    // If this action was oneshot, then also remove it from actions_.    ++current_command_;    if (current_command_ == action->NumCommands()) {        current_executing_actions_.pop();        current_command_ = 0;        if (action->oneshot()) {            auto eraser = [&action] (std::unique_ptr<Action>& a) {                return a.get() == action;            };            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));        }    }}void Action::ExecuteCommand(const Command& command) const {    Timer t;    //执行该command对应的处理函数    int result = command.InvokeFunc();    ........}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
void Action::ExecuteCommand(const Command& command) const {    Timer t;    //执行该command对应的处理函数    int result = command.InvokeFunc();    ........}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

从代码可以看出,当while循环不断调用ExecuteOneCommand函数时,将按照trigger表的顺序,依次取出action链表中与trigger匹配的action。 
每次均执行一个action中的一个command对应函数(一个action可能携带多个command)。 
当一个action所有的command均执行完毕后,再执行下一个action。 
当一个trigger对应的action均执行完毕后,再执行下一个trigger对应action。

restart_processes函数负责按需重启service

static void restart_processes() {    process_needs_restart = 0;    ServiceManager::GetInstance().ForEachServiceWithFlags(        SVC_RESTARTING,        [] (Service* s) {            s->RestartIfNeeded(process_needs_restart);        });}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

该函数轮询service对应的链表,对于有SVC_RESTARING标志的service执行RestartIfNeeded(当子进程终止时,init进程会将可被重启进程的服务标志位置为SVC_RESTARTING)。

RestartIfNeeded可以重新启动服务。

void Service::RestartIfNeeded(time_t& process_needs_restart)(struct service *svc){    time_t next_start_time = svc->time_started + 5;    //两次服务启动时间的间隔要大于5s    if (next_start_time <= gettime()) {        svc->flags &= (~SVC_RESTARTING);        //满足时间间隔的要求后,重启服务        //Start将会重新fork服务进程,并做相应的配置        Start(svc, NULL);        return;    }    //更新main函数中,while循环需要等待的时间    if ((next_start_time < process_needs_restart) ||        (process_needs_restart == 0)) {        process_needs_restart = next_start_time;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Bootchart 是一个能对 GNU/Linux boot 过程进行性能分析并把结果直观化的工具。它在 boot 过程中搜集资源利用情况及进程信息然后以PNG, SVG或EPS格式来显示结果。BootChart 包含数据收集工具和图像产生工具。数据收集工具在原始的BootChart中是独立的shell程序,但在Android中,数据收集工具被集成到了init 程序中。


0 0
原创粉丝点击