init: add reboot_on_failure service option
This replaces the recently added `exec_reboot_on_failure` builtin, since
it'll be cleaner to extend service definitions than extending `exec`.
This is in line with what we decided when adding `exec_start` instead
of extending `exec` to add parameters for priority.
Test: `exec_start` a service with a reboot_on_failure option and watch
the system reboot appropriately when the service is not found and when
the service terminates with a non-zero exit code.
Change-Id: I332bf9839fa94840d159a810c4a6ba2522189d0b
diff --git a/init/service.cpp b/init/service.cpp
index 7a20966..793a2b2 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -29,6 +29,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/sockets.h>
@@ -41,6 +42,7 @@
#if defined(__ANDROID__)
#include <ApexProperties.sysprop.h>
+#include "init.h"
#include "mount_namespace.h"
#include "property_service.h"
#else
@@ -50,6 +52,7 @@
using android::base::boot_clock;
using android::base::GetProperty;
using android::base::Join;
+using android::base::make_scope_guard;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -250,6 +253,11 @@
f(siginfo);
}
+ if ((siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) && on_failure_reboot_target_) {
+ LOG(ERROR) << "Service with 'reboot_on_failure' option failed, shutting down system.";
+ EnterShutdown(*on_failure_reboot_target_);
+ }
+
if (flags_ & SVC_EXEC) UnSetExec();
if (flags_ & SVC_TEMPORARY) return;
@@ -325,6 +333,12 @@
Result<void> Service::ExecStart() {
+ auto reboot_on_failure = make_scope_guard([this] {
+ if (on_failure_reboot_target_) {
+ EnterShutdown(*on_failure_reboot_target_);
+ }
+ });
+
if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
// Don't delay the service for ExecStart() as the semantic is that
// the caller might depend on the side effect of the execution.
@@ -345,10 +359,17 @@
<< " gid " << proc_attr_.gid << "+" << proc_attr_.supp_gids.size() << " context "
<< (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting...";
+ reboot_on_failure.Disable();
return {};
}
Result<void> Service::Start() {
+ auto reboot_on_failure = make_scope_guard([this] {
+ if (on_failure_reboot_target_) {
+ EnterShutdown(*on_failure_reboot_target_);
+ }
+ });
+
if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
ServiceList::GetInstance().DelayService(*this);
return Error() << "Cannot start an updatable service '" << name_
@@ -371,6 +392,7 @@
flags_ |= SVC_RESTART;
}
// It is not an error to try to start a service that is already running.
+ reboot_on_failure.Disable();
return {};
}
@@ -532,6 +554,7 @@
}
NotifyStateChange("running");
+ reboot_on_failure.Disable();
return {};
}