diff --git a/init/init.cpp b/init/init.cpp index 19f34dabb..0439d224a 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -108,6 +108,7 @@ using android::base::SetProperty; using android::base::StringPrintf; using android::base::Timer; using android::base::Trim; +using android::base::unique_fd; using android::fs_mgr::AvbHandle; using android::snapshot::SnapshotManager; @@ -116,7 +117,8 @@ namespace init { static int property_triggers_enabled = 0; -static int signal_fd = -1; +int sigchld_fd = -1; +static int sigterm_fd = -1; static int property_fd = -1; struct PendingControlMessage { @@ -713,8 +715,9 @@ static void HandleSigtermSignal(const signalfd_siginfo& siginfo) { HandlePowerctlMessage("shutdown,container"); } -static void HandleSignalFd() { +static void HandleSignalFd(int signal) { signalfd_siginfo siginfo; + const int signal_fd = signal == SIGCHLD ? sigchld_fd : sigterm_fd; ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo))); if (bytes_read != sizeof(siginfo)) { PLOG(ERROR) << "Failed to read siginfo from signal_fd"; @@ -748,6 +751,24 @@ static void UnblockSignals() { } } +static Result CreateAndRegisterSignalFd(Epoll* epoll, int signal) { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, signal); + unique_fd signal_fd(signalfd(-1, &mask, SFD_CLOEXEC)); + if (signal_fd == -1) { + return ErrnoError() << "failed to create signalfd for signal " << signal; + } + + auto result = epoll->RegisterHandler( + signal_fd.get(), [signal]() { HandleSignalFd(signal); }, EPOLLIN | EPOLLPRI); + if (!result.ok()) { + return result.error(); + } + + return signal_fd.release(); +} + static void InstallSignalFdHandler(Epoll* epoll) { // Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving // SIGCHLD when a child process stops or continues (b/77867680#comment9). @@ -774,14 +795,19 @@ static void InstallSignalFdHandler(Epoll* epoll) { LOG(FATAL) << "Failed to register a fork handler: " << strerror(result); } - signal_fd = signalfd(-1, &mask, SFD_CLOEXEC); - if (signal_fd == -1) { - PLOG(FATAL) << "failed to create signalfd"; + Result cs_result = CreateAndRegisterSignalFd(epoll, SIGCHLD); + if (!cs_result.ok()) { + PLOG(FATAL) << cs_result.error(); } + sigchld_fd = cs_result.value(); + Service::SetSigchldFd(sigchld_fd); - constexpr int flags = EPOLLIN | EPOLLPRI; - if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd, flags); !result.ok()) { - LOG(FATAL) << result.error(); + if (sigismember(&mask, SIGTERM)) { + Result cs_result = CreateAndRegisterSignalFd(epoll, SIGTERM); + if (!cs_result.ok()) { + PLOG(FATAL) << cs_result.error(); + } + sigterm_fd = cs_result.value(); } } diff --git a/init/init.h b/init/init.h index 9c7e91879..b78116721 100644 --- a/init/init.h +++ b/init/init.h @@ -28,6 +28,8 @@ namespace android { namespace init { +extern int sigchld_fd; + Parser CreateParser(ActionManager& action_manager, ServiceList& service_list); Parser CreateApexConfigParser(ActionManager& action_manager, ServiceList& service_list); diff --git a/init/reboot.cpp b/init/reboot.cpp index 3351c4c45..575792258 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -563,7 +563,7 @@ static void StopServices(const std::set& services, std::chrono::mil } } if (timeout > 0ms) { - WaitToBeReaped(pids, timeout); + WaitToBeReaped(sigchld_fd, pids, timeout); } else { // Even if we don't to wait for services to stop, we still optimistically reap zombies. ReapAnyOutstandingChildren(); diff --git a/init/service.cpp b/init/service.cpp index 208745257..311a13299 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -136,6 +136,7 @@ static bool ExpandArgsAndExecv(const std::vector& args, bool sigsto unsigned long Service::next_start_order_ = 1; bool Service::is_exec_service_running_ = false; +int Service::sigchld_fd_ = -1; Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands, const std::string& filename, const std::vector& args) diff --git a/init/service.h b/init/service.h index 35521b207..13c8b5f78 100644 --- a/init/service.h +++ b/init/service.h @@ -156,6 +156,7 @@ class Service { const Subcontext* subcontext() const { return subcontext_; } const std::string& filename() const { return filename_; } void set_filename(const std::string& name) { filename_ = name; } + static void SetSigchldFd(int sigchld_fd) { sigchld_fd_ = sigchld_fd; } private: void NotifyStateChange(const std::string& new_state) const; @@ -168,8 +169,10 @@ class Service { void RunService(const std::vector& descriptors, InterprocessFifo cgroups_activated, InterprocessFifo setsid_finished); void SetMountNamespace(); + static unsigned long next_start_order_; static bool is_exec_service_running_; + static int sigchld_fd_; const std::string name_; std::set classnames_; diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp index 0901a960f..9d4c7c8e3 100644 --- a/init/sigchld_handler.cpp +++ b/init/sigchld_handler.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include +#include "epoll.h" #include "init.h" #include "service.h" #include "service_list.h" @@ -121,8 +123,23 @@ void ReapAnyOutstandingChildren() { } } -void WaitToBeReaped(const std::vector& pids, std::chrono::milliseconds timeout) { +static void DiscardSiginfo(int signal_fd) { + signalfd_siginfo siginfo; + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo))); + if (bytes_read != sizeof(siginfo)) { + LOG(WARNING) << "Unexpected: " << __func__ << " read " << bytes_read << " bytes instead of " + << sizeof(siginfo); + } +} + +void WaitToBeReaped(int sigchld_fd, const std::vector& pids, + std::chrono::milliseconds timeout) { Timer t; + Epoll epoll; + // The init process passes a valid sigchld_fd argument but unit tests do not. + if (sigchld_fd >= 0) { + epoll.RegisterHandler(sigchld_fd, [sigchld_fd]() { DiscardSiginfo(sigchld_fd); }); + } std::vector alive_pids(pids.begin(), pids.end()); while (!alive_pids.empty() && t.duration() < timeout) { pid_t pid; @@ -135,7 +152,11 @@ void WaitToBeReaped(const std::vector& pids, std::chrono::milliseconds ti if (alive_pids.empty()) { break; } - std::this_thread::sleep_for(50ms); + if (sigchld_fd >= 0) { + epoll.Wait(std::max(timeout - t.duration(), 0ms)); + } else { + std::this_thread::sleep_for(50ms); + } } LOG(INFO) << "Waiting for " << pids.size() << " pids to be reaped took " << t << " with " << alive_pids.size() << " of them still running"; diff --git a/init/sigchld_handler.h b/init/sigchld_handler.h index fac10201e..e07a7d66a 100644 --- a/init/sigchld_handler.h +++ b/init/sigchld_handler.h @@ -25,7 +25,8 @@ namespace init { void ReapAnyOutstandingChildren(); -void WaitToBeReaped(const std::vector& pids, std::chrono::milliseconds timeout); +void WaitToBeReaped(int sigchld_fd, const std::vector& pids, + std::chrono::milliseconds timeout); } // namespace init } // namespace android