diff --git a/init/reboot.cpp b/init/reboot.cpp index 6002040a1..b1cde9328 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -53,6 +53,7 @@ #include "init.h" #include "property_service.h" #include "service.h" +#include "signal_handler.h" using android::base::StringPrintf; using android::base::Timer; @@ -406,7 +407,7 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re // Only wait up to half of timeout here auto termination_wait_timeout = shutdown_timeout / 2; while (t.duration() < termination_wait_timeout) { - ServiceManager::GetInstance().ReapAnyOutstandingChildren(); + ReapAnyOutstandingChildren(); service_count = 0; ServiceManager::GetInstance().ForEachService([&service_count](Service* s) { @@ -437,7 +438,7 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re ServiceManager::GetInstance().ForEachServiceShutdownOrder([](Service* s) { if (!s->IsShutdownCritical()) s->Stop(); }); - ServiceManager::GetInstance().ReapAnyOutstandingChildren(); + ReapAnyOutstandingChildren(); // 3. send volume shutdown to vold Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold"); diff --git a/init/service.cpp b/init/service.cpp index 7f7958483..b5e2067a5 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -1091,69 +1091,6 @@ void ServiceManager::DumpState() const { } } -bool ServiceManager::ReapOneProcess() { - siginfo_t siginfo = {}; - // This returns a zombie pid or informs us that there are no zombies left to be reaped. - // It does NOT reap the pid; that is done below. - if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) { - PLOG(ERROR) << "waitid failed"; - return false; - } - - auto pid = siginfo.si_pid; - if (pid == 0) return false; - - // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid - // whenever the function returns from this point forward. - // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we - // want the pid to remain valid throughout that (and potentially future) usages. - auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); }); - - if (PropertyChildReap(pid)) { - return true; - } - - Service* svc = FindServiceByPid(pid); - - std::string name; - std::string wait_string; - if (svc) { - name = StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid); - if (svc->flags() & SVC_EXEC) { - auto exec_duration = boot_clock::now() - svc->time_started(); - auto exec_duration_ms = - std::chrono::duration_cast(exec_duration).count(); - wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f); - } - } else { - name = StringPrintf("Untracked pid %d", pid); - } - - auto status = siginfo.si_status; - if (WIFEXITED(status)) { - LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string; - } else if (WIFSIGNALED(status)) { - LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string; - } - - if (!svc) { - return true; - } - - svc->Reap(); - - if (svc->flags() & SVC_TEMPORARY) { - RemoveService(*svc); - } - - return true; -} - -void ServiceManager::ReapAnyOutstandingChildren() { - while (ReapOneProcess()) { - } -} - bool ServiceParser::ParseSection(std::vector&& args, const std::string& filename, int line, std::string* err) { if (args.size() < 3) { diff --git a/init/service.h b/init/service.h index 4098005d3..a7c91ae0a 100644 --- a/init/service.h +++ b/init/service.h @@ -221,15 +221,10 @@ class ServiceManager { void ForEachServiceShutdownOrder(const std::function& callback) const; void ForEachServiceInClass(const std::string& classname, void (*func)(Service* svc)) const; - void ReapAnyOutstandingChildren(); void RemoveService(const Service& svc); void DumpState() const; private: - // Cleans up a child process that exited. - // Returns true iff a children was cleaned up. - bool ReapOneProcess(); - std::vector> services_; }; diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp index db1bfcf8c..d77a2123b 100644 --- a/init/signal_handler.cpp +++ b/init/signal_handler.cpp @@ -14,29 +14,94 @@ * limitations under the License. */ +#include "signal_handler.h" + #include #include #include #include +#include #include +#include #include +#include +#include #include "init.h" +#include "property_service.h" #include "service.h" +using android::base::StringPrintf; +using android::base::boot_clock; +using android::base::make_scope_guard; + namespace android { namespace init { static int signal_write_fd = -1; static int signal_read_fd = -1; +static bool ReapOneProcess() { + siginfo_t siginfo = {}; + // This returns a zombie pid or informs us that there are no zombies left to be reaped. + // It does NOT reap the pid; that is done below. + if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) { + PLOG(ERROR) << "waitid failed"; + return false; + } + + auto pid = siginfo.si_pid; + if (pid == 0) return false; + + // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid + // whenever the function returns from this point forward. + // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we + // want the pid to remain valid throughout that (and potentially future) usages. + auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); }); + + if (PropertyChildReap(pid)) return true; + + Service* service = ServiceManager::GetInstance().FindServiceByPid(pid); + + std::string name; + std::string wait_string; + if (service) { + name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid); + if (service->flags() & SVC_EXEC) { + auto exec_duration = boot_clock::now() - service->time_started(); + auto exec_duration_ms = + std::chrono::duration_cast(exec_duration).count(); + wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f); + } + } else { + name = StringPrintf("Untracked pid %d", pid); + } + + auto status = siginfo.si_status; + if (WIFEXITED(status)) { + LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string; + } else if (WIFSIGNALED(status)) { + LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string; + } + + if (!service) return true; + + service->Reap(); + + if (service->flags() & SVC_TEMPORARY) { + ServiceManager::GetInstance().RemoveService(*service); + } + + return true; +} + static void handle_signal() { // Clear outstanding requests. char buf[32]; read(signal_read_fd, buf, sizeof(buf)); - ServiceManager::GetInstance().ReapAnyOutstandingChildren(); + ReapAnyOutstandingChildren(); } static void SIGCHLD_handler(int) { @@ -45,6 +110,11 @@ static void SIGCHLD_handler(int) { } } +void ReapAnyOutstandingChildren() { + while (ReapOneProcess()) { + } +} + void signal_handler_init() { // Create a signalling mechanism for SIGCHLD. int s[2]; @@ -63,7 +133,7 @@ void signal_handler_init() { act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, 0); - ServiceManager::GetInstance().ReapAnyOutstandingChildren(); + ReapAnyOutstandingChildren(); register_epoll_handler(signal_read_fd, handle_signal); } diff --git a/init/signal_handler.h b/init/signal_handler.h index f7881abff..9362be532 100644 --- a/init/signal_handler.h +++ b/init/signal_handler.h @@ -20,6 +20,8 @@ namespace android { namespace init { +void ReapAnyOutstandingChildren(); + void signal_handler_init(void); } // namespace init