diff options
Diffstat (limited to 'init')
-rw-r--r-- | init/builtins.cpp | 9 | ||||
-rw-r--r-- | init/devices.cpp | 10 | ||||
-rw-r--r-- | init/init.cpp | 273 | ||||
-rw-r--r-- | init/init.h | 2 | ||||
-rw-r--r-- | init/init_parser.cpp | 1 | ||||
-rw-r--r-- | init/keychords.cpp | 59 | ||||
-rw-r--r-- | init/keychords.h | 6 | ||||
-rw-r--r-- | init/keywords.h | 2 | ||||
-rw-r--r-- | init/property_service.cpp | 20 | ||||
-rw-r--r-- | init/property_service.h | 2 | ||||
-rw-r--r-- | init/readme.txt | 5 | ||||
-rw-r--r-- | init/signal_handler.cpp | 78 | ||||
-rw-r--r-- | init/signal_handler.h | 4 | ||||
-rw-r--r-- | init/util.cpp | 44 | ||||
-rw-r--r-- | init/util.h | 3 |
15 files changed, 245 insertions, 273 deletions
diff --git a/init/builtins.cpp b/init/builtins.cpp index d0e56ec0c..c03968990 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -487,15 +487,6 @@ int do_swapon_all(int nargs, char **args) return ret; } -int do_setcon(int nargs, char **args) { - if (is_selinux_enabled() <= 0) - return 0; - if (setcon(args[1]) < 0) { - return -errno; - } - return 0; -} - int do_setprop(int nargs, char **args) { const char *name = args[1]; diff --git a/init/devices.cpp b/init/devices.cpp index 96b1696b4..2c7f5a9cd 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -266,7 +266,6 @@ static void make_device(const char *path, static void add_platform_device(const char *path) { int path_len = strlen(path); - struct listnode *node; struct platform_node *bus; const char *name = path; @@ -276,15 +275,6 @@ static void add_platform_device(const char *path) name += 9; } - list_for_each_reverse(node, &platform_names) { - bus = node_to_item(node, struct platform_node, list); - if ((bus->path_len < path_len) && - (path[bus->path_len] == '/') && - !strncmp(path, bus->path, bus->path_len)) - /* subdevice of an existing platform, ignore it */ - return; - } - INFO("adding platform device %s (%s)\n", name, path); bus = (platform_node*) calloc(1, sizeof(struct platform_node)); diff --git a/init/init.cpp b/init/init.cpp index b1d65dbc0..dd74538de 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -25,8 +25,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/epoll.h> #include <sys/mount.h> -#include <sys/poll.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> @@ -82,6 +82,17 @@ static const char *ENV[32]; bool waiting_for_exec = false; +static int epoll_fd = -1; + +void register_epoll_handler(int fd, void (*fn)()) { + epoll_event ev; + ev.events = EPOLLIN; + ev.data.ptr = reinterpret_cast<void*>(fn); + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { + ERROR("epoll_ctl failed: %s\n", strerror(errno)); + } +} + void service::NotifyStateChange(const char* new_state) { if (!properties_initialized()) { // If properties aren't available yet, we can't set them. @@ -603,14 +614,16 @@ void execute_one_command() { } } -static int wait_for_coldboot_done_action(int nargs, char **args) -{ - int ret; - INFO("wait for %s\n", COLDBOOT_DONE); - ret = wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT); - if (ret) +static int wait_for_coldboot_done_action(int nargs, char **args) { + Timer t; + + NOTICE("Waiting for %s...\n", COLDBOOT_DONE); + if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) { ERROR("Timed out waiting for %s\n", COLDBOOT_DONE); - return ret; + } + + NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration()); + return 0; } /* @@ -733,7 +746,7 @@ static int console_init_action(int nargs, char **args) return 0; } -static void import_kernel_nv(char *name, int for_emulator) +static void import_kernel_nv(char *name, bool for_emulator) { char *value = strchr(name, '='); int name_len = strlen(name); @@ -827,35 +840,9 @@ static void process_kernel_cmdline(void) * second pass is only necessary for qemu to export all kernel params * as props. */ - import_kernel_cmdline(0, import_kernel_nv); + import_kernel_cmdline(false, import_kernel_nv); if (qemu[0]) - import_kernel_cmdline(1, import_kernel_nv); -} - -static int property_service_init_action(int nargs, char **args) -{ - /* read any property files on system or data and - * fire up the property service. This must happen - * after the ro.foo properties are set above so - * that /data/local.prop cannot interfere with them. - */ - start_property_service(); - if (get_property_set_fd() < 0) { - ERROR("start_property_service() failed\n"); - exit(1); - } - - return 0; -} - -static int signal_init_action(int nargs, char **args) -{ - signal_init(); - if (get_signal_fd() < 0) { - ERROR("signal_init() failed\n"); - exit(1); - } - return 0; + import_kernel_cmdline(true, import_kernel_nv); } static int queue_property_triggers_action(int nargs, char **args) @@ -866,13 +853,36 @@ static int queue_property_triggers_action(int nargs, char **args) return 0; } -void selinux_init_all_handles(void) +static void selinux_init_all_handles(void) { sehandle = selinux_android_file_context_handle(); selinux_android_set_sehandle(sehandle); sehandle_prop = selinux_android_prop_context_handle(); } +enum selinux_enforcing_status { SELINUX_DISABLED, SELINUX_PERMISSIVE, SELINUX_ENFORCING }; + +static selinux_enforcing_status selinux_status_from_cmdline() { + selinux_enforcing_status status = SELINUX_ENFORCING; + + std::function<void(char*,bool)> fn = [&](char* name, bool in_qemu) { + char *value = strchr(name, '='); + if (value == nullptr) { return; } + *value++ = '\0'; + if (strcmp(name, "androidboot.selinux") == 0) { + if (strcmp(value, "disabled") == 0) { + status = SELINUX_DISABLED; + } else if (strcmp(value, "permissive") == 0) { + status = SELINUX_PERMISSIVE; + } + } + }; + import_kernel_cmdline(false, fn); + + return status; +} + + static bool selinux_is_disabled(void) { if (ALLOW_DISABLE_SELINUX) { @@ -881,12 +891,7 @@ static bool selinux_is_disabled(void) // via the kernel command line "selinux=0". return true; } - - char tmp[PROP_VALUE_MAX]; - if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) { - // SELinux is compiled into the kernel, but we've been told to disable it. - return true; - } + return selinux_status_from_cmdline() == SELINUX_DISABLED; } return false; @@ -895,20 +900,7 @@ static bool selinux_is_disabled(void) static bool selinux_is_enforcing(void) { if (ALLOW_DISABLE_SELINUX) { - char tmp[PROP_VALUE_MAX]; - if (property_get("ro.boot.selinux", tmp) == 0) { - // Property is not set. Assume enforcing. - return true; - } - - if (strcmp(tmp, "permissive") == 0) { - // SELinux is in the kernel, but we've been told to go into permissive mode. - return false; - } - - if (strcmp(tmp, "enforcing") != 0) { - ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp); - } + return selinux_status_from_cmdline() == SELINUX_ENFORCING; } return true; } @@ -940,7 +932,13 @@ static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_ return 0; } -static void selinux_initialize() { +static void security_failure() { + ERROR("Security failure; rebooting into recovery mode...\n"); + android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + while (true) { pause(); } // never reached +} + +static void selinux_initialize(bool in_kernel_domain) { Timer t; selinux_callback cb; @@ -953,19 +951,25 @@ static void selinux_initialize() { return; } - INFO("Loading SELinux policy...\n"); - if (selinux_android_load_policy() < 0) { - ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n"); - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); - while (1) { pause(); } // never reached - } + if (in_kernel_domain) { + INFO("Loading SELinux policy...\n"); + if (selinux_android_load_policy() < 0) { + ERROR("failed to load policy: %s\n", strerror(errno)); + security_failure(); + } - selinux_init_all_handles(); - bool is_enforcing = selinux_is_enforcing(); - INFO("SELinux: security_setenforce(%d)\n", is_enforcing); - security_setenforce(is_enforcing); + bool is_enforcing = selinux_is_enforcing(); + security_setenforce(is_enforcing); - NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration()); + 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(); + } } int main(int argc, char** argv) { @@ -982,21 +986,18 @@ int main(int argc, char** argv) { 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. - mkdir("/dev", 0755); - mkdir("/proc", 0755); - mkdir("/sys", 0755); - - 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); - - // Indicate that booting is in progress to background fw loaders, etc. - close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); + 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); + } // 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 @@ -1006,20 +1007,41 @@ int main(int argc, char** argv) { klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); - NOTICE("init started!\n"); + NOTICE("init%s started!\n", is_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)); - property_init(); + 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(); + // 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(); - // Propogate the kernel variables to internal variables - // used by init as well as the current required properties. - export_kernel_boot_props(); + // Propogate 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. + selinux_initialize(is_first_stage); - selinux_initialize(); + // 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) { + 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. @@ -1030,13 +1052,24 @@ int main(int argc, char** argv) { restorecon("/dev/__properties__"); restorecon_recursive("/sys"); + epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (epoll_fd == -1) { + ERROR("epoll_create1 failed: %s\n", strerror(errno)); + exit(1); + } + + signal_handler_init(); + property_load_boot_defaults(); + start_property_service(); init_parse_config_file("/init.rc"); action_for_each_trigger("early-init", action_add_queue_tail); + // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev... queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); + // ... so that we can start queuing up actions that require stuff from /dev. queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); @@ -1047,8 +1080,6 @@ int main(int argc, char** argv) { // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random // wasn't ready immediately after wait_for_coldboot_done queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); - queue_builtin_action(property_service_init_action, "property_service_init"); - queue_builtin_action(signal_init_action, "signal_init"); // Don't mount filesystems or start core system services in charger mode. char bootmode[PROP_VALUE_MAX]; @@ -1061,41 +1092,12 @@ int main(int argc, char** argv) { // Run all property triggers based on current state of the properties. queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); - // TODO: why do we only initialize ufds after execute_one_command and restart_processes? - size_t fd_count = 0; - struct pollfd ufds[3]; - bool property_set_fd_init = false; - bool signal_fd_init = false; - bool keychord_fd_init = false; - - for (;;) { + while (true) { if (!waiting_for_exec) { execute_one_command(); restart_processes(); } - if (!property_set_fd_init && get_property_set_fd() > 0) { - ufds[fd_count].fd = get_property_set_fd(); - ufds[fd_count].events = POLLIN; - ufds[fd_count].revents = 0; - fd_count++; - property_set_fd_init = true; - } - if (!signal_fd_init && get_signal_fd() > 0) { - ufds[fd_count].fd = get_signal_fd(); - ufds[fd_count].events = POLLIN; - ufds[fd_count].revents = 0; - fd_count++; - signal_fd_init = true; - } - if (!keychord_fd_init && get_keychord_fd() > 0) { - ufds[fd_count].fd = get_keychord_fd(); - ufds[fd_count].events = POLLIN; - ufds[fd_count].revents = 0; - fd_count++; - keychord_fd_init = true; - } - int timeout = -1; if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; @@ -1109,21 +1111,12 @@ int main(int argc, char** argv) { bootchart_sample(&timeout); - int nr = poll(ufds, fd_count, timeout); - if (nr <= 0) { - continue; - } - - for (size_t i = 0; i < fd_count; i++) { - if (ufds[i].revents & POLLIN) { - if (ufds[i].fd == get_property_set_fd()) { - handle_property_set_fd(); - } else if (ufds[i].fd == get_keychord_fd()) { - handle_keychord(); - } else if (ufds[i].fd == get_signal_fd()) { - handle_signal(); - } - } + 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)(); } } diff --git a/init/init.h b/init/init.h index a104af607..1cabb147e 100644 --- a/init/init.h +++ b/init/init.h @@ -155,4 +155,6 @@ int selinux_reload_policy(void); void zap_stdio(void); +void register_epoll_handler(int fd, void (*fn)()); + #endif /* _INIT_INIT_H */ diff --git a/init/init_parser.cpp b/init/init_parser.cpp index ff31093cb..b76b04ee5 100644 --- a/init/init_parser.cpp +++ b/init/init_parser.cpp @@ -184,7 +184,6 @@ static int lookup_keyword(const char *s) case 's': if (!strcmp(s, "eclabel")) return K_seclabel; if (!strcmp(s, "ervice")) return K_service; - if (!strcmp(s, "etcon")) return K_setcon; if (!strcmp(s, "etenv")) return K_setenv; if (!strcmp(s, "etprop")) return K_setprop; if (!strcmp(s, "etrlimit")) return K_setrlimit; diff --git a/init/keychords.cpp b/init/keychords.cpp index 27894a2e8..10d9573f2 100644 --- a/init/keychords.cpp +++ b/init/keychords.cpp @@ -62,37 +62,7 @@ void add_service_keycodes(struct service *svc) } } -void keychord_init() -{ - int fd, ret; - - service_for_each(add_service_keycodes); - - /* nothing to do if no services require keychords */ - if (!keychords) - return; - - fd = open("/dev/keychord", O_RDWR | O_CLOEXEC); - if (fd < 0) { - ERROR("could not open /dev/keychord\n"); - return; - } - - ret = write(fd, keychords, keychords_length); - if (ret != keychords_length) { - ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno)); - close(fd); - fd = -1; - } - - free(keychords); - keychords = 0; - - keychord_fd = fd; -} - -void handle_keychord() -{ +static void handle_keychord() { struct service *svc; char adb_enabled[PROP_VALUE_MAX]; int ret; @@ -117,7 +87,28 @@ void handle_keychord() } } -int get_keychord_fd() -{ - return keychord_fd; +void keychord_init() { + service_for_each(add_service_keycodes); + + // Nothing to do if no services require keychords. + if (!keychords) { + return; + } + + keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC)); + if (keychord_fd == -1) { + ERROR("could not open /dev/keychord: %s\n", strerror(errno)); + return; + } + + int ret = write(keychord_fd, keychords, keychords_length); + if (ret != keychords_length) { + ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno)); + close(keychord_fd); + } + + free(keychords); + keychords = nullptr; + + register_epoll_handler(keychord_fd, handle_keychord); } diff --git a/init/keychords.h b/init/keychords.h index 070b85891..d2723b71c 100644 --- a/init/keychords.h +++ b/init/keychords.h @@ -19,9 +19,7 @@ struct service; -void add_service_keycodes(struct service *svc); -void keychord_init(void); -void handle_keychord(void); -int get_keychord_fd(void); +void add_service_keycodes(service*); +void keychord_init(); #endif diff --git a/init/keywords.h b/init/keywords.h index 059dde126..37f01b861 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -20,7 +20,6 @@ int do_restorecon(int nargs, char **args); int do_restorecon_recursive(int nargs, char **args); int do_rm(int nargs, char **args); int do_rmdir(int nargs, char **args); -int do_setcon(int nargs, char **args); int do_setprop(int nargs, char **args); int do_setrlimit(int nargs, char **args); int do_start(int nargs, char **args); @@ -76,7 +75,6 @@ enum { KEYWORD(rmdir, COMMAND, 1, do_rmdir) KEYWORD(seclabel, OPTION, 0, 0) KEYWORD(service, SECTION, 0, 0) - KEYWORD(setcon, COMMAND, 1, do_setcon) KEYWORD(setenv, OPTION, 2, 0) KEYWORD(setprop, COMMAND, 2, do_setprop) KEYWORD(setrlimit, COMMAND, 3, do_setrlimit) diff --git a/init/property_service.cpp b/init/property_service.cpp index 8544951c1..930ef8213 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -246,7 +246,7 @@ int property_set(const char* name, const char* value) { return rc; } -void handle_property_set_fd() +static void handle_property_set_fd() { prop_msg msg; int s; @@ -519,16 +519,14 @@ void load_all_props() { } void start_property_service() { - int fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); - if (fd == -1) return; - - fcntl(fd, F_SETFD, FD_CLOEXEC); - fcntl(fd, F_SETFL, O_NONBLOCK); + 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(fd, 8); - property_set_fd = fd; -} + listen(property_set_fd, 8); -int get_property_set_fd() { - return property_set_fd; + register_epoll_handler(property_set_fd, handle_property_set_fd); } diff --git a/init/property_service.h b/init/property_service.h index 825a7dd2a..a27053d93 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -20,7 +20,6 @@ #include <stddef.h> #include <sys/system_properties.h> -extern void handle_property_set_fd(void); extern void property_init(void); extern void property_load_boot_defaults(void); extern void load_persist_props(void); @@ -30,7 +29,6 @@ void get_property_workspace(int *fd, int *sz); extern int __property_get(const char *name, char *value); extern int property_set(const char *name, const char *value); extern bool properties_initialized(); -int get_property_set_fd(void); #ifndef __clang__ extern void __property_get_size_error() diff --git a/init/readme.txt b/init/readme.txt index 84afd11d8..6b9c42d3f 100644 --- a/init/readme.txt +++ b/init/readme.txt @@ -252,11 +252,6 @@ rm <path> rmdir <path> Calls rmdir(2) on the given path. -setcon <seclabel> - Set the current process security context to the specified string. - This is typically only used from early-init to set the init context - before any other process is started. - setprop <name> <value> Set system property <name> to <value>. Properties are expanded within <value>. diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp index 8be4af59c..39a466dee 100644 --- a/init/signal_handler.cpp +++ b/init/signal_handler.cpp @@ -35,14 +35,10 @@ #define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */ #define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery */ -static int signal_fd = -1; -static int signal_recv_fd = -1; +static int signal_write_fd = -1; +static int signal_read_fd = -1; -static void sigchld_handler(int s) { - write(signal_fd, &s, 1); -} - -std::string DescribeStatus(int status) { +static std::string DescribeStatus(int status) { if (WIFEXITED(status)) { return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { @@ -54,11 +50,14 @@ std::string DescribeStatus(int status) { } } -static int wait_for_one_process() { +static bool wait_for_one_process() { int status; pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); - if (pid <= 0) { - return -1; + if (pid == 0) { + return false; + } else if (pid == -1) { + ERROR("waitpid failed: %s\n", strerror(errno)); + return false; } service* svc = service_find_by_pid(pid); @@ -73,7 +72,7 @@ static int wait_for_one_process() { NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str()); if (!svc) { - return 0; + return true; } // TODO: all the code from here down should be a member function on service. @@ -96,7 +95,7 @@ static int wait_for_one_process() { list_remove(&svc->slist); free(svc->name); free(svc); - return 0; + return true; } svc->pid = 0; @@ -111,7 +110,7 @@ static int wait_for_one_process() { // Disabled and reset processes do not get restarted automatically. if (svc->flags & (SVC_DISABLED | SVC_RESET)) { svc->NotifyStateChange("stopped"); - return 0; + return true; } time_t now = gettime(); @@ -122,7 +121,7 @@ static int wait_for_one_process() { "rebooting into recovery mode\n", svc->name, CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60); android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); - return 0; + return true; } } else { svc->time_crashed = now; @@ -140,34 +139,47 @@ static int wait_for_one_process() { cmd->func(cmd->nargs, cmd->args); } svc->NotifyStateChange("restarting"); - return 0; + return true; +} + +static void reap_any_outstanding_children() { + while (wait_for_one_process()) { + } +} + +static void handle_signal() { + // Clear outstanding requests. + char buf[32]; + read(signal_read_fd, buf, sizeof(buf)); + + reap_any_outstanding_children(); } -void handle_signal() { - // We got a SIGCHLD - reap and restart as needed. - char tmp[32]; - read(signal_recv_fd, tmp, sizeof(tmp)); - while (!wait_for_one_process()) { +static void SIGCHLD_handler(int) { + if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) { + ERROR("write(signal_write_fd) failed: %s\n", strerror(errno)); } } -void signal_init() { +void signal_handler_init() { + // Create a signalling mechanism for SIGCHLD. + int s[2]; + 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 = 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_handler = SIGCHLD_handler; act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, 0); - // Create a signalling mechanism for the sigchld handler. - int s[2]; - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == 0) { - signal_fd = s[0]; - signal_recv_fd = s[1]; - } - - handle_signal(); -} + reap_any_outstanding_children(); -int get_signal_fd() { - return signal_recv_fd; + register_epoll_handler(signal_read_fd, handle_signal); } diff --git a/init/signal_handler.h b/init/signal_handler.h index b092ccb6e..449b4af80 100644 --- a/init/signal_handler.h +++ b/init/signal_handler.h @@ -17,8 +17,6 @@ #ifndef _INIT_SIGNAL_HANDLER_H_ #define _INIT_SIGNAL_HANDLER_H_ -void signal_init(void); -void handle_signal(void); -int get_signal_fd(void); +void signal_handler_init(void); #endif diff --git a/init/util.cpp b/init/util.cpp index 3b49b30d3..9343145a7 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -179,9 +179,13 @@ bool read_file(const char* path, std::string* content) { int write_file(const char* path, const char* content) { int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600)); if (fd == -1) { - return -errno; + NOTICE("write_file: Unable to open '%s': %s\n", path, strerror(errno)); + return -1; + } + int result = android::base::WriteStringToFd(content, fd) ? 0 : -1; + if (result == -1) { + NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno)); } - int result = android::base::WriteStringToFd(content, fd) ? 0 : -errno; TEMP_FAILURE_RETRY(close(fd)); return result; } @@ -375,27 +379,31 @@ int wait_for_file(const char *filename, int timeout) void open_devnull_stdio(void) { - int fd; - 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 >= 0) { - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - if (fd > 2) { - close(fd); - } - return; + // 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); } } - exit(1); + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) { + close(fd); + } } -void import_kernel_cmdline(int in_qemu, - void (*import_kernel_nv)(char *name, int in_qemu)) +void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv) { char cmdline[2048]; char *ptr; diff --git a/init/util.h b/init/util.h index 8fec7a801..6864acf15 100644 --- a/init/util.h +++ b/init/util.h @@ -21,6 +21,7 @@ #include <sys/types.h> #include <string> +#include <functional> #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) @@ -57,7 +58,7 @@ void make_link(const char *oldpath, const char *newpath); void remove_link(const char *oldpath, const char *newpath); int wait_for_file(const char *filename, int timeout); void open_devnull_stdio(void); -void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu)); +void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>); int make_dir(const char *path, mode_t mode); int restorecon(const char *pathname); int restorecon_recursive(const char *pathname); |