Merge "init: handle sys.powerctl immediately" am: 14ed55bae8 am: e6bfb53196 am: 8972f887d2
am: 1f49801ab1

Change-Id: I6af3f4e1850593f13f27a3fd48f1310e0c3e369c
diff --git a/init/README.md b/init/README.md
index fc50730..8cb1e52 100644
--- a/init/README.md
+++ b/init/README.md
@@ -370,10 +370,6 @@
   _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 2327cdf..43eb420 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -598,58 +598,6 @@
     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 @@
         {"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 dedca29..a857377 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 @@
     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 fe850ef..1da3350 100644
--- a/init/init.h
+++ b/init/init.h
@@ -26,7 +26,7 @@
 
 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 2aa89ff..20a2aa1 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -205,7 +205,7 @@
     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 d9ebd91..4d65437 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -425,3 +425,54 @@
     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 6432fa5..b304b3c 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 f6b7039..0517884 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -641,9 +641,6 @@
     class_reset late_start
     class_reset main
 
-on property:sys.powerctl=*
-    powerctl ${sys.powerctl}
-
 on property:sys.boot_completed=1
     bootchart stop