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
(cherry picked from commit 98ad32a967
)
This commit is contained in:
parent
02012596c1
commit
5ceb7b3ebd
|
@ -365,10 +365,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.
|
||||
|
|
|
@ -603,54 +603,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() > 2) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
|
@ -962,7 +914,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}},
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "keychords.h"
|
||||
#include "log.h"
|
||||
#include "property_service.h"
|
||||
#include "reboot.h"
|
||||
#include "service.h"
|
||||
#include "signal_handler.h"
|
||||
#include "ueventd.h"
|
||||
|
@ -149,8 +150,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) {
|
||||
|
|
|
@ -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)());
|
||||
|
||||
|
|
|
@ -206,7 +206,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -27,4 +27,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
|
||||
|
|
|
@ -641,9 +641,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
|
||||
|
||||
|
|
Loading…
Reference in New Issue