From 98ad32a967079be80a101458d8a29d7ecefbb547 Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Mon, 17 Apr 2017 16:34:20 -0700 Subject: [PATCH] init: handle sys.powerctl immediately Currently if a process sets the sys.powerctl property, init adds this property change into the event queue, just like any other property. The actual logic to shutdown the device is not executed until init gets to the action associated with the property change. This is bad for multiple reasons, but explicitly causes deadlock in the follow scenario: A service is started with `exec` or `exec_start` The same service sets sys.powerctl indicating to the system to shutdown The same service then waits infinitely In this case, init doesn't process any further commands until the exec service completes, including the command to reboot the device. This change causes init to immediately handle sys.powerctl and reboot the device regardless of the state of the event queue, wait for exec, or wait for property conditions. Bug: 37209359 Bug: 37415192 Test: Init reboots normally Test: Update verifier can reboot the system Change-Id: Iff2295aed970840f47e56c4bacc93001b791fa35 --- init/README.md | 4 --- init/builtins.cpp | 53 --------------------------------------- init/init.cpp | 10 ++++++-- init/init.h | 2 +- init/property_service.cpp | 2 +- init/reboot.cpp | 51 +++++++++++++++++++++++++++++++++++++ init/reboot.h | 3 +++ rootdir/init.rc | 3 --- 8 files changed, 64 insertions(+), 64 deletions(-) diff --git a/init/README.md b/init/README.md index fc507300f..8cb1e52a3 100644 --- a/init/README.md +++ b/init/README.md @@ -370,10 +370,6 @@ Commands _options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as a comma separated string, eg: barrier=1,noauto\_da\_alloc -`powerctl` -> Internal implementation detail used to respond to changes to the - "sys.powerctl" system property, used to implement rebooting. - `restart ` > Stops and restarts a running service, does nothing if the service is currently restarting, otherwise, it just starts the service. diff --git a/init/builtins.cpp b/init/builtins.cpp index 2327cdfb4..43eb42075 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -598,58 +598,6 @@ static int do_restart(const std::vector& args) { return 0; } -static int do_powerctl(const std::vector& args) { - const std::string& command = args[1]; - unsigned int cmd = 0; - std::vector cmd_params = android::base::Split(command, ","); - std::string reason_string = cmd_params[0]; - std::string reboot_target = ""; - bool runFsck = false; - bool commandInvalid = false; - - if (cmd_params.size() > 3) { - commandInvalid = true; - } else if (cmd_params[0] == "shutdown") { - cmd = ANDROID_RB_POWEROFF; - if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") { - // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED. - // Run fsck once the file system is remounted in read-only mode. - runFsck = true; - reason_string = cmd_params[1]; - } - } else if (cmd_params[0] == "reboot") { - cmd = ANDROID_RB_RESTART2; - if (cmd_params.size() >= 2) { - reboot_target = cmd_params[1]; - // When rebooting to the bootloader notify the bootloader writing - // also the BCB. - if (reboot_target == "bootloader") { - std::string err; - if (!write_reboot_bootloader(&err)) { - LOG(ERROR) << "reboot-bootloader: Error writing " - "bootloader_message: " - << err; - } - } - // If there is an additional bootloader parameter, pass it along - if (cmd_params.size() == 3) { - reboot_target += "," + cmd_params[2]; - } - } - } else if (command == "thermal-shutdown") { // no additional parameter allowed - cmd = ANDROID_RB_THERMOFF; - } else { - commandInvalid = true; - } - if (commandInvalid) { - LOG(ERROR) << "powerctl: unrecognized command '" << command << "'"; - return -EINVAL; - } - - DoReboot(cmd, reason_string, reboot_target, runFsck); - return 0; -} - static int do_trigger(const std::vector& args) { ActionManager::GetInstance().QueueEventTrigger(args[1]); return 0; @@ -919,7 +867,6 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"mount_all", {1, kMax, do_mount_all}}, {"mount", {3, kMax, do_mount}}, {"umount", {1, 1, do_umount}}, - {"powerctl", {1, 1, do_powerctl}}, {"restart", {1, 1, do_restart}}, {"restorecon", {1, kMax, do_restorecon}}, {"restorecon_recursive", {1, kMax, do_restorecon_recursive}}, diff --git a/init/init.cpp b/init/init.cpp index 181b18d0b..9a4aa246e 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -67,6 +67,7 @@ #include "keychords.h" #include "log.h" #include "property_service.h" +#include "reboot.h" #include "service.h" #include "signal_handler.h" #include "ueventd.h" @@ -153,8 +154,13 @@ bool start_waiting_for_property(const char *name, const char *value) return true; } -void property_changed(const char *name, const char *value) -{ +void property_changed(const std::string& name, const std::string& value) { + // If the property is sys.powerctl, we bypass the event queue and immediately handle it. + // This is to ensure that init will always and immediately shutdown/reboot, regardless of + // if there are other pending events to process or if init is waiting on an exec service or + // waiting on a property. + if (name == "sys.powerctl") HandlePowerctlMessage(value); + if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyTrigger(name, value); if (waiting_for_prop) { diff --git a/init/init.h b/init/init.h index fe850efd7..1da335030 100644 --- a/init/init.h +++ b/init/init.h @@ -26,7 +26,7 @@ extern struct selabel_handle *sehandle_prop; void handle_control_message(const std::string& msg, const std::string& arg); -void property_changed(const char *name, const char *value); +void property_changed(const std::string& name, const std::string& value); void register_epoll_handler(int fd, void (*fn)()); diff --git a/init/property_service.cpp b/init/property_service.cpp index 2aa89ff96..20a2aa1fb 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -205,7 +205,7 @@ uint32_t property_set(const std::string& name, const std::string& value) { if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) { write_persistent_property(name.c_str(), value.c_str()); } - property_changed(name.c_str(), value.c_str()); + property_changed(name, value); return PROP_SUCCESS; } diff --git a/init/reboot.cpp b/init/reboot.cpp index d9ebd91ee..4d65437de 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -425,3 +425,54 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re RebootSystem(cmd, rebootTarget); abort(); } + +bool HandlePowerctlMessage(const std::string& command) { + unsigned int cmd = 0; + std::vector cmd_params = android::base::Split(command, ","); + std::string reason_string = cmd_params[0]; + std::string reboot_target = ""; + bool run_fsck = false; + bool command_invalid = false; + + if (cmd_params.size() > 3) { + command_invalid = true; + } else if (cmd_params[0] == "shutdown") { + cmd = ANDROID_RB_POWEROFF; + if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") { + // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED. + // Run fsck once the file system is remounted in read-only mode. + run_fsck = true; + reason_string = cmd_params[1]; + } + } else if (cmd_params[0] == "reboot") { + cmd = ANDROID_RB_RESTART2; + if (cmd_params.size() >= 2) { + reboot_target = cmd_params[1]; + // When rebooting to the bootloader notify the bootloader writing + // also the BCB. + if (reboot_target == "bootloader") { + std::string err; + if (!write_reboot_bootloader(&err)) { + LOG(ERROR) << "reboot-bootloader: Error writing " + "bootloader_message: " + << err; + } + } + // If there is an additional bootloader parameter, pass it along + if (cmd_params.size() == 3) { + reboot_target += "," + cmd_params[2]; + } + } + } else if (command == "thermal-shutdown") { // no additional parameter allowed + cmd = ANDROID_RB_THERMOFF; + } else { + command_invalid = true; + } + if (command_invalid) { + LOG(ERROR) << "powerctl: unrecognized command '" << command << "'"; + return false; + } + + DoReboot(cmd, reason_string, reboot_target, run_fsck); + return true; +} diff --git a/init/reboot.h b/init/reboot.h index 6432fa5df..b304b3cd9 100644 --- a/init/reboot.h +++ b/init/reboot.h @@ -29,4 +29,7 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget, bool runFsck) __attribute__((__noreturn__)); +// Parses and handles a setprop sys.powerctl message. +bool HandlePowerctlMessage(const std::string& command); + #endif diff --git a/rootdir/init.rc b/rootdir/init.rc index a43b0e1ab..8b9b19d7c 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -638,9 +638,6 @@ on property:vold.decrypt=trigger_shutdown_framework class_reset late_start class_reset main -on property:sys.powerctl=* - powerctl ${sys.powerctl} - on property:sys.boot_completed=1 bootchart stop