diff options
| author | Luis Hector Chavez <lhchavez@google.com> | 2017-09-06 13:43:57 -0700 |
|---|---|---|
| committer | Luis Hector Chavez <lhchavez@google.com> | 2017-09-07 10:47:04 -0700 |
| commit | 9f97f4794027d8143b7d4f2d3ad4f80ca72ca77a (patch) | |
| tree | d3483bb93fd2fe22fd5b71b0668145ce9571ef29 /init/init.cpp | |
| parent | 6139592321a489607534d9f51533d33908d75ba4 (diff) | |
| download | system_core-9f97f4794027d8143b7d4f2d3ad4f80ca72ca77a.tar.gz system_core-9f97f4794027d8143b7d4f2d3ad4f80ca72ca77a.tar.bz2 system_core-9f97f4794027d8143b7d4f2d3ad4f80ca72ca77a.zip | |
init: Allow clean system shutdown upon SIGTERM
This allows Android to cleanly shutdown when running in a PID namespace
in a way that does not rely on adbd running. This is useful to allow
Android to be running in a container and its lifetime managed by an
OCI-compliant tool.
Bug: 65415372
Test: `kill -TERM 1` as root is correctly dropped.
Test: `kill -TERM 1` from the init PID namespace causes init to cleanly shutdown.
Change-Id: Ia66ebdb436221919081bc4723337c0c7f1e53b09
Diffstat (limited to 'init/init.cpp')
| -rw-r--r-- | init/init.cpp | 47 |
1 files changed, 45 insertions, 2 deletions
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 <string.h> #include <sys/epoll.h> #include <sys/mount.h> +#include <sys/signalfd.h> #include <sys/sysmacros.h> #include <sys/types.h> #include <unistd.h> @@ -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<Timer> 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(); |
