Merge "init: Allow clean system shutdown upon SIGTERM"
am: 61cb88add2
Change-Id: If0a495fa067440f0b59969ac0dbc010b4687b52f
This commit is contained in:
commit
721b2d6035
8 changed files with 58 additions and 14 deletions
|
@ -119,7 +119,7 @@ cc_binary {
|
|||
"init_first_stage.cpp",
|
||||
"keychords.cpp",
|
||||
"reboot.cpp",
|
||||
"signal_handler.cpp",
|
||||
"sigchld_handler.cpp",
|
||||
"ueventd.cpp",
|
||||
"watchdogd.cpp",
|
||||
],
|
||||
|
|
|
@ -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 \
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
|
@ -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
|
Loading…
Reference in a new issue