init进程-用户空间的第一个进程如何守护子进程

377次阅读  |  发布于2年以前

相关源码

创建文件,挂载分区

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);
        mount("proc", "/proc", "proc", 0, NULL);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
    }

如何解析启动脚本

...import导入其他脚本
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc
//on命令
on early-init
//主要这几个关键的服务
service servicemanager /system/bin/servicemanager
service surfaceflinger /system/bin/surfaceflinger
service media /system/bin/mediaserver

init.rc是Android的启动脚本,基本组成单位是section,stction分为三种类型,分别由三个关键字来区分,这三个关键字是import导入、on命令、service服务,接下来看如何解析启动脚本

    //初始化signal_handler
    signal_handler_init();
...
    //解析init.rc启动脚本
    init_parse_config_file("/init.rc");
    //将early-init加入到队列中
    action_for_each_trigger("early-init", action_add_queue_tail);
    while (true) {
        if (!waiting_for_exec) {
            //执行命令
            execute_one_command();
            restart_processes();
        }
    }
static void parse_config(const char *fn, const std::string& data)
{
    ...

    for (;;) {
        switch (next_token(&state)) {
        //T_EOF 如果是文件结束符,则跳转到parser_done
        case T_EOF:
            state.parse_line(&state, 0, 0);
            goto parser_done;
        //如果是新的一行,则一行行解析section
        case T_NEWLINE:
            state.line++;
            if (nargs) {
                int kw = lookup_keyword(args[0]);
                if (kw_is(kw, SECTION)) {
                    state.parse_line(&state, 0, 0);
                    //解析section:包括parse
                    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;
        }
    }

parser_done:
    //循环解析import
    list_for_each(node, &import_list) {
         struct import *import = node_to_item(node, struct import, list);
         int ret;

         ret = init_parse_config_file(import->filename);
         if (ret)
             ERROR("could not import file '%s' from '%s'\n",
                   import->filename, fn);
    }
}

如何启动服务

system/core/init/builtins.cpp

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);
    return0;
}
void service_for_each_class(const char *classname,
                            void (*func)(struct service *svc))
{
    struct listnode *node;
    struct service *svc;
    list_for_each(node, &service_list) {
        svc = node_to_item(node, struct service, slist);
        //如果名字相等则执行回调函数 service_start_if_not_disabled
        if (!strcmp(svc->classname, classname)) {
            func(svc);
        }
    }
}
static void service_start_if_not_disabled(struct service *svc)
{
    if (!(svc->flags & SVC_DISABLED)) {
        service_start(svc, NULL);
    } else {
        svc->flags |= SVC_DISABLED_START;
    }
}
void service_start(struct service *svc, const char *dynamic_args) {
...
//真正的service启动函数,利用fork子进程,复制父进程中的所有资源
    pid_t pid = fork();
    if (pid == 0) {
        execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
    }
}

如何理解fork函数:fork是Linux中创建进程的方式,通过fork来复制父进程中的所有资源,fpid=fork()==0,则子进程创建成功,fork调用一次,但会回调两次:一次是子进程中,一次是父进程中

init进程如何守护子进程

void signal_handler_init() {
    // Create a signalling mechanism for SIGCHLD.
    int s[2];
 //创建socket pair用于通信
   if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
        ERROR("socketpair failed: %s\n", strerror(errno));
        exit(1);
    }
//当捕获信号,则写入signal_write_fd
    signal_write_fd = s[0];
    signal_read_fd = s[1];

    // Write to signal_write_fd if we catch SIGCHLD.
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIGCHLD_handler;
    act.sa_flags = SA_NOCLDSTOP;
//SA_NOCLDSTOP 表示只有子进程终止时,父进程才会收到SIGCHLD信号
    sigaction(SIGCHLD, &act, 0);
//
    reap_any_outstanding_children();

    register_epoll_handler(signal_read_fd, handle_signal);
}
static bool wait_for_one_process() {
    int status;
    //等待任意子进程,如果子进程没有退出则返回0,否则返回pid
    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
    if (pid == 0) {
        returnfalse;
    } elseif (pid == -1) {
        ERROR("waitpid failed: %s\n", strerror(errno));
        returnfalse;
    }
    //根据pid查找服务
    service* svc = service_find_by_pid(pid);

   ...

    //当svc是RESTART且不是ONESHOT时,kill进程组内的所有进程
    if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
        NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
        kill(-pid, SIGKILL);
    }

    // 移除已经创建的socket
    for (socketinfo* si = svc->sockets; si; si = si->next) {
        char tmp[128];
        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
        unlink(tmp);
    }
    //当flag为EXEC时,释放相应服务
    if (svc->flags & SVC_EXEC) {
        INFO("SVC_EXEC pid %d finished...\n", svc->pid);
        waiting_for_exec = false;
        list_remove(&svc->slist);
        free(svc->name);
        free(svc);
        returntrue;
    }

    svc->pid = 0;
    svc->flags &= (~SVC_RUNNING);

    //对于ONESHOT服务,使其进入DISABLED状态
    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
        svc->flags |= SVC_DISABLED;
    }

    //禁用和重置的服务,都不能自动重启
    if (svc->flags & (SVC_DISABLED | SVC_RESET))  {
        svc->NotifyStateChange("stopped");
        returntrue;
    }

    ...

    // 执行当前服务中的重启命令
    struct listnode* node;
    list_for_each(node, &svc->onrestart.commands) {
        command* cmd = node_to_item(node, struct command, clist);
        cmd->func(cmd->nargs, cmd->args);
    }
    svc->NotifyStateChange("restarting");
    returntrue;
}

总结

init进程是Linux系统中用户空间的第一个进程,做了以下工作

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8