Merge "init: Allow clean system shutdown upon SIGTERM"

am: 61cb88add2

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

View file

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

View file

@ -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 \

View file

@ -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;

View file

@ -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();

View file

@ -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;

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.
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

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "signal_handler.h"
#include "sigchld_handler.h"
#include <signal.h>
#include <string.h>
@ -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) {

View file

@ -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