Loading init/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ LOCAL_SRC_FILES:= \ init_parser.cpp \ log.cpp \ parser.cpp \ service.cpp \ util.cpp \ LOCAL_STATIC_LIBRARIES := libbase Loading init/builtins.cpp +35 −46 Original line number Diff line number Diff line Loading @@ -44,20 +44,19 @@ #include <private/android_filesystem_config.h> #include "action.h" #include "devices.h" #include "init.h" #include "init_parser.h" #include "keywords.h" #include "log.h" #include "property_service.h" #include "devices.h" #include "init_parser.h" #include "service.h" #include "util.h" #include "log.h" #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW #define UNMOUNT_CHECK_MS 5000 #define UNMOUNT_CHECK_TIMES 10 int add_environment(const char *name, const char *value); // System call provided by bionic but not in any header file. extern "C" int init_module(void *, unsigned long, const char *); Loading Loading @@ -100,15 +99,6 @@ done: return ret; } 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; } } static void unmount_and_fsck(const struct mntent *entry) { if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4")) Loading @@ -131,7 +121,7 @@ static void unmount_and_fsck(const struct mntent *entry) * automatically restart after kill(), but that is not really a problem * because |entry->mnt_dir| is no longer visible to such new processes. */ service_for_each(service_stop); ServiceManager::GetInstance().ForEachService([] (Service* s) { s->Stop(); }); TEMP_FAILURE_RETRY(kill(-1, SIGKILL)); int count = 0; Loading Loading @@ -176,19 +166,22 @@ int do_class_start(const std::vector<std::string>& args) * which are explicitly disabled. They must * be started individually. */ service_for_each_class(args[1].c_str(), service_start_if_not_disabled); ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); }); return 0; } int do_class_stop(const std::vector<std::string>& args) { service_for_each_class(args[1].c_str(), service_stop); ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); }); return 0; } int do_class_reset(const std::vector<std::string>& args) { service_for_each_class(args[1].c_str(), service_reset); ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); }); return 0; } Loading @@ -199,30 +192,22 @@ int do_domainname(const std::vector<std::string>& args) int do_enable(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED); if (svc->flags & SVC_DISABLED_START) { service_start(svc, NULL); } } else { Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { return -1; } return 0; return svc->Enable(); } int do_exec(const std::vector<std::string>& args) { std::vector<char*> strs; strs.reserve(args.size()); for (const auto& s : args) { strs.push_back(const_cast<char*>(s.c_str())); Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args); if (!svc) { return -1; } service* svc = make_exec_oneshot_service(strs.size(), &strs[0]); if (svc == NULL) { if (!svc->Start()) { return -1; } service_start(svc, NULL); waiting_for_exec = true; return 0; } Loading Loading @@ -567,31 +552,35 @@ int do_setrlimit(const std::vector<std::string>& args) int do_start(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { service_start(svc, NULL); Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { ERROR("do_start: Service %s not found\n", args[1].c_str()); return -1; } if (!svc->Start()) return -1; return 0; } int do_stop(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { service_stop(svc); Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { ERROR("do_stop: Service %s not found\n", args[1].c_str()); return -1; } svc->Stop(); return 0; } int do_restart(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { service_restart(svc); Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { ERROR("do_restart: Service %s not found\n", args[1].c_str()); return -1; } svc->Restart(); return 0; } Loading init/init.cpp +40 −383 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ #include <sys/types.h> #include <sys/un.h> #include <sys/wait.h> #include <termios.h> #include <unistd.h> #include <mtd/mtd-user.h> Loading @@ -54,16 +53,17 @@ #include <memory> #include "action.h" #include "bootchart.h" #include "devices.h" #include "init.h" #include "init_parser.h" #include "keychords.h" #include "log.h" #include "property_service.h" #include "bootchart.h" #include "service.h" #include "signal_handler.h" #include "keychords.h" #include "init_parser.h" #include "util.h" #include "ueventd.h" #include "util.h" #include "watchdogd.h" struct selabel_handle *sehandle; Loading @@ -73,11 +73,11 @@ static int property_triggers_enabled = 0; static char qemu[32]; static int have_console; static std::string console_name = "/dev/console"; int have_console; std::string console_name = "/dev/console"; static time_t process_needs_restart; static const char *ENV[32]; const char *ENV[32]; bool waiting_for_exec = false; Loading @@ -92,27 +92,6 @@ void register_epoll_handler(int fd, void (*fn)()) { } } void service::NotifyStateChange(const char* new_state) { if (!properties_initialized()) { // If properties aren't available yet, we can't set them. return; } if ((flags & SVC_EXEC) != 0) { // 'exec' commands don't have properties tracking their state. return; } char prop_name[PROP_NAME_MAX]; if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= PROP_NAME_MAX) { // If the property name would be too long, we can't set it. ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n", name, new_state); return; } property_set(prop_name, new_state); } /* add_environment - add "key=value" to the current environment */ int add_environment(const char *key, const char *val) { Loading Loading @@ -145,398 +124,76 @@ int add_environment(const char *key, const char *val) return -1; } void zap_stdio(void) { int fd; fd = open("/dev/null", O_RDWR); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } static void open_console() { int fd; if ((fd = open(console_name.c_str(), O_RDWR)) < 0) { fd = open("/dev/null", O_RDWR); } ioctl(fd, TIOCSCTTY, 0); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } static void publish_socket(const char *name, int fd) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; char val[64]; strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); snprintf(val, sizeof(val), "%d", fd); add_environment(key, val); /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0); } void service_start(struct service *svc, const char *dynamic_args) { // 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)); 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) { return; } bool needs_console = (svc->flags & SVC_CONSOLE); if (needs_console && !have_console) { ERROR("service '%s' requires console\n", svc->name); svc->flags |= SVC_DISABLED; return; } struct stat sb; if (stat(svc->args[0], &sb) == -1) { ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name); svc->flags |= SVC_DISABLED; return; } if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]); svc->flags |= SVC_DISABLED; return; } char* scon = NULL; 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]); int 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); free(mycon); return; } rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon); if (rc == 0 && !strcmp(scon, mycon)) { ERROR("Service %s does not have a SELinux domain defined.\n", svc->name); free(mycon); free(fcon); free(scon); return; } free(mycon); free(fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } } NOTICE("Starting service '%s'...\n", svc->name); pid_t pid = fork(); if (pid == 0) { struct socketinfo *si; struct svcenvinfo *ei; char tmp[32]; int fd, sz; umask(077); if (properties_initialized()) { get_property_workspace(&fd, &sz); snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } for (ei = svc->envvars; ei; ei = ei->next) add_environment(ei->name, ei->value); for (si = svc->sockets; si; si = si->next) { 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); } } free(scon); scon = NULL; if (svc->writepid_files_) { std::string pid_str = android::base::StringPrintf("%d", pid); for (auto& file : *svc->writepid_files_) { if (!android::base::WriteStringToFile(pid_str, file)) { ERROR("couldn't write %s to %s: %s\n", pid_str.c_str(), file.c_str(), strerror(errno)); } } } 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 (false) { for (size_t n = 0; svc->args[n]; n++) { INFO("args[%zu] = '%s'\n", n, svc->args[n]); } for (size_t n = 0; ENV[n]; n++) { INFO("env[%zu] = '%s'\n", n, ENV[n]); } } setpgid(0, getpid()); // As requested, set our gid, supplemental gids, and uid. if (svc->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) { if (setuid(svc->uid) != 0) { ERROR("setuid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->seclabel) { if (setexeccon(svc->seclabel) < 0) { ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno)); _exit(127); } } if (!dynamic_args) { if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { 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] = NULL; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } free(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 ((svc->flags & SVC_EXEC) != 0) { INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n", svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel ? : "default"); waiting_for_exec = true; } svc->NotifyStateChange("running"); } /* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */ static void service_stop_or_reset(struct service *svc, int how) { /* The service is still SVC_RUNNING until its process exits, but if it has * already exited it shoudn't attempt a restart yet. */ svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START); if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) { /* Hrm, an illegal flag. Default to SVC_DISABLED */ how = SVC_DISABLED; } /* if the service has not yet started, prevent * it from auto-starting with its class */ if (how == SVC_RESET) { svc->flags |= (svc->flags & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET; } else { svc->flags |= how; } if (svc->pid) { NOTICE("Service '%s' is being killed...\n", svc->name); kill(-svc->pid, SIGKILL); svc->NotifyStateChange("stopping"); } else { svc->NotifyStateChange("stopped"); } } void service_reset(struct service *svc) { service_stop_or_reset(svc, SVC_RESET); } void service_stop(struct service *svc) { service_stop_or_reset(svc, SVC_DISABLED); } void service_restart(struct service *svc) { if (svc->flags & SVC_RUNNING) { /* Stop, wait, then start the service. */ service_stop_or_reset(svc, SVC_RESTART); } else if (!(svc->flags & SVC_RESTARTING)) { /* Just start the service since it's not running. */ service_start(svc, NULL); } /* else: Service is restarting anyways. */ } void property_changed(const char *name, const char *value) { if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyTrigger(name, value); } static void restart_service_if_needed(struct service *svc) { time_t next_start_time = svc->time_started + 5; if (next_start_time <= gettime()) { svc->flags &= (~SVC_RESTARTING); service_start(svc, NULL); return; } if ((next_start_time < process_needs_restart) || (process_needs_restart == 0)) { process_needs_restart = next_start_time; } } static void restart_processes() { process_needs_restart = 0; service_for_each_flags(SVC_RESTARTING, restart_service_if_needed); ServiceManager::GetInstance(). ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) { s->RestartIfNeeded(process_needs_restart); }); } static void msg_start(const char *name) static void msg_start(const std::string& name) { struct service *svc = NULL; char *tmp = NULL; char *args = NULL; Service* svc = nullptr; std::vector<std::string> vargs; if (!strchr(name, ':')) svc = service_find_by_name(name); else { tmp = strdup(name); if (tmp) { args = strchr(tmp, ':'); *args = '\0'; args++; size_t colon_pos = name.find(':'); if (colon_pos == std::string::npos) { svc = ServiceManager::GetInstance().FindServiceByName(name); } else { std::string service_name(name.substr(0, colon_pos)); std::string args(name.substr(colon_pos + 1)); vargs = android::base::Split(args, " "); svc = service_find_by_name(tmp); } svc = ServiceManager::GetInstance().FindServiceByName(service_name); } if (svc) { service_start(svc, args); svc->Start(vargs); } else { ERROR("no such service '%s'\n", name); ERROR("no such service '%s'\n", name.c_str()); } if (tmp) free(tmp); } static void msg_stop(const char *name) static void msg_stop(const std::string& name) { struct service *svc = service_find_by_name(name); Service* svc = ServiceManager::GetInstance().FindServiceByName(name); if (svc) { service_stop(svc); svc->Stop(); } else { ERROR("no such service '%s'\n", name); ERROR("no such service '%s'\n", name.c_str()); } } static void msg_restart(const char *name) static void msg_restart(const std::string& name) { struct service *svc = service_find_by_name(name); Service* svc = ServiceManager::GetInstance().FindServiceByName(name); if (svc) { service_restart(svc); svc->Restart(); } else { ERROR("no such service '%s'\n", name); ERROR("no such service '%s'\n", name.c_str()); } } void handle_control_message(const char *msg, const char *arg) void handle_control_message(const std::string& msg, const std::string& arg) { if (!strcmp(msg,"start")) { if (msg == "start") { msg_start(arg); } else if (!strcmp(msg,"stop")) { } else if (msg == "stop") { msg_stop(arg); } else if (!strcmp(msg,"restart")) { } else if (msg == "restart") { msg_restart(arg); } else { ERROR("unknown control msg '%s'\n", msg); ERROR("unknown control msg '%s'\n", msg.c_str()); } } Loading init/init.h +7 −96 Original line number Diff line number Diff line Loading @@ -17,117 +17,28 @@ #ifndef _INIT_INIT_H #define _INIT_INIT_H #include <sys/types.h> #include <stdlib.h> #include <list> #include <map> #include <string> #include <vector> #include <cutils/list.h> #include <cutils/iosched_policy.h> class Action; struct socketinfo { struct socketinfo *next; const char *name; const char *type; uid_t uid; gid_t gid; int perm; const char *socketcon; }; struct svcenvinfo { struct svcenvinfo *next; const char *name; const char *value; }; #define SVC_DISABLED 0x001 // do not autostart with class #define SVC_ONESHOT 0x002 // do not restart on exit #define SVC_RUNNING 0x004 // currently active #define SVC_RESTARTING 0x008 // waiting to restart #define SVC_CONSOLE 0x010 // requires console #define SVC_CRITICAL 0x020 // will reboot into recovery if keeps crashing #define SVC_RESET 0x040 // Use when stopping a process, but not disabling so it can be restarted with its class. #define SVC_RC_DISABLED 0x080 // Remember if the disabled flag was set in the rc script. #define SVC_RESTART 0x100 // Use to safely restart (stop, wait, start) a service. #define SVC_DISABLED_START 0x200 // A start was requested but it was disabled at the time. #define SVC_EXEC 0x400 // This synthetic service corresponds to an 'exec'. #define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ class Service; #define COMMAND_RETRY_TIMEOUT 5 struct service { void NotifyStateChange(const char* new_state); /* list of all services */ struct listnode slist; char *name; const char *classname; unsigned flags; pid_t pid; time_t time_started; /* time of last start */ time_t time_crashed; /* first crash within inspection window */ int nr_crashed; /* number of times crashed within window */ uid_t uid; gid_t gid; gid_t supp_gids[NR_SVC_SUPP_GIDS]; size_t nr_supp_gids; const char* seclabel; struct socketinfo *sockets; struct svcenvinfo *envvars; Action* onrestart; /* Commands to execute on restart. */ std::vector<std::string>* writepid_files_; /* keycodes for triggering this service via /dev/keychord */ int *keycodes; int nkeycodes; int keychord_id; IoSchedClass ioprio_class; int ioprio_pri; int nargs; /* "MUST BE AT THE END OF THE STRUCT" */ char *args[1]; }; /* ^-------'args' MUST be at the end of this struct! */ extern const char *ENV[32]; extern bool waiting_for_exec; extern int have_console; extern std::string console_name; extern struct selabel_handle *sehandle; extern struct selabel_handle *sehandle_prop; void handle_control_message(const char *msg, const char *arg); void handle_control_message(const std::string& msg, const std::string& arg); struct service *service_find_by_name(const char *name); struct service *service_find_by_pid(pid_t pid); struct service *service_find_by_keychord(int keychord_id); void service_for_each(void (*func)(struct service *svc)); void service_for_each_class(const char *classname, void (*func)(struct service *svc)); void service_for_each_flags(unsigned matchflags, void (*func)(struct service *svc)); void service_stop(struct service *svc); void service_reset(struct service *svc); void service_restart(struct service *svc); void service_start(struct service *svc, const char *dynamic_args); void property_changed(const char *name, const char *value); int selinux_reload_policy(void); void zap_stdio(void); void register_epoll_handler(int fd, void (*fn)()); int add_environment(const char* key, const char* val); #endif /* _INIT_INIT_H */ Loading
init/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ LOCAL_SRC_FILES:= \ init_parser.cpp \ log.cpp \ parser.cpp \ service.cpp \ util.cpp \ LOCAL_STATIC_LIBRARIES := libbase Loading
init/builtins.cpp +35 −46 Original line number Diff line number Diff line Loading @@ -44,20 +44,19 @@ #include <private/android_filesystem_config.h> #include "action.h" #include "devices.h" #include "init.h" #include "init_parser.h" #include "keywords.h" #include "log.h" #include "property_service.h" #include "devices.h" #include "init_parser.h" #include "service.h" #include "util.h" #include "log.h" #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW #define UNMOUNT_CHECK_MS 5000 #define UNMOUNT_CHECK_TIMES 10 int add_environment(const char *name, const char *value); // System call provided by bionic but not in any header file. extern "C" int init_module(void *, unsigned long, const char *); Loading Loading @@ -100,15 +99,6 @@ done: return ret; } 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; } } static void unmount_and_fsck(const struct mntent *entry) { if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4")) Loading @@ -131,7 +121,7 @@ static void unmount_and_fsck(const struct mntent *entry) * automatically restart after kill(), but that is not really a problem * because |entry->mnt_dir| is no longer visible to such new processes. */ service_for_each(service_stop); ServiceManager::GetInstance().ForEachService([] (Service* s) { s->Stop(); }); TEMP_FAILURE_RETRY(kill(-1, SIGKILL)); int count = 0; Loading Loading @@ -176,19 +166,22 @@ int do_class_start(const std::vector<std::string>& args) * which are explicitly disabled. They must * be started individually. */ service_for_each_class(args[1].c_str(), service_start_if_not_disabled); ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); }); return 0; } int do_class_stop(const std::vector<std::string>& args) { service_for_each_class(args[1].c_str(), service_stop); ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); }); return 0; } int do_class_reset(const std::vector<std::string>& args) { service_for_each_class(args[1].c_str(), service_reset); ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); }); return 0; } Loading @@ -199,30 +192,22 @@ int do_domainname(const std::vector<std::string>& args) int do_enable(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED); if (svc->flags & SVC_DISABLED_START) { service_start(svc, NULL); } } else { Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { return -1; } return 0; return svc->Enable(); } int do_exec(const std::vector<std::string>& args) { std::vector<char*> strs; strs.reserve(args.size()); for (const auto& s : args) { strs.push_back(const_cast<char*>(s.c_str())); Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args); if (!svc) { return -1; } service* svc = make_exec_oneshot_service(strs.size(), &strs[0]); if (svc == NULL) { if (!svc->Start()) { return -1; } service_start(svc, NULL); waiting_for_exec = true; return 0; } Loading Loading @@ -567,31 +552,35 @@ int do_setrlimit(const std::vector<std::string>& args) int do_start(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { service_start(svc, NULL); Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { ERROR("do_start: Service %s not found\n", args[1].c_str()); return -1; } if (!svc->Start()) return -1; return 0; } int do_stop(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { service_stop(svc); Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { ERROR("do_stop: Service %s not found\n", args[1].c_str()); return -1; } svc->Stop(); return 0; } int do_restart(const std::vector<std::string>& args) { struct service *svc; svc = service_find_by_name(args[1].c_str()); if (svc) { service_restart(svc); Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]); if (!svc) { ERROR("do_restart: Service %s not found\n", args[1].c_str()); return -1; } svc->Restart(); return 0; } Loading
init/init.cpp +40 −383 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ #include <sys/types.h> #include <sys/un.h> #include <sys/wait.h> #include <termios.h> #include <unistd.h> #include <mtd/mtd-user.h> Loading @@ -54,16 +53,17 @@ #include <memory> #include "action.h" #include "bootchart.h" #include "devices.h" #include "init.h" #include "init_parser.h" #include "keychords.h" #include "log.h" #include "property_service.h" #include "bootchart.h" #include "service.h" #include "signal_handler.h" #include "keychords.h" #include "init_parser.h" #include "util.h" #include "ueventd.h" #include "util.h" #include "watchdogd.h" struct selabel_handle *sehandle; Loading @@ -73,11 +73,11 @@ static int property_triggers_enabled = 0; static char qemu[32]; static int have_console; static std::string console_name = "/dev/console"; int have_console; std::string console_name = "/dev/console"; static time_t process_needs_restart; static const char *ENV[32]; const char *ENV[32]; bool waiting_for_exec = false; Loading @@ -92,27 +92,6 @@ void register_epoll_handler(int fd, void (*fn)()) { } } void service::NotifyStateChange(const char* new_state) { if (!properties_initialized()) { // If properties aren't available yet, we can't set them. return; } if ((flags & SVC_EXEC) != 0) { // 'exec' commands don't have properties tracking their state. return; } char prop_name[PROP_NAME_MAX]; if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= PROP_NAME_MAX) { // If the property name would be too long, we can't set it. ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n", name, new_state); return; } property_set(prop_name, new_state); } /* add_environment - add "key=value" to the current environment */ int add_environment(const char *key, const char *val) { Loading Loading @@ -145,398 +124,76 @@ int add_environment(const char *key, const char *val) return -1; } void zap_stdio(void) { int fd; fd = open("/dev/null", O_RDWR); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } static void open_console() { int fd; if ((fd = open(console_name.c_str(), O_RDWR)) < 0) { fd = open("/dev/null", O_RDWR); } ioctl(fd, TIOCSCTTY, 0); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } static void publish_socket(const char *name, int fd) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; char val[64]; strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); snprintf(val, sizeof(val), "%d", fd); add_environment(key, val); /* make sure we don't close-on-exec */ fcntl(fd, F_SETFD, 0); } void service_start(struct service *svc, const char *dynamic_args) { // 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)); 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) { return; } bool needs_console = (svc->flags & SVC_CONSOLE); if (needs_console && !have_console) { ERROR("service '%s' requires console\n", svc->name); svc->flags |= SVC_DISABLED; return; } struct stat sb; if (stat(svc->args[0], &sb) == -1) { ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name); svc->flags |= SVC_DISABLED; return; } if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]); svc->flags |= SVC_DISABLED; return; } char* scon = NULL; 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]); int 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); free(mycon); return; } rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon); if (rc == 0 && !strcmp(scon, mycon)) { ERROR("Service %s does not have a SELinux domain defined.\n", svc->name); free(mycon); free(fcon); free(scon); return; } free(mycon); free(fcon); if (rc < 0) { ERROR("could not get context while starting '%s'\n", svc->name); return; } } NOTICE("Starting service '%s'...\n", svc->name); pid_t pid = fork(); if (pid == 0) { struct socketinfo *si; struct svcenvinfo *ei; char tmp[32]; int fd, sz; umask(077); if (properties_initialized()) { get_property_workspace(&fd, &sz); snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz); add_environment("ANDROID_PROPERTY_WORKSPACE", tmp); } for (ei = svc->envvars; ei; ei = ei->next) add_environment(ei->name, ei->value); for (si = svc->sockets; si; si = si->next) { 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); } } free(scon); scon = NULL; if (svc->writepid_files_) { std::string pid_str = android::base::StringPrintf("%d", pid); for (auto& file : *svc->writepid_files_) { if (!android::base::WriteStringToFile(pid_str, file)) { ERROR("couldn't write %s to %s: %s\n", pid_str.c_str(), file.c_str(), strerror(errno)); } } } 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 (false) { for (size_t n = 0; svc->args[n]; n++) { INFO("args[%zu] = '%s'\n", n, svc->args[n]); } for (size_t n = 0; ENV[n]; n++) { INFO("env[%zu] = '%s'\n", n, ENV[n]); } } setpgid(0, getpid()); // As requested, set our gid, supplemental gids, and uid. if (svc->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) { if (setuid(svc->uid) != 0) { ERROR("setuid failed: %s\n", strerror(errno)); _exit(127); } } if (svc->seclabel) { if (setexeccon(svc->seclabel) < 0) { ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno)); _exit(127); } } if (!dynamic_args) { if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) { 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] = NULL; execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); } _exit(127); } free(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 ((svc->flags & SVC_EXEC) != 0) { INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n", svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel ? : "default"); waiting_for_exec = true; } svc->NotifyStateChange("running"); } /* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */ static void service_stop_or_reset(struct service *svc, int how) { /* The service is still SVC_RUNNING until its process exits, but if it has * already exited it shoudn't attempt a restart yet. */ svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START); if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) { /* Hrm, an illegal flag. Default to SVC_DISABLED */ how = SVC_DISABLED; } /* if the service has not yet started, prevent * it from auto-starting with its class */ if (how == SVC_RESET) { svc->flags |= (svc->flags & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET; } else { svc->flags |= how; } if (svc->pid) { NOTICE("Service '%s' is being killed...\n", svc->name); kill(-svc->pid, SIGKILL); svc->NotifyStateChange("stopping"); } else { svc->NotifyStateChange("stopped"); } } void service_reset(struct service *svc) { service_stop_or_reset(svc, SVC_RESET); } void service_stop(struct service *svc) { service_stop_or_reset(svc, SVC_DISABLED); } void service_restart(struct service *svc) { if (svc->flags & SVC_RUNNING) { /* Stop, wait, then start the service. */ service_stop_or_reset(svc, SVC_RESTART); } else if (!(svc->flags & SVC_RESTARTING)) { /* Just start the service since it's not running. */ service_start(svc, NULL); } /* else: Service is restarting anyways. */ } void property_changed(const char *name, const char *value) { if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyTrigger(name, value); } static void restart_service_if_needed(struct service *svc) { time_t next_start_time = svc->time_started + 5; if (next_start_time <= gettime()) { svc->flags &= (~SVC_RESTARTING); service_start(svc, NULL); return; } if ((next_start_time < process_needs_restart) || (process_needs_restart == 0)) { process_needs_restart = next_start_time; } } static void restart_processes() { process_needs_restart = 0; service_for_each_flags(SVC_RESTARTING, restart_service_if_needed); ServiceManager::GetInstance(). ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) { s->RestartIfNeeded(process_needs_restart); }); } static void msg_start(const char *name) static void msg_start(const std::string& name) { struct service *svc = NULL; char *tmp = NULL; char *args = NULL; Service* svc = nullptr; std::vector<std::string> vargs; if (!strchr(name, ':')) svc = service_find_by_name(name); else { tmp = strdup(name); if (tmp) { args = strchr(tmp, ':'); *args = '\0'; args++; size_t colon_pos = name.find(':'); if (colon_pos == std::string::npos) { svc = ServiceManager::GetInstance().FindServiceByName(name); } else { std::string service_name(name.substr(0, colon_pos)); std::string args(name.substr(colon_pos + 1)); vargs = android::base::Split(args, " "); svc = service_find_by_name(tmp); } svc = ServiceManager::GetInstance().FindServiceByName(service_name); } if (svc) { service_start(svc, args); svc->Start(vargs); } else { ERROR("no such service '%s'\n", name); ERROR("no such service '%s'\n", name.c_str()); } if (tmp) free(tmp); } static void msg_stop(const char *name) static void msg_stop(const std::string& name) { struct service *svc = service_find_by_name(name); Service* svc = ServiceManager::GetInstance().FindServiceByName(name); if (svc) { service_stop(svc); svc->Stop(); } else { ERROR("no such service '%s'\n", name); ERROR("no such service '%s'\n", name.c_str()); } } static void msg_restart(const char *name) static void msg_restart(const std::string& name) { struct service *svc = service_find_by_name(name); Service* svc = ServiceManager::GetInstance().FindServiceByName(name); if (svc) { service_restart(svc); svc->Restart(); } else { ERROR("no such service '%s'\n", name); ERROR("no such service '%s'\n", name.c_str()); } } void handle_control_message(const char *msg, const char *arg) void handle_control_message(const std::string& msg, const std::string& arg) { if (!strcmp(msg,"start")) { if (msg == "start") { msg_start(arg); } else if (!strcmp(msg,"stop")) { } else if (msg == "stop") { msg_stop(arg); } else if (!strcmp(msg,"restart")) { } else if (msg == "restart") { msg_restart(arg); } else { ERROR("unknown control msg '%s'\n", msg); ERROR("unknown control msg '%s'\n", msg.c_str()); } } Loading
init/init.h +7 −96 Original line number Diff line number Diff line Loading @@ -17,117 +17,28 @@ #ifndef _INIT_INIT_H #define _INIT_INIT_H #include <sys/types.h> #include <stdlib.h> #include <list> #include <map> #include <string> #include <vector> #include <cutils/list.h> #include <cutils/iosched_policy.h> class Action; struct socketinfo { struct socketinfo *next; const char *name; const char *type; uid_t uid; gid_t gid; int perm; const char *socketcon; }; struct svcenvinfo { struct svcenvinfo *next; const char *name; const char *value; }; #define SVC_DISABLED 0x001 // do not autostart with class #define SVC_ONESHOT 0x002 // do not restart on exit #define SVC_RUNNING 0x004 // currently active #define SVC_RESTARTING 0x008 // waiting to restart #define SVC_CONSOLE 0x010 // requires console #define SVC_CRITICAL 0x020 // will reboot into recovery if keeps crashing #define SVC_RESET 0x040 // Use when stopping a process, but not disabling so it can be restarted with its class. #define SVC_RC_DISABLED 0x080 // Remember if the disabled flag was set in the rc script. #define SVC_RESTART 0x100 // Use to safely restart (stop, wait, start) a service. #define SVC_DISABLED_START 0x200 // A start was requested but it was disabled at the time. #define SVC_EXEC 0x400 // This synthetic service corresponds to an 'exec'. #define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ class Service; #define COMMAND_RETRY_TIMEOUT 5 struct service { void NotifyStateChange(const char* new_state); /* list of all services */ struct listnode slist; char *name; const char *classname; unsigned flags; pid_t pid; time_t time_started; /* time of last start */ time_t time_crashed; /* first crash within inspection window */ int nr_crashed; /* number of times crashed within window */ uid_t uid; gid_t gid; gid_t supp_gids[NR_SVC_SUPP_GIDS]; size_t nr_supp_gids; const char* seclabel; struct socketinfo *sockets; struct svcenvinfo *envvars; Action* onrestart; /* Commands to execute on restart. */ std::vector<std::string>* writepid_files_; /* keycodes for triggering this service via /dev/keychord */ int *keycodes; int nkeycodes; int keychord_id; IoSchedClass ioprio_class; int ioprio_pri; int nargs; /* "MUST BE AT THE END OF THE STRUCT" */ char *args[1]; }; /* ^-------'args' MUST be at the end of this struct! */ extern const char *ENV[32]; extern bool waiting_for_exec; extern int have_console; extern std::string console_name; extern struct selabel_handle *sehandle; extern struct selabel_handle *sehandle_prop; void handle_control_message(const char *msg, const char *arg); void handle_control_message(const std::string& msg, const std::string& arg); struct service *service_find_by_name(const char *name); struct service *service_find_by_pid(pid_t pid); struct service *service_find_by_keychord(int keychord_id); void service_for_each(void (*func)(struct service *svc)); void service_for_each_class(const char *classname, void (*func)(struct service *svc)); void service_for_each_flags(unsigned matchflags, void (*func)(struct service *svc)); void service_stop(struct service *svc); void service_reset(struct service *svc); void service_restart(struct service *svc); void service_start(struct service *svc, const char *dynamic_args); void property_changed(const char *name, const char *value); int selinux_reload_policy(void); void zap_stdio(void); void register_epoll_handler(int fd, void (*fn)()); int add_environment(const char* key, const char* val); #endif /* _INIT_INIT_H */