Android啟動流程分析(十) action的執行和service的啟動
阿新 • • 發佈:2019-02-13
終於結束了漫長的init程序的分析,估計這十篇文章可以基本概括了init程序啟動過程中的每一個細節。void service_start(struct service *svc, const char *dynamic_args) { /// ****************************** start service 的第一個階段 struct stat s; pid_t pid; int needs_console; int n; char *scon = NULL; int rc; /* starting a service removes it from the disabled or reset * state and immediately takes it out of the restarting * state if it was in there */ svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); // 這個service即將被啟動,將其從disable或reset的狀態給移除掉,置其為重新執行的狀態 svc->time_started = 0; /* running processes require no additional work -- if * they're in the process of exiting, we've ensured * that they will immediately restart on exit, unless * they are ONESHOT */ if (svc->flags & SVC_RUNNING) { // 如果這個service仍然是執行態的話,即return return; } needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0; if (needs_console && (!have_console)) { ERROR("service '%s' requires console\n", svc->name); svc->flags |= SVC_DISABLED; return; } // 如果這個service的flags是初始console,但是這個已經啟動了的話,就會設定當前的flags為disabled if (stat(svc->args[0], &s) != 0) { // 如果要執行的這個service的start的command不存在的話,返回error ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name); svc->flags |= SVC_DISABLED; return; } if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { // 因為dynamic_args為null,所以這邊不會進入這個判斷 ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]); svc->flags |= SVC_DISABLED; return; } // ***********************************************************這裡我們可以認為是第二個階段,selinux是資訊保安相關的操作,這邊我們忽略掉 if (is_selinux_enabled() > 0) { if (svc->seclabel) { scon = strdup(svc->seclabel); if (!scon) { ERROR("Out of memory while starting '%s'\n", svc->name); return; } } else { char *mycon = NULL, *fcon = NULL; INFO("computing context for service '%s'\n", svc->args[0]); rc = getcon(&mycon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } rc = getfilecon(svc->args[0], &fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); freecon(mycon); return; } rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon); if (rc == 0 && !strcmp(scon, mycon)) { ERROR("Warning! Service %s needs a SELinux domain defined; please fix!\n", svc->name); } freecon(mycon); freecon(fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } } } // ***************************************** selinux的操作結束,進入到第三個階段 NOTICE("starting '%s'\n", svc->name); pid = fork(); // fork一個自程序,即所有從init.rc啟動的service,都是一個子程序 if (pid == 0) { // pid = 0, 進入到子程序中 struct socketinfo *si; struct svcenvinfo *ei; char tmp[32]; int fd, sz; umask(077); if (properties_inited()) { get_property_workspace(&fd, &sz); // 得到屬性儲存空間的資訊並加入到環境變數中 sprintf(tmp, "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } for (ei = svc->envvars; ei; ei = ei->next) // 將service自己宣告的env加入到環境變數中 add_environment(ei->name, ei->value); for (si = svc->sockets; si; si = si->next) { // 根據socket info設定socket int socket_type = ( !strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET)); int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid, si->socketcon ?: scon); if (s >= 0) { publish_socket(si->name, s); } } freecon(scon); scon = NULL; if (svc->ioprio_class != IoSchedClass_NONE) { if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) { ERROR("Failed to set pid %d ioprio = %d,%d: %s\n", getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno)); } } if (needs_console) { setsid(); open_console(); } else { zap_stdio(); } #if 0 for (n = 0; svc->args[n]; n++) { INFO("args[%d] = '%s'\n", n, svc->args[n]); } for (n = 0; ENV[n]; n++) { INFO("env[%d] = '%s'\n", n, ENV[n]); } #endif setpgid(0, getpid()); /* as requested, set our gid, supplemental gids, and uid */ if (svc->gid) { // 設定gid if (setgid(svc->gid) != 0) { ERROR("setgid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->nr_supp_gids) { if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) { ERROR("setgroups failed: %s\n", strerror(errno)); _exit(127); } } if (svc->uid) { // 設定uid if (setuid(svc->uid) != 0) { ERROR("setuid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->seclabel) { if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) { ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno)); _exit(127); } } if (!dynamic_args) { // 因為dynamic_args設定的為null,我們在第一次從init.rc啟動的時候,一定會進入到這個判斷。 if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { // !!! 執行當前的service的啟動的命令,也就是說從這邊開始,我們就可以理解為已經從init程序中,去像kernel執行init一樣,就去執行各個service所對應的啟動函數了! ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno)); } } else { char *arg_ptrs[INIT_PARSER_MAXARGS+1]; int arg_idx = svc->nargs; char *tmp = strdup(dynamic_args); char *next = tmp; char *bword; /* Copy the static arguments */ memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *))); while((bword = strsep(&next, " "))) { arg_ptrs[arg_idx++] = bword; if (arg_idx == INIT_PARSER_MAXARGS) break; } arg_ptrs[arg_idx] = '\0'; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } freecon(scon); if (pid < 0) { ERROR("failed to start '%s'\n", svc->name); svc->pid = 0; return; } svc->time_started = gettime(); svc->pid = pid; svc->flags |= SVC_RUNNING; if (properties_inited()) notify_service_state(svc->name, "running"); }