Loading init/builtins.cpp +5 −5 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ #define UNMOUNT_CHECK_MS 5000 #define UNMOUNT_CHECK_TIMES 10 static const int kTerminateServiceDelayMicroSeconds = 50000; static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s; static int insmod(const char *filename, const char *options, int flags) { int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); Loading Loading @@ -444,7 +444,7 @@ static int do_mount(const std::vector<std::string>& args) { return -1; } else { if (wait) wait_for_file(source, COMMAND_RETRY_TIMEOUT); wait_for_file(source, kCommandRetryTimeout); if (mount(source, target, system, flags, options) < 0) { return -1; } Loading Loading @@ -749,7 +749,7 @@ static int do_powerctl(const std::vector<std::string>& args) { } // Wait a bit before recounting the number or running services. usleep(kTerminateServiceDelayMicroSeconds); usleep(50000 /*us*/); } LOG(VERBOSE) << "Terminating running services took " << t.duration() << " seconds"; } Loading Loading @@ -956,11 +956,11 @@ static int do_load_system_props(const std::vector<std::string>& args) { static int do_wait(const std::vector<std::string>& args) { if (args.size() == 2) { return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT); return wait_for_file(args[1].c_str(), kCommandRetryTimeout); } else if (args.size() == 3) { int timeout; if (android::base::ParseInt(args[2], &timeout)) { return wait_for_file(args[1].c_str(), timeout); return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout)); } } return -1; Loading init/init.cpp +43 −34 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <libgen.h> #include <paths.h> #include <signal.h> Loading Loading @@ -67,6 +68,8 @@ #include "util.h" #include "watchdogd.h" using android::base::StringPrintf; struct selabel_handle *sehandle; struct selabel_handle *sehandle_prop; Loading @@ -75,7 +78,7 @@ static int property_triggers_enabled = 0; static char qemu[32]; std::string default_console = "/dev/console"; static time_t process_needs_restart; static time_t process_needs_restart_at; const char *ENV[32]; Loading Loading @@ -132,10 +135,9 @@ void property_changed(const char *name, const char *value) static void restart_processes() { process_needs_restart = 0; ServiceManager::GetInstance(). ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) { s->RestartIfNeeded(process_needs_restart); process_needs_restart_at = 0; ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) { s->RestartIfNeeded(&process_needs_restart_at); }); } Loading Loading @@ -164,7 +166,7 @@ static int wait_for_coldboot_done_action(const std::vector<std::string>& args) { // Any longer than 1s is an unreasonable length of time to delay booting. // If you're hitting this timeout, check that you didn't make your // sepolicy regular expressions too expensive (http://b/19899875). if (wait_for_file(COLDBOOT_DONE, 1)) { if (wait_for_file(COLDBOOT_DONE, 1s)) { LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE; } Loading Loading @@ -268,15 +270,14 @@ static void import_kernel_nv(const std::string& key, const std::string& value, b if (for_emulator) { // In the emulator, export any kernel option with the "ro.kernel." prefix. property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str()); property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str()); return; } if (key == "qemu") { strlcpy(qemu, value.c_str(), sizeof(qemu)); } else if (android::base::StartsWith(key, "androidboot.")) { property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str()); property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str()); } } Loading Loading @@ -314,7 +315,7 @@ static void export_kernel_boot_props() { static void process_kernel_dt() { static const char android_dir[] = "/proc/device-tree/firmware/android"; std::string file_name = android::base::StringPrintf("%s/compatible", android_dir); std::string file_name = StringPrintf("%s/compatible", android_dir); std::string dt_file; android::base::ReadFileToString(file_name, &dt_file); Loading @@ -332,12 +333,12 @@ static void process_kernel_dt() { continue; } file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name); file_name = StringPrintf("%s/%s", android_dir, dp->d_name); android::base::ReadFileToString(file_name, &dt_file); std::replace(dt_file.begin(), dt_file.end(), ',', '.'); std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name); std::string property_name = StringPrintf("ro.boot.%s", dp->d_name); property_set(property_name.c_str(), dt_file.c_str()); } } Loading Loading @@ -566,12 +567,14 @@ int main(int argc, char** argv) { return watchdogd_main(argc, argv); } boot_clock::time_point start_time = boot_clock::now(); // Clear the umask. umask(0); add_environment("PATH", _PATH_DEFPATH); bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0); bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr); // Don't expose the raw commandline to unprivileged processes. chmod("/proc/cmdline", 0440); Loading @@ -596,32 +599,34 @@ int main(int argc, char** argv) { // talk to the outside world... InitKernelLogging(argv); if (is_first_stage) { LOG(INFO) << "init first stage started!"; LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!"; if (is_first_stage) { // Mount devices defined in android.early.* kernel commandline early_mount(); // Set up SELinux, including loading the SELinux policy if we're in the kernel domain. // Set up SELinux, loading the SELinux policy. selinux_initialize(true); // If we're in the kernel domain, re-exec init to transition to the init domain now // We're in the kernel domain, so re-exec init to transition to the init domain now // that the SELinux policy has been loaded. if (restorecon("/init") == -1) { PLOG(ERROR) << "restorecon failed"; security_failure(); } setenv("INIT_SECOND_STAGE", "true", 1); uint64_t start_ns = start_time.time_since_epoch().count(); setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ns).c_str(), 1); char* path = argv[0]; char* args[] = { path, const_cast<char*>("--second-stage"), nullptr }; char* args[] = { path, nullptr }; if (execv(path, args) == -1) { PLOG(ERROR) << "execv(\"" << path << "\") failed"; security_failure(); } } else { LOG(INFO) << "init second stage started!"; // Indicate that booting is in progress to background fw loaders, etc. close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); Loading @@ -636,7 +641,10 @@ int main(int argc, char** argv) { // used by init as well as the current required properties. export_kernel_boot_props(); // Now set up SELinux for second stage // Make the time that init started available for bootstat to log. property_set("init.start", getenv("INIT_STARTED_AT")); // Now set up SELinux for second stage. selinux_initialize(false); } Loading Loading @@ -710,21 +718,22 @@ int main(int argc, char** argv) { restart_processes(); } int timeout = -1; if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } // By default, sleep until something happens. int epoll_timeout_ms = -1; // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout_ms = 0; if (am.HasMoreCommands()) { timeout = 0; // If there's a process that needs restarting, wake up in time for that. if (process_needs_restart_at != 0) { epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000; if (epoll_timeout_ms < 0) epoll_timeout_ms = 0; } bootchart_sample(&timeout); bootchart_sample(&epoll_timeout_ms); epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout)); int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms)); if (nr == -1) { PLOG(ERROR) << "epoll_wait failed"; } else if (nr == 1) { Loading init/init.h +0 −2 Original line number Diff line number Diff line Loading @@ -22,8 +22,6 @@ class Action; class Service; #define COMMAND_RETRY_TIMEOUT 5 extern const char *ENV[32]; extern bool waiting_for_exec; extern std::string default_console; Loading init/readme.txt +13 −5 Original line number Diff line number Diff line Loading @@ -440,9 +440,17 @@ Properties Init provides information about the services that it is responsible for via the below properties. init.start Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first stage of init started. init.svc.<name> State of a named service ("stopped", "stopping", "running", "restarting") init.svc.<name>.start Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was most recently started. Bootcharting ------------ Loading Loading @@ -537,10 +545,10 @@ service akmd /system/bin/logwrapper /sbin/akmd For quicker turnaround when working on init itself, use: mm -j m ramdisk-nodeps m bootimage-nodeps adb reboot bootloader mm -j && m ramdisk-nodeps && m bootimage-nodeps && adb reboot bootloader && fastboot boot $ANDROID_PRODUCT_OUT/boot.img Alternatively, use the emulator: Loading init/service.cpp +25 −22 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "service.h" #include <fcntl.h> #include <inttypes.h> #include <linux/securebits.h> #include <sched.h> #include <sys/mount.h> Loading Loading @@ -51,9 +52,6 @@ using android::base::ParseInt; using android::base::StringPrintf; using android::base::WriteStringToFile; #define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ... #define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery static std::string ComputeContextFromExecutable(std::string& service_name, const std::string& service_path) { std::string computed_context; Loading Loading @@ -154,8 +152,8 @@ ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name, Service::Service(const std::string& name, const std::string& classname, const std::vector<std::string>& args) : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0), : name_(name), classname_(classname), flags_(0), pid_(0), crash_count_(0), uid_(0), gid_(0), namespace_flags_(0), seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0), oom_score_adjust_(-1000), args_(args) { onrestart_.InitSingleTrigger("onrestart"); Loading @@ -168,7 +166,7 @@ Service::Service(const std::string& name, const std::string& classname, const std::string& seclabel, const std::vector<std::string>& args) : name_(name), classname_(classname), flags_(flags), pid_(0), time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid), crash_count_(0), uid_(uid), gid_(gid), supp_gids_(supp_gids), capabilities_(capabilities), namespace_flags_(namespace_flags), seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0), Loading @@ -190,6 +188,12 @@ void Service::NotifyStateChange(const std::string& new_state) const { } property_set(prop_name.c_str(), new_state.c_str()); if (new_state == "running") { prop_name += ".start"; uint64_t start_ns = time_started_.time_since_epoch().count(); property_set(prop_name.c_str(), StringPrintf("%" PRIu64, start_ns).c_str()); } } void Service::KillProcessGroup(int signal) { Loading Loading @@ -274,20 +278,19 @@ bool Service::Reap() { return false; } time_t now = gettime(); // If we crash > 4 times in 4 minutes, reboot into recovery. boot_clock::time_point now = boot_clock::now(); if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) { if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) { if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) { LOG(ERROR) << "critical process '" << name_ << "' exited " << CRITICAL_CRASH_THRESHOLD << " times in " << (CRITICAL_CRASH_WINDOW / 60) << " minutes; " if (now < time_crashed_ + 4min) { if (++crash_count_ > 4) { LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes; " << "rebooting into recovery mode"; android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); return false; } } else { time_crashed_ = now; nr_crashed_ = 1; crash_count_ = 1; } } Loading Loading @@ -553,7 +556,6 @@ bool Service::Start() { // 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. flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); 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 Loading Loading @@ -667,7 +669,7 @@ bool Service::Start() { } } time_started_ = gettime(); time_started_ = boot_clock::now(); pid_ = pid; flags_ |= SVC_RUNNING; Loading Loading @@ -731,18 +733,19 @@ void Service::Restart() { } /* else: Service is restarting anyways. */ } void Service::RestartIfNeeded(time_t& process_needs_restart) { time_t next_start_time = time_started_ + 5; if (next_start_time <= gettime()) { void Service::RestartIfNeeded(time_t* process_needs_restart_at) { boot_clock::time_point now = boot_clock::now(); boot_clock::time_point next_start = time_started_ + 5s; if (now > next_start) { flags_ &= (~SVC_RESTARTING); Start(); return; } if ((next_start_time < process_needs_restart) || (process_needs_restart == 0)) { process_needs_restart = next_start_time; time_t next_start_time_t = time(nullptr) + time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count()); if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) { *process_needs_restart_at = next_start_time_t; } } Loading Loading
init/builtins.cpp +5 −5 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ #define UNMOUNT_CHECK_MS 5000 #define UNMOUNT_CHECK_TIMES 10 static const int kTerminateServiceDelayMicroSeconds = 50000; static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s; static int insmod(const char *filename, const char *options, int flags) { int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); Loading Loading @@ -444,7 +444,7 @@ static int do_mount(const std::vector<std::string>& args) { return -1; } else { if (wait) wait_for_file(source, COMMAND_RETRY_TIMEOUT); wait_for_file(source, kCommandRetryTimeout); if (mount(source, target, system, flags, options) < 0) { return -1; } Loading Loading @@ -749,7 +749,7 @@ static int do_powerctl(const std::vector<std::string>& args) { } // Wait a bit before recounting the number or running services. usleep(kTerminateServiceDelayMicroSeconds); usleep(50000 /*us*/); } LOG(VERBOSE) << "Terminating running services took " << t.duration() << " seconds"; } Loading Loading @@ -956,11 +956,11 @@ static int do_load_system_props(const std::vector<std::string>& args) { static int do_wait(const std::vector<std::string>& args) { if (args.size() == 2) { return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT); return wait_for_file(args[1].c_str(), kCommandRetryTimeout); } else if (args.size() == 3) { int timeout; if (android::base::ParseInt(args[2], &timeout)) { return wait_for_file(args[1].c_str(), timeout); return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout)); } } return -1; Loading
init/init.cpp +43 −34 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <libgen.h> #include <paths.h> #include <signal.h> Loading Loading @@ -67,6 +68,8 @@ #include "util.h" #include "watchdogd.h" using android::base::StringPrintf; struct selabel_handle *sehandle; struct selabel_handle *sehandle_prop; Loading @@ -75,7 +78,7 @@ static int property_triggers_enabled = 0; static char qemu[32]; std::string default_console = "/dev/console"; static time_t process_needs_restart; static time_t process_needs_restart_at; const char *ENV[32]; Loading Loading @@ -132,10 +135,9 @@ void property_changed(const char *name, const char *value) static void restart_processes() { process_needs_restart = 0; ServiceManager::GetInstance(). ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) { s->RestartIfNeeded(process_needs_restart); process_needs_restart_at = 0; ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) { s->RestartIfNeeded(&process_needs_restart_at); }); } Loading Loading @@ -164,7 +166,7 @@ static int wait_for_coldboot_done_action(const std::vector<std::string>& args) { // Any longer than 1s is an unreasonable length of time to delay booting. // If you're hitting this timeout, check that you didn't make your // sepolicy regular expressions too expensive (http://b/19899875). if (wait_for_file(COLDBOOT_DONE, 1)) { if (wait_for_file(COLDBOOT_DONE, 1s)) { LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE; } Loading Loading @@ -268,15 +270,14 @@ static void import_kernel_nv(const std::string& key, const std::string& value, b if (for_emulator) { // In the emulator, export any kernel option with the "ro.kernel." prefix. property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str()); property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str()); return; } if (key == "qemu") { strlcpy(qemu, value.c_str(), sizeof(qemu)); } else if (android::base::StartsWith(key, "androidboot.")) { property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str()); property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str()); } } Loading Loading @@ -314,7 +315,7 @@ static void export_kernel_boot_props() { static void process_kernel_dt() { static const char android_dir[] = "/proc/device-tree/firmware/android"; std::string file_name = android::base::StringPrintf("%s/compatible", android_dir); std::string file_name = StringPrintf("%s/compatible", android_dir); std::string dt_file; android::base::ReadFileToString(file_name, &dt_file); Loading @@ -332,12 +333,12 @@ static void process_kernel_dt() { continue; } file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name); file_name = StringPrintf("%s/%s", android_dir, dp->d_name); android::base::ReadFileToString(file_name, &dt_file); std::replace(dt_file.begin(), dt_file.end(), ',', '.'); std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name); std::string property_name = StringPrintf("ro.boot.%s", dp->d_name); property_set(property_name.c_str(), dt_file.c_str()); } } Loading Loading @@ -566,12 +567,14 @@ int main(int argc, char** argv) { return watchdogd_main(argc, argv); } boot_clock::time_point start_time = boot_clock::now(); // Clear the umask. umask(0); add_environment("PATH", _PATH_DEFPATH); bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0); bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr); // Don't expose the raw commandline to unprivileged processes. chmod("/proc/cmdline", 0440); Loading @@ -596,32 +599,34 @@ int main(int argc, char** argv) { // talk to the outside world... InitKernelLogging(argv); if (is_first_stage) { LOG(INFO) << "init first stage started!"; LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!"; if (is_first_stage) { // Mount devices defined in android.early.* kernel commandline early_mount(); // Set up SELinux, including loading the SELinux policy if we're in the kernel domain. // Set up SELinux, loading the SELinux policy. selinux_initialize(true); // If we're in the kernel domain, re-exec init to transition to the init domain now // We're in the kernel domain, so re-exec init to transition to the init domain now // that the SELinux policy has been loaded. if (restorecon("/init") == -1) { PLOG(ERROR) << "restorecon failed"; security_failure(); } setenv("INIT_SECOND_STAGE", "true", 1); uint64_t start_ns = start_time.time_since_epoch().count(); setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ns).c_str(), 1); char* path = argv[0]; char* args[] = { path, const_cast<char*>("--second-stage"), nullptr }; char* args[] = { path, nullptr }; if (execv(path, args) == -1) { PLOG(ERROR) << "execv(\"" << path << "\") failed"; security_failure(); } } else { LOG(INFO) << "init second stage started!"; // Indicate that booting is in progress to background fw loaders, etc. close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); Loading @@ -636,7 +641,10 @@ int main(int argc, char** argv) { // used by init as well as the current required properties. export_kernel_boot_props(); // Now set up SELinux for second stage // Make the time that init started available for bootstat to log. property_set("init.start", getenv("INIT_STARTED_AT")); // Now set up SELinux for second stage. selinux_initialize(false); } Loading Loading @@ -710,21 +718,22 @@ int main(int argc, char** argv) { restart_processes(); } int timeout = -1; if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } // By default, sleep until something happens. int epoll_timeout_ms = -1; // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout_ms = 0; if (am.HasMoreCommands()) { timeout = 0; // If there's a process that needs restarting, wake up in time for that. if (process_needs_restart_at != 0) { epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000; if (epoll_timeout_ms < 0) epoll_timeout_ms = 0; } bootchart_sample(&timeout); bootchart_sample(&epoll_timeout_ms); epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout)); int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms)); if (nr == -1) { PLOG(ERROR) << "epoll_wait failed"; } else if (nr == 1) { Loading
init/init.h +0 −2 Original line number Diff line number Diff line Loading @@ -22,8 +22,6 @@ class Action; class Service; #define COMMAND_RETRY_TIMEOUT 5 extern const char *ENV[32]; extern bool waiting_for_exec; extern std::string default_console; Loading
init/readme.txt +13 −5 Original line number Diff line number Diff line Loading @@ -440,9 +440,17 @@ Properties Init provides information about the services that it is responsible for via the below properties. init.start Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first stage of init started. init.svc.<name> State of a named service ("stopped", "stopping", "running", "restarting") init.svc.<name>.start Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was most recently started. Bootcharting ------------ Loading Loading @@ -537,10 +545,10 @@ service akmd /system/bin/logwrapper /sbin/akmd For quicker turnaround when working on init itself, use: mm -j m ramdisk-nodeps m bootimage-nodeps adb reboot bootloader mm -j && m ramdisk-nodeps && m bootimage-nodeps && adb reboot bootloader && fastboot boot $ANDROID_PRODUCT_OUT/boot.img Alternatively, use the emulator: Loading
init/service.cpp +25 −22 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "service.h" #include <fcntl.h> #include <inttypes.h> #include <linux/securebits.h> #include <sched.h> #include <sys/mount.h> Loading Loading @@ -51,9 +52,6 @@ using android::base::ParseInt; using android::base::StringPrintf; using android::base::WriteStringToFile; #define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ... #define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery static std::string ComputeContextFromExecutable(std::string& service_name, const std::string& service_path) { std::string computed_context; Loading Loading @@ -154,8 +152,8 @@ ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name, Service::Service(const std::string& name, const std::string& classname, const std::vector<std::string>& args) : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0), : name_(name), classname_(classname), flags_(0), pid_(0), crash_count_(0), uid_(0), gid_(0), namespace_flags_(0), seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0), oom_score_adjust_(-1000), args_(args) { onrestart_.InitSingleTrigger("onrestart"); Loading @@ -168,7 +166,7 @@ Service::Service(const std::string& name, const std::string& classname, const std::string& seclabel, const std::vector<std::string>& args) : name_(name), classname_(classname), flags_(flags), pid_(0), time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid), crash_count_(0), uid_(uid), gid_(gid), supp_gids_(supp_gids), capabilities_(capabilities), namespace_flags_(namespace_flags), seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0), Loading @@ -190,6 +188,12 @@ void Service::NotifyStateChange(const std::string& new_state) const { } property_set(prop_name.c_str(), new_state.c_str()); if (new_state == "running") { prop_name += ".start"; uint64_t start_ns = time_started_.time_since_epoch().count(); property_set(prop_name.c_str(), StringPrintf("%" PRIu64, start_ns).c_str()); } } void Service::KillProcessGroup(int signal) { Loading Loading @@ -274,20 +278,19 @@ bool Service::Reap() { return false; } time_t now = gettime(); // If we crash > 4 times in 4 minutes, reboot into recovery. boot_clock::time_point now = boot_clock::now(); if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) { if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) { if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) { LOG(ERROR) << "critical process '" << name_ << "' exited " << CRITICAL_CRASH_THRESHOLD << " times in " << (CRITICAL_CRASH_WINDOW / 60) << " minutes; " if (now < time_crashed_ + 4min) { if (++crash_count_ > 4) { LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes; " << "rebooting into recovery mode"; android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); return false; } } else { time_crashed_ = now; nr_crashed_ = 1; crash_count_ = 1; } } Loading Loading @@ -553,7 +556,6 @@ bool Service::Start() { // 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. flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); 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 Loading Loading @@ -667,7 +669,7 @@ bool Service::Start() { } } time_started_ = gettime(); time_started_ = boot_clock::now(); pid_ = pid; flags_ |= SVC_RUNNING; Loading Loading @@ -731,18 +733,19 @@ void Service::Restart() { } /* else: Service is restarting anyways. */ } void Service::RestartIfNeeded(time_t& process_needs_restart) { time_t next_start_time = time_started_ + 5; if (next_start_time <= gettime()) { void Service::RestartIfNeeded(time_t* process_needs_restart_at) { boot_clock::time_point now = boot_clock::now(); boot_clock::time_point next_start = time_started_ + 5s; if (now > next_start) { flags_ &= (~SVC_RESTARTING); Start(); return; } if ((next_start_time < process_needs_restart) || (process_needs_restart == 0)) { process_needs_restart = next_start_time; time_t next_start_time_t = time(nullptr) + time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count()); if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) { *process_needs_restart_at = next_start_time_t; } } Loading