diff --git a/init/init.cpp b/init/init.cpp index 83cb78b51..aeccd6696 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -117,7 +117,6 @@ namespace init { static int property_triggers_enabled = 0; -int sigchld_fd = -1; static int sigterm_fd = -1; static int property_fd = -1; @@ -717,7 +716,7 @@ static void HandleSigtermSignal(const signalfd_siginfo& siginfo) { static void HandleSignalFd(int signal) { signalfd_siginfo siginfo; - const int signal_fd = signal == SIGCHLD ? sigchld_fd : sigterm_fd; + const int signal_fd = signal == SIGCHLD ? Service::GetSigchldFd() : 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"; @@ -751,20 +750,24 @@ static void UnblockSignals() { } } +static Result RegisterSignalFd(Epoll* epoll, int signal, int fd) { + return epoll->RegisterHandler( + fd, [signal]() { HandleSignalFd(signal); }, EPOLLIN | EPOLLPRI); +} + 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; + if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) { + return ErrnoError() << "failed to block signal " << signal; } - auto result = epoll->RegisterHandler( - signal_fd.get(), [signal]() { HandleSignalFd(signal); }, EPOLLIN | EPOLLPRI); - if (!result.ok()) { - return result.error(); + unique_fd signal_fd(signalfd(-1, &mask, SFD_CLOEXEC)); + if (signal_fd.get() < 0) { + return ErrnoError() << "failed to create signalfd for signal " << signal; } + OR_RETURN(RegisterSignalFd(epoll, signal, signal_fd.get())); return signal_fd.release(); } @@ -775,34 +778,18 @@ static void InstallSignalFdHandler(Epoll* epoll) { const struct sigaction act { .sa_flags = SA_NOCLDSTOP, .sa_handler = SIG_DFL }; sigaction(SIGCHLD, &act, nullptr); - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - - if (!IsRebootCapable()) { - // If init does not have the CAP_SYS_BOOT capability, it is running in a container. - // In that case, receiving SIGTERM will cause the system to shut down. - sigaddset(&mask, SIGTERM); - } - - if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) { - PLOG(FATAL) << "failed to block signals"; - } - // Register a handler to unblock signals in the child processes. const int result = pthread_atfork(nullptr, nullptr, &UnblockSignals); if (result != 0) { LOG(FATAL) << "Failed to register a fork handler: " << strerror(result); } - Result cs_result = CreateAndRegisterSignalFd(epoll, SIGCHLD); + Result cs_result = RegisterSignalFd(epoll, SIGCHLD, Service::GetSigchldFd()); if (!cs_result.ok()) { PLOG(FATAL) << cs_result.error(); } - sigchld_fd = cs_result.value(); - Service::SetSigchldFd(sigchld_fd); - if (sigismember(&mask, SIGTERM)) { + if (!IsRebootCapable()) { Result cs_result = CreateAndRegisterSignalFd(epoll, SIGTERM); if (!cs_result.ok()) { PLOG(FATAL) << cs_result.error(); diff --git a/init/init.h b/init/init.h index b78116721..9c7e91879 100644 --- a/init/init.h +++ b/init/init.h @@ -28,8 +28,6 @@ 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 575792258..1a26c4d3c 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(sigchld_fd, pids, timeout); + WaitToBeReaped(Service::GetSigchldFd(), 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 d351a8fe1..eb24dd593 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -68,6 +69,7 @@ using android::base::make_scope_guard; using android::base::SetProperty; using android::base::StartsWith; using android::base::StringPrintf; +using android::base::unique_fd; using android::base::WriteStringToFile; namespace android { @@ -136,7 +138,6 @@ 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) @@ -792,6 +793,35 @@ void Service::SetMountNamespace() { mount_namespace_ = IsDefaultMountNamespaceReady() ? NS_DEFAULT : NS_BOOTSTRAP; } +static int ThreadCount() { + std::unique_ptr dir(opendir("/proc/self/task"), closedir); + if (!dir) { + return -1; + } + + int count = 0; + dirent* entry; + while ((entry = readdir(dir.get())) != nullptr) { + if (entry->d_name[0] != '.') { + count++; + } + } + return count; +} + +// Must be called BEFORE any threads are created. See also the sigprocmask() man page. +unique_fd Service::CreateSigchldFd() { + CHECK_EQ(ThreadCount(), 1); + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0) { + PLOG(FATAL) << "Failed to block SIGCHLD"; + } + + return unique_fd(signalfd(-1, &mask, SFD_CLOEXEC)); +} + void Service::SetStartedInFirstStage(pid_t pid) { LOG(INFO) << "adding first-stage service '" << name_ << "'..."; diff --git a/init/service.h b/init/service.h index 13c8b5f78..5e9af25db 100644 --- a/init/service.h +++ b/init/service.h @@ -156,7 +156,10 @@ 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; } + static int GetSigchldFd() { + static int sigchld_fd = CreateSigchldFd().release(); + return sigchld_fd; + } private: void NotifyStateChange(const std::string& new_state) const; @@ -169,10 +172,10 @@ class Service { void RunService(const std::vector& descriptors, InterprocessFifo cgroups_activated, InterprocessFifo setsid_finished); void SetMountNamespace(); + static ::android::base::unique_fd CreateSigchldFd(); static unsigned long next_start_order_; static bool is_exec_service_running_; - static int sigchld_fd_; const std::string name_; std::set classnames_;