Merge "init: Support custom shutdown actions"

am: c1bc4241f8

Change-Id: I6bb1789dbc5edbb10f2f4d712e9ca83e6302fdf4
This commit is contained in:
Wei Wang 2017-07-05 23:54:56 +00:00 committed by android-build-merger
commit 5b89535442
10 changed files with 69 additions and 9 deletions

View file

@ -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());

View file

@ -104,6 +104,7 @@ class ActionManager {
void ExecuteOneCommand();
bool HasMoreCommands() const;
void DumpState() const;
void ClearQueue();
private:
ActionManager(ActionManager const&) = delete;

View file

@ -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;
}

View file

@ -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) {

View file

@ -44,6 +44,8 @@ bool start_waiting_for_property(const char *name, const char *value);
void DumpState();
void ResetWaitForProp();
} // namespace init
} // namespace android

View file

@ -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;
}

View file

@ -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) {

View file

@ -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();

View file

@ -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);
}

View file

@ -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