Loading init/builtins.cpp +40 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <selinux/label.h> #include <fs_mgr.h> #include <android-base/parseint.h> #include <android-base/stringprintf.h> #include <cutils/partition_utils.h> #include <cutils/android_reboot.h> Loading @@ -53,6 +54,7 @@ #include "log.h" #include "property_service.h" #include "service.h" #include "signal_handler.h" #include "util.h" #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW Loading @@ -62,6 +64,8 @@ // System call provided by bionic but not in any header file. extern "C" int init_module(void *, unsigned long, const char *); static const int kTerminateServiceDelayMicroSeconds = 50000; static int insmod(const char *filename, const char *options) { std::string module; if (!read_file(filename, &module)) { Loading Loading @@ -608,6 +612,42 @@ static int do_powerctl(const std::vector<std::string>& args) { return -EINVAL; } std::string timeout = property_get("ro.build.shutdown_timeout"); unsigned int delay = 0; if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) { Timer t; // Ask all services to terminate. ServiceManager::GetInstance().ForEachService( [] (Service* s) { s->Terminate(); }); while (t.duration() < delay) { ServiceManager::GetInstance().ReapAnyOutstandingChildren(); int service_count = 0; ServiceManager::GetInstance().ForEachService( [&service_count] (Service* s) { // Count the number of services running. // Exclude the console as it will ignore the SIGTERM signal // and not exit. // Note: SVC_CONSOLE actually means "requires console" but // it is only used by the shell. if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) { service_count++; } }); if (service_count == 0) { // All terminable services terminated. We can exit early. break; } // Wait a bit before recounting the number or running services. usleep(kTerminateServiceDelayMicroSeconds); } NOTICE("Terminating running services took %.02f seconds", t.duration()); } return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount); } Loading init/service.cpp +61 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <termios.h> #include <unistd.h> Loading Loading @@ -531,6 +532,17 @@ void Service::Stop() { StopOrReset(SVC_DISABLED); } void Service::Terminate() { flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START); flags_ |= SVC_DISABLED; if (pid_) { NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(), pid_); kill(-pid_, SIGTERM); NotifyStateChange("stopping"); } } void Service::Restart() { if (flags_ & SVC_RUNNING) { /* Stop, wait, then start the service. */ Loading Loading @@ -724,9 +736,9 @@ Service* ServiceManager::FindServiceByKeychord(int keychord_id) const { return nullptr; } void ServiceManager::ForEachService(void (*func)(Service* svc)) const { void ServiceManager::ForEachService(std::function<void(Service*)> callback) const { for (const auto& s : services_) { func(s.get()); callback(s.get()); } } Loading Loading @@ -767,6 +779,53 @@ void ServiceManager::DumpState() const { INFO("\n"); } bool ServiceManager::ReapOneProcess() { int status; pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); if (pid == 0) { return false; } else if (pid == -1) { ERROR("waitpid failed: %s\n", strerror(errno)); return false; } Service* svc = FindServiceByPid(pid); std::string name; if (svc) { name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid); } else { name = android::base::StringPrintf("Untracked pid %d", pid); } if (WIFEXITED(status)) { NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status)); } else if (WIFSTOPPED(status)) { NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status)); } else { NOTICE("%s state changed", name.c_str()); } if (!svc) { return true; } if (svc->Reap()) { waiting_for_exec = false; RemoveService(*svc); } return true; } void ServiceManager::ReapAnyOutstandingChildren() { while (ReapOneProcess()) { } } bool ServiceParser::ParseSection(const std::vector<std::string>& args, std::string* err) { if (args.size() < 3) { Loading init/service.h +7 −1 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ public: bool Enable(); void Reset(); void Stop(); void Terminate(); void Restart(); void RestartIfNeeded(time_t& process_needs_restart); bool Reap(); Loading Loading @@ -167,17 +168,22 @@ public: Service* FindServiceByName(const std::string& name) const; Service* FindServiceByPid(pid_t pid) const; Service* FindServiceByKeychord(int keychord_id) const; void ForEachService(void (*func)(Service* svc)) const; void ForEachService(std::function<void(Service*)> callback) const; void ForEachServiceInClass(const std::string& classname, void (*func)(Service* svc)) const; void ForEachServiceWithFlags(unsigned matchflags, void (*func)(Service* svc)) const; void ReapAnyOutstandingChildren(); void RemoveService(const Service& svc); void DumpState() const; private: ServiceManager(); // Cleans up a child process that exited. // Returns true iff a children was cleaned up. bool ReapOneProcess(); static int exec_count_; // Every service needs a unique name. std::vector<std::unique_ptr<Service>> services_; }; Loading init/signal_handler.cpp +2 −52 Original line number Diff line number Diff line Loading @@ -37,62 +37,12 @@ static int signal_write_fd = -1; static int signal_read_fd = -1; static std::string DescribeStatus(int status) { if (WIFEXITED(status)) { return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { return android::base::StringPrintf("killed by signal %d", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status)); } else { return "state changed"; } } static bool wait_for_one_process() { int status; pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); if (pid == 0) { return false; } else if (pid == -1) { ERROR("waitpid failed: %s\n", strerror(errno)); return false; } Service* svc = ServiceManager::GetInstance().FindServiceByPid(pid); std::string name; if (svc) { name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid); } else { name = android::base::StringPrintf("Untracked pid %d", pid); } NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str()); if (!svc) { return true; } if (svc->Reap()) { waiting_for_exec = false; ServiceManager::GetInstance().RemoveService(*svc); } 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(); ServiceManager::GetInstance().ReapAnyOutstandingChildren(); } static void SIGCHLD_handler(int) { Loading @@ -119,7 +69,7 @@ void signal_handler_init() { act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, 0); reap_any_outstanding_children(); ServiceManager::GetInstance().ReapAnyOutstandingChildren(); register_epoll_handler(signal_read_fd, handle_signal); } Loading
init/builtins.cpp +40 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <selinux/label.h> #include <fs_mgr.h> #include <android-base/parseint.h> #include <android-base/stringprintf.h> #include <cutils/partition_utils.h> #include <cutils/android_reboot.h> Loading @@ -53,6 +54,7 @@ #include "log.h" #include "property_service.h" #include "service.h" #include "signal_handler.h" #include "util.h" #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW Loading @@ -62,6 +64,8 @@ // System call provided by bionic but not in any header file. extern "C" int init_module(void *, unsigned long, const char *); static const int kTerminateServiceDelayMicroSeconds = 50000; static int insmod(const char *filename, const char *options) { std::string module; if (!read_file(filename, &module)) { Loading Loading @@ -608,6 +612,42 @@ static int do_powerctl(const std::vector<std::string>& args) { return -EINVAL; } std::string timeout = property_get("ro.build.shutdown_timeout"); unsigned int delay = 0; if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) { Timer t; // Ask all services to terminate. ServiceManager::GetInstance().ForEachService( [] (Service* s) { s->Terminate(); }); while (t.duration() < delay) { ServiceManager::GetInstance().ReapAnyOutstandingChildren(); int service_count = 0; ServiceManager::GetInstance().ForEachService( [&service_count] (Service* s) { // Count the number of services running. // Exclude the console as it will ignore the SIGTERM signal // and not exit. // Note: SVC_CONSOLE actually means "requires console" but // it is only used by the shell. if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) { service_count++; } }); if (service_count == 0) { // All terminable services terminated. We can exit early. break; } // Wait a bit before recounting the number or running services. usleep(kTerminateServiceDelayMicroSeconds); } NOTICE("Terminating running services took %.02f seconds", t.duration()); } return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount); } Loading
init/service.cpp +61 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <termios.h> #include <unistd.h> Loading Loading @@ -531,6 +532,17 @@ void Service::Stop() { StopOrReset(SVC_DISABLED); } void Service::Terminate() { flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START); flags_ |= SVC_DISABLED; if (pid_) { NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(), pid_); kill(-pid_, SIGTERM); NotifyStateChange("stopping"); } } void Service::Restart() { if (flags_ & SVC_RUNNING) { /* Stop, wait, then start the service. */ Loading Loading @@ -724,9 +736,9 @@ Service* ServiceManager::FindServiceByKeychord(int keychord_id) const { return nullptr; } void ServiceManager::ForEachService(void (*func)(Service* svc)) const { void ServiceManager::ForEachService(std::function<void(Service*)> callback) const { for (const auto& s : services_) { func(s.get()); callback(s.get()); } } Loading Loading @@ -767,6 +779,53 @@ void ServiceManager::DumpState() const { INFO("\n"); } bool ServiceManager::ReapOneProcess() { int status; pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); if (pid == 0) { return false; } else if (pid == -1) { ERROR("waitpid failed: %s\n", strerror(errno)); return false; } Service* svc = FindServiceByPid(pid); std::string name; if (svc) { name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid); } else { name = android::base::StringPrintf("Untracked pid %d", pid); } if (WIFEXITED(status)) { NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status)); } else if (WIFSTOPPED(status)) { NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status)); } else { NOTICE("%s state changed", name.c_str()); } if (!svc) { return true; } if (svc->Reap()) { waiting_for_exec = false; RemoveService(*svc); } return true; } void ServiceManager::ReapAnyOutstandingChildren() { while (ReapOneProcess()) { } } bool ServiceParser::ParseSection(const std::vector<std::string>& args, std::string* err) { if (args.size() < 3) { Loading
init/service.h +7 −1 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ public: bool Enable(); void Reset(); void Stop(); void Terminate(); void Restart(); void RestartIfNeeded(time_t& process_needs_restart); bool Reap(); Loading Loading @@ -167,17 +168,22 @@ public: Service* FindServiceByName(const std::string& name) const; Service* FindServiceByPid(pid_t pid) const; Service* FindServiceByKeychord(int keychord_id) const; void ForEachService(void (*func)(Service* svc)) const; void ForEachService(std::function<void(Service*)> callback) const; void ForEachServiceInClass(const std::string& classname, void (*func)(Service* svc)) const; void ForEachServiceWithFlags(unsigned matchflags, void (*func)(Service* svc)) const; void ReapAnyOutstandingChildren(); void RemoveService(const Service& svc); void DumpState() const; private: ServiceManager(); // Cleans up a child process that exited. // Returns true iff a children was cleaned up. bool ReapOneProcess(); static int exec_count_; // Every service needs a unique name. std::vector<std::unique_ptr<Service>> services_; }; Loading
init/signal_handler.cpp +2 −52 Original line number Diff line number Diff line Loading @@ -37,62 +37,12 @@ static int signal_write_fd = -1; static int signal_read_fd = -1; static std::string DescribeStatus(int status) { if (WIFEXITED(status)) { return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { return android::base::StringPrintf("killed by signal %d", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status)); } else { return "state changed"; } } static bool wait_for_one_process() { int status; pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); if (pid == 0) { return false; } else if (pid == -1) { ERROR("waitpid failed: %s\n", strerror(errno)); return false; } Service* svc = ServiceManager::GetInstance().FindServiceByPid(pid); std::string name; if (svc) { name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid); } else { name = android::base::StringPrintf("Untracked pid %d", pid); } NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str()); if (!svc) { return true; } if (svc->Reap()) { waiting_for_exec = false; ServiceManager::GetInstance().RemoveService(*svc); } 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(); ServiceManager::GetInstance().ReapAnyOutstandingChildren(); } static void SIGCHLD_handler(int) { Loading @@ -119,7 +69,7 @@ void signal_handler_init() { act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, 0); reap_any_outstanding_children(); ServiceManager::GetInstance().ReapAnyOutstandingChildren(); register_epoll_handler(signal_read_fd, handle_signal); }