summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Cherry <tomcherry@google.com>2017-04-17 16:34:20 -0700
committerTom Cherry <tomcherry@google.com>2017-04-17 16:40:06 -0700
commit98ad32a967079be80a101458d8a29d7ecefbb547 (patch)
tree64c0d213fc7c4f81f1424aa601792c5628c2989b
parentb7826a74f246ac148c3f5c6ad73e3fc8728a0bfe (diff)
downloadsystem_core-98ad32a967079be80a101458d8a29d7ecefbb547.tar.gz
system_core-98ad32a967079be80a101458d8a29d7ecefbb547.tar.bz2
system_core-98ad32a967079be80a101458d8a29d7ecefbb547.zip
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
-rw-r--r--init/README.md4
-rw-r--r--init/builtins.cpp53
-rw-r--r--init/init.cpp10
-rw-r--r--init/init.h2
-rw-r--r--init/property_service.cpp2
-rw-r--r--init/reboot.cpp51
-rw-r--r--init/reboot.h3
-rw-r--r--rootdir/init.rc3
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 <service>`
> 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<std::string>& args) {
return 0;
}
-static int do_powerctl(const std::vector<std::string>& args) {
- const std::string& command = args[1];
- unsigned int cmd = 0;
- std::vector<std::string> 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<std::string>& 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<std::string> 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