Related to the source code

  • system/core/init/init.cpp

  • system/core/rootdir/init.rc

  • system/core/init/init_parser.cpp

  • system/core/init/builtins.cpp

  • The main logic

    • Create files and mount partitions
    • Parsing startup scripts
    • The init process starts the child process
    • The init process guards the child process

Create files and mount partitions

   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);
    }
Copy the code

How do I parse the startup script

. Import Import /init.${ro.hardware}. Rc import /init.${ro.zygote}. Rc import /init.trace.rc //on on early-init / / the main key service service servicemanager/system/bin/servicemanager service surfaceflinger/system/bin/surfaceflinger service  media /system/bin/mediaserverCopy the code

Init. rc is a startup script for Android. The basic unit is section. Stction is divided into three types, which are distinguished by three keywords: import, on command, and service

// initialize signal_handler signal_handler_init(); . // parse init.rc startup script init_parse_config_file("/init.rc"); Action_for_each_trigger ("early-init", action_add_queue_tail);Copy the code
while (true) { if (! Waiting_for_exec) {// execute execute_one_command(); restart_processes(); }}Copy the code
static void parse_config(const char *fn, const std::string& data)
{...for (;;) {
        switch (next_token(&state)) {
        //T_EOF jumps to parser_done if it is the end of file
        case T_EOF:
            state.parse_line(&state, 0.0);
            goto parser_done;
        // If it is a new row, the section is parsed line by line
        case T_NEWLINE:
            state.line++;
            if (nargs) {
                int kw = lookup_keyword(args[0]);
                if (kw_is(kw, SECTION)) {
                    state.parse_line(&state, 0.0);
                    // Parse section: includes parse
                    parse_new_section(&state, kw, nargs, args);
                } else {
                   // Parse common commands
                    state.parse_line(&state, nargs, args);
                }
                nargs = 0;
            }
            break;
        case T_TEXT:
            if (nargs < INIT_PARSER_MAXARGS) {
                args[nargs++] = state.text;
            }
            break;
        }
    }

parser_done:
    // Loop through 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); }}Copy the code

How to Start a service

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);
    return 0;
}
Copy the code
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);
        // If the names are equal, the callback function service_start_if_not_disabled is executed
        if (!strcmp(svc->classname, classname)) {
            func(svc); }}}Copy the code
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; }}Copy the code
void service_start(struct service *svc, const char *dynamic_args) {...// The real service start function forks all the resources in the parent process
    pid_t pid = fork();
    if (pid == 0) {
        execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); }}Copy the code

Fpid =fork()==0; fpid=fork()==0; fpid=fork()==0

How does the init process daemon child processes

void signal_handler_init(a) {
    // Create a signalling mechanism for SIGCHLD.
    int s[2];
 // Create a socket pair for communication
   if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == - 1) {
        ERROR("socketpair failed: %s\n".strerror(errno));
        exit(1);
    }
// When a signal is captured, write 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 indicates that the parent process receives the SIGCHLD signal only when the child process terminates
    sigaction(SIGCHLD, &act, 0);
//
    reap_any_outstanding_children(a);register_epoll_handler(signal_read_fd, handle_signal);
}

Copy the code
static bool wait_for_one_process(a) {
    int status;
    // Wait for any child process, return 0 if the child does not exit, otherwise return PID
    pid_t pid = TEMP_FAILURE_RETRY(waitpid(- 1, &status, WNOHANG));
    if (pid == 0) {
        return false;
    } else if (pid == - 1) {
        ERROR("waitpid failed: %s\n".strerror(errno));
        return false;
    }
    // Find the service according to pid
    service* svc = service_find_by_pid(pid); .// When SVC is RESTART and not ONESHOT, kill all processes in the process group
    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);
    }

    // Remove the created 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);
    }
    // If flag is EXEC, release the corresponding service
    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);
        return true;
    }

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

    // For ONESHOT service, make it DISABLED
    if((svc->flags & SVC_ONESHOT) && ! (svc->flags & SVC_RESTART)) { svc->flags |= SVC_DISABLED; }// Services that are disabled or reset cannot be restarted automatically
    if (svc->flags & (SVC_DISABLED | SVC_RESET))  {
        svc->NotifyStateChange("stopped");
        return true; }...// Run the restart command for the current service
    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");
    return true;
}
Copy the code

conclusion

The init process, which is the first user space process on a Linux system, does the following

  • Create files and mount partitions
  • Parsing startup scripts
  • The init process starts the child process
  • The init process guards the child process