Merge "init: Support custom shutdown actions"
am: c1bc4241f8
Change-Id: I6bb1789dbc5edbb10f2f4d712e9ca83e6302fdf4
This commit is contained in:
commit
5b89535442
10 changed files with 69 additions and 9 deletions
|
@ -326,6 +326,13 @@ void ActionManager::DumpState() const {
|
|||
}
|
||||
}
|
||||
|
||||
void ActionManager::ClearQueue() {
|
||||
// We are shutting down so don't claim the oneshot builtin actions back
|
||||
current_executing_actions_ = {};
|
||||
event_queue_ = {};
|
||||
current_command_ = 0;
|
||||
}
|
||||
|
||||
bool ActionParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
|
||||
int line, std::string* err) {
|
||||
std::vector<std::string> triggers(args.begin() + 1, args.end());
|
||||
|
|
|
@ -104,6 +104,7 @@ class ActionManager {
|
|||
void ExecuteOneCommand();
|
||||
bool HasMoreCommands() const;
|
||||
void DumpState() const;
|
||||
void ClearQueue();
|
||||
|
||||
private:
|
||||
ActionManager(ActionManager const&) = delete;
|
||||
|
|
|
@ -119,7 +119,7 @@ static int reboot_into_recovery(const std::vector<std::string>& options) {
|
|||
LOG(ERROR) << "failed to set bootloader message: " << err;
|
||||
return -1;
|
||||
}
|
||||
DoReboot(ANDROID_RB_RESTART2, "reboot", "recovery", false);
|
||||
property_set("sys.powerctl", "reboot,recovery");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ static int epoll_fd = -1;
|
|||
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
|
||||
static std::string wait_prop_name;
|
||||
static std::string wait_prop_value;
|
||||
static bool shutting_down;
|
||||
|
||||
void DumpState() {
|
||||
ServiceManager::GetInstance().DumpState();
|
||||
|
@ -158,21 +159,31 @@ bool start_waiting_for_property(const char *name, const char *value)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ResetWaitForProp() {
|
||||
wait_prop_name.clear();
|
||||
wait_prop_value.clear();
|
||||
waiting_for_prop.reset();
|
||||
}
|
||||
|
||||
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);
|
||||
// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
|
||||
// commands to be executed.
|
||||
if (name == "sys.powerctl") {
|
||||
if (HandlePowerctlMessage(value)) {
|
||||
shutting_down = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
|
||||
|
||||
if (waiting_for_prop) {
|
||||
if (wait_prop_name == name && wait_prop_value == value) {
|
||||
wait_prop_name.clear();
|
||||
wait_prop_value.clear();
|
||||
LOG(INFO) << "Wait for property took " << *waiting_for_prop;
|
||||
waiting_for_prop.reset();
|
||||
ResetWaitForProp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1166,7 +1177,7 @@ int main(int argc, char** argv) {
|
|||
am.ExecuteOneCommand();
|
||||
}
|
||||
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
|
||||
restart_processes();
|
||||
if (!shutting_down) restart_processes();
|
||||
|
||||
// If there's a process that needs restarting, wake up in time for that.
|
||||
if (process_needs_restart_at != 0) {
|
||||
|
|
|
@ -44,6 +44,8 @@ bool start_waiting_for_property(const char *name, const char *value);
|
|||
|
||||
void DumpState();
|
||||
|
||||
void ResetWaitForProp();
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include "capabilities.h"
|
||||
#include "init.h"
|
||||
#include "property_service.h"
|
||||
#include "service.h"
|
||||
|
||||
|
@ -490,6 +491,9 @@ bool HandlePowerctlMessage(const std::string& command) {
|
|||
}
|
||||
} else if (command == "thermal-shutdown") { // no additional parameter allowed
|
||||
cmd = ANDROID_RB_THERMOFF;
|
||||
// Do not queue "shutdown" trigger since we want to shutdown immediately
|
||||
DoReboot(cmd, command, reboot_target, run_fsck);
|
||||
return true;
|
||||
} else {
|
||||
command_invalid = true;
|
||||
}
|
||||
|
@ -498,7 +502,26 @@ bool HandlePowerctlMessage(const std::string& command) {
|
|||
return false;
|
||||
}
|
||||
|
||||
DoReboot(cmd, command, reboot_target, run_fsck);
|
||||
LOG(INFO) << "Clear action queue and start shutdown trigger";
|
||||
ActionManager::GetInstance().ClearQueue();
|
||||
// Queue shutdown trigger first
|
||||
ActionManager::GetInstance().QueueEventTrigger("shutdown");
|
||||
// Queue built-in shutdown_done
|
||||
auto shutdown_handler = [cmd, command, reboot_target,
|
||||
run_fsck](const std::vector<std::string>&) {
|
||||
DoReboot(cmd, command, reboot_target, run_fsck);
|
||||
return 0;
|
||||
};
|
||||
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
|
||||
|
||||
// Skip wait for prop if it is in progress
|
||||
ResetWaitForProp();
|
||||
|
||||
// Skip wait for exec if it is in progress
|
||||
if (ServiceManager::GetInstance().IsWaitingForExec()) {
|
||||
ServiceManager::GetInstance().ClearExecWait();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1152,6 +1152,15 @@ void ServiceManager::ReapAnyOutstandingChildren() {
|
|||
}
|
||||
}
|
||||
|
||||
void ServiceManager::ClearExecWait() {
|
||||
// Clear EXEC flag if there is one pending
|
||||
// And clear the wait flag
|
||||
for (const auto& s : services_) {
|
||||
s->UnSetExec();
|
||||
}
|
||||
exec_waiter_.reset();
|
||||
}
|
||||
|
||||
bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
|
||||
int line, std::string* err) {
|
||||
if (args.size() < 3) {
|
||||
|
|
|
@ -89,6 +89,7 @@ class Service {
|
|||
void DumpState() const;
|
||||
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
|
||||
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
|
||||
void UnSetExec() { flags_ &= ~SVC_EXEC; }
|
||||
|
||||
const std::string& name() const { return name_; }
|
||||
const std::set<std::string>& classnames() const { return classnames_; }
|
||||
|
@ -186,7 +187,7 @@ class Service {
|
|||
};
|
||||
|
||||
class ServiceManager {
|
||||
public:
|
||||
public:
|
||||
static ServiceManager& GetInstance();
|
||||
|
||||
// Exposed for testing
|
||||
|
@ -208,8 +209,9 @@ public:
|
|||
void ReapAnyOutstandingChildren();
|
||||
void RemoveService(const Service& svc);
|
||||
void DumpState() const;
|
||||
void ClearExecWait();
|
||||
|
||||
private:
|
||||
private:
|
||||
// Cleans up a child process that exited.
|
||||
// Returns true iff a children was cleaned up.
|
||||
bool ReapOneProcess();
|
||||
|
|
|
@ -370,6 +370,7 @@ bool expand_props(const std::string& src, std::string* dst) {
|
|||
|
||||
void panic() {
|
||||
LOG(ERROR) << "panic: rebooting to bootloader";
|
||||
// Do not queue "shutdown" trigger since we want to shutdown immediately
|
||||
DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
|
||||
}
|
||||
|
||||
|
|
|
@ -678,6 +678,10 @@ on property:security.perf_harden=0
|
|||
on property:security.perf_harden=1
|
||||
write /proc/sys/kernel/perf_event_paranoid 3
|
||||
|
||||
# on shutdown
|
||||
# In device's init.rc, this trigger can be used to do device-specific actions
|
||||
# before shutdown. e.g disable watchdog and mask error handling
|
||||
|
||||
## Daemon processes to be run by init.
|
||||
##
|
||||
service ueventd /sbin/ueventd
|
||||
|
|
Loading…
Reference in a new issue