Merge "init: Allow clean system shutdown upon SIGTERM" am: 61cb88add2

am: 721b2d6035

Change-Id: Id420e18f64e3abba6bd50a444ff4f9b05db3dc2d
This commit is contained in:
Luis Hector Chavez 2017-09-07 20:09:29 +00:00 committed by android-build-merger
commit 69596c2d00
8 changed files with 58 additions and 14 deletions

View file

@ -119,7 +119,7 @@ cc_binary {
"init_first_stage.cpp", "init_first_stage.cpp",
"keychords.cpp", "keychords.cpp",
"reboot.cpp", "reboot.cpp",
"signal_handler.cpp", "sigchld_handler.cpp",
"ueventd.cpp", "ueventd.cpp",
"watchdogd.cpp", "watchdogd.cpp",
], ],

View file

@ -48,7 +48,7 @@ LOCAL_SRC_FILES:= \
init_first_stage.cpp \ init_first_stage.cpp \
keychords.cpp \ keychords.cpp \
reboot.cpp \ reboot.cpp \
signal_handler.cpp \ sigchld_handler.cpp \
ueventd.cpp \ ueventd.cpp \
watchdogd.cpp \ watchdogd.cpp \

View file

@ -66,7 +66,6 @@
#include "reboot.h" #include "reboot.h"
#include "rlimit_parser.h" #include "rlimit_parser.h"
#include "service.h" #include "service.h"
#include "signal_handler.h"
#include "util.h" #include "util.h"
using namespace std::literals::string_literals; using namespace std::literals::string_literals;

View file

@ -25,6 +25,7 @@
#include <string.h> #include <string.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/signalfd.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
@ -51,7 +52,7 @@
#include "reboot.h" #include "reboot.h"
#include "security.h" #include "security.h"
#include "selinux.h" #include "selinux.h"
#include "signal_handler.h" #include "sigchld_handler.h"
#include "ueventd.h" #include "ueventd.h"
#include "util.h" #include "util.h"
#include "watchdogd.h" #include "watchdogd.h"
@ -72,6 +73,7 @@ static char qemu[32];
std::string default_console = "/dev/console"; std::string default_console = "/dev/console";
static int epoll_fd = -1; static int epoll_fd = -1;
static int sigterm_signal_fd = -1;
static std::unique_ptr<Timer> waiting_for_prop(nullptr); static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name; static std::string wait_prop_name;
@ -392,6 +394,41 @@ static void InstallRebootSignalHandlers() {
sigaction(SIGTRAP, &action, nullptr); 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) { int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) { if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv); return ueventd_main(argc, argv);
@ -527,7 +564,13 @@ int main(int argc, char** argv) {
exit(1); 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(); property_load_boot_defaults();
export_oem_lock_status(); export_oem_lock_status();

View file

@ -54,7 +54,7 @@
#include "init.h" #include "init.h"
#include "property_service.h" #include "property_service.h"
#include "service.h" #include "service.h"
#include "signal_handler.h" #include "sigchld_handler.h"
using android::base::StringPrintf; using android::base::StringPrintf;
using android::base::Timer; using android::base::Timer;
@ -169,9 +169,7 @@ static void LogShutdownTime(UmountStat stat, Timer* t) {
<< stat; << stat;
} }
// Determines whether the system is capable of rebooting. This is conservative, bool IsRebootCapable() {
// so if any of the attempts to determine this fail, it will still return true.
static bool IsRebootCapable() {
if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) { if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
PLOG(WARNING) << "CAP_SYS_BOOT is not supported"; PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
return true; return true;

View file

@ -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. // Parses and handles a setprop sys.powerctl message.
bool HandlePowerctlMessage(const std::string& command); 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 init
} // namespace android } // namespace android

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include "signal_handler.h" #include "sigchld_handler.h"
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
@ -115,7 +115,7 @@ void ReapAnyOutstandingChildren() {
} }
} }
void signal_handler_init() { void sigchld_handler_init() {
// Create a signalling mechanism for SIGCHLD. // Create a signalling mechanism for SIGCHLD.
int s[2]; int s[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) { if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {

View file

@ -14,15 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef _INIT_SIGNAL_HANDLER_H_ #ifndef _INIT_SIGCHLD_HANDLER_H_
#define _INIT_SIGNAL_HANDLER_H_ #define _INIT_SIGCHLD_HANDLER_H_
namespace android { namespace android {
namespace init { namespace init {
void ReapAnyOutstandingChildren(); void ReapAnyOutstandingChildren();
void signal_handler_init(void); void sigchld_handler_init(void);
} // namespace init } // namespace init
} // namespace android } // namespace android