diff --git a/init/Android.bp b/init/Android.bp index 8737defae..672942e62 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -119,7 +119,7 @@ cc_binary { "init_first_stage.cpp", "keychords.cpp", "reboot.cpp", - "signal_handler.cpp", + "sigchld_handler.cpp", "ueventd.cpp", "watchdogd.cpp", ], diff --git a/init/Android.mk b/init/Android.mk index 23ada73a5..6c28517e0 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -48,7 +48,7 @@ LOCAL_SRC_FILES:= \ init_first_stage.cpp \ keychords.cpp \ reboot.cpp \ - signal_handler.cpp \ + sigchld_handler.cpp \ ueventd.cpp \ watchdogd.cpp \ diff --git a/init/builtins.cpp b/init/builtins.cpp index 549a46418..d77abdf52 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -66,7 +66,6 @@ #include "reboot.h" #include "rlimit_parser.h" #include "service.h" -#include "signal_handler.h" #include "util.h" using namespace std::literals::string_literals; diff --git a/init/init.cpp b/init/init.cpp index 678f49f58..c3e08fb88 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ #include "reboot.h" #include "security.h" #include "selinux.h" -#include "signal_handler.h" +#include "sigchld_handler.h" #include "ueventd.h" #include "util.h" #include "watchdogd.h" @@ -72,6 +73,7 @@ static char qemu[32]; std::string default_console = "/dev/console"; static int epoll_fd = -1; +static int sigterm_signal_fd = -1; static std::unique_ptr waiting_for_prop(nullptr); static std::string wait_prop_name; @@ -392,6 +394,41 @@ static void InstallRebootSignalHandlers() { sigaction(SIGTRAP, &action, nullptr); } +static void HandleSigtermSignal() { + signalfd_siginfo siginfo; + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo))); + if (bytes_read != sizeof(siginfo)) { + PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd"; + return; + } + + if (siginfo.ssi_pid != 0) { + // Drop any userspace SIGTERM requests. + LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid; + return; + } + + LOG(INFO) << "Handling SIGTERM, shutting system down"; + HandlePowerctlMessage("shutdown"); +} + +static void InstallSigtermHandler() { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + + if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) { + PLOG(FATAL) << "failed to block SIGTERM"; + } + + sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC); + if (sigterm_signal_fd == -1) { + PLOG(FATAL) << "failed to create signalfd for SIGTERM"; + } + + register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal); +} + int main(int argc, char** argv) { if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); @@ -527,7 +564,13 @@ int main(int argc, char** argv) { exit(1); } - signal_handler_init(); + sigchld_handler_init(); + + 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. + InstallSigtermHandler(); + } property_load_boot_defaults(); export_oem_lock_status(); diff --git a/init/reboot.cpp b/init/reboot.cpp index 891ca03c1..049c95276 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -54,7 +54,7 @@ #include "init.h" #include "property_service.h" #include "service.h" -#include "signal_handler.h" +#include "sigchld_handler.h" using android::base::StringPrintf; using android::base::Timer; @@ -169,9 +169,7 @@ static void LogShutdownTime(UmountStat stat, Timer* t) { << stat; } -// Determines whether the system is capable of rebooting. This is conservative, -// so if any of the attempts to determine this fail, it will still return true. -static bool IsRebootCapable() { +bool IsRebootCapable() { if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) { PLOG(WARNING) << "CAP_SYS_BOOT is not supported"; return true; diff --git a/init/reboot.h b/init/reboot.h index ece407f0d..1c58bd134 100644 --- a/init/reboot.h +++ b/init/reboot.h @@ -38,6 +38,10 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re // Parses and handles a setprop sys.powerctl message. bool HandlePowerctlMessage(const std::string& command); +// Determines whether the system is capable of rebooting. This is conservative, +// so if any of the attempts to determine this fail, it will still return true. +bool IsRebootCapable(); + } // namespace init } // namespace android diff --git a/init/signal_handler.cpp b/init/sigchld_handler.cpp similarity index 98% rename from init/signal_handler.cpp rename to init/sigchld_handler.cpp index 9e49c48a7..8fc995606 100644 --- a/init/signal_handler.cpp +++ b/init/sigchld_handler.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "signal_handler.h" +#include "sigchld_handler.h" #include #include @@ -115,7 +115,7 @@ void ReapAnyOutstandingChildren() { } } -void signal_handler_init() { +void sigchld_handler_init() { // Create a signalling mechanism for SIGCHLD. int s[2]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) { diff --git a/init/signal_handler.h b/init/sigchld_handler.h similarity index 88% rename from init/signal_handler.h rename to init/sigchld_handler.h index 9362be532..c86dc8dd4 100644 --- a/init/signal_handler.h +++ b/init/sigchld_handler.h @@ -14,15 +14,15 @@ * limitations under the License. */ -#ifndef _INIT_SIGNAL_HANDLER_H_ -#define _INIT_SIGNAL_HANDLER_H_ +#ifndef _INIT_SIGCHLD_HANDLER_H_ +#define _INIT_SIGCHLD_HANDLER_H_ namespace android { namespace init { void ReapAnyOutstandingChildren(); -void signal_handler_init(void); +void sigchld_handler_init(void); } // namespace init } // namespace android