Add a very basic userspace reboot watchdog

Watchdog is just a forked process that is going to fall back to the
full reboot in case device wasn't able to boot in given amount of time.

Currently this amount is hard-coded to 1 minute, but in the future it
will be controlled by a read-only property.

Also added sync calls before and after tearing down services.

Test: adb reboot userspace
Bug: 135984674
Change-Id: Ie6053c9446a6761deae6dc104036bb35b09ef0e2
This commit is contained in:
Nikita Ioffe 2019-11-07 15:37:38 +00:00
parent 2ebe95ff2a
commit 82a431eb2f

View file

@ -760,6 +760,12 @@ static Result<void> DoUserspaceReboot() {
were_enabled.push_back(s);
}
}
{
Timer sync_timer;
LOG(INFO) << "sync() before terminating services...";
sync();
LOG(INFO) << "sync() took " << sync_timer;
}
// TODO(b/135984674): do we need shutdown animation for userspace reboot?
// TODO(b/135984674): control userspace timeout via read-only property?
StopServicesAndLogViolations(stop_first, 10s, true /* SIGTERM */);
@ -775,6 +781,12 @@ static Result<void> DoUserspaceReboot() {
// TODO(b/135984674): store information about offending services for debugging.
return Error() << r << " debugging services are still running";
}
{
Timer sync_timer;
LOG(INFO) << "sync() after stopping services...";
sync();
LOG(INFO) << "sync() took " << sync_timer;
}
if (auto result = UnmountAllApexes(); !result) {
return result;
}
@ -792,7 +804,38 @@ static Result<void> DoUserspaceReboot() {
return {};
}
static void UserspaceRebootWatchdogThread() {
if (!WaitForProperty("sys.init.userspace_reboot_in_progress", "1", 20s)) {
// TODO(b/135984674): should we reboot instead?
LOG(WARNING) << "Userspace reboot didn't start in 20 seconds. Stopping watchdog";
return;
}
LOG(INFO) << "Starting userspace reboot watchdog";
// TODO(b/135984674): this should be configured via a read-only sysprop.
std::chrono::milliseconds timeout = 60s;
if (!WaitForProperty("sys.boot_completed", "1", timeout)) {
LOG(ERROR) << "Failed to boot in " << timeout.count() << "ms. Switching to full reboot";
// In this case device is in a boot loop. Only way to recover is to do dirty reboot.
RebootSystem(ANDROID_RB_RESTART2, "userspace-reboot-watchdog-triggered");
}
LOG(INFO) << "Device booted, stopping userspace reboot watchdog";
}
static void HandleUserspaceReboot() {
// Spinnig up a separate thread will fail the setns call later in the boot sequence.
// Fork a new process to monitor userspace reboot while we are investigating a better solution.
pid_t pid = fork();
if (pid < 0) {
PLOG(ERROR) << "Failed to fork process for userspace reboot watchdog. Switching to full "
<< "reboot";
trigger_shutdown("reboot,userspace-reboot-failed-to-fork");
return;
}
if (pid == 0) {
// Child
UserspaceRebootWatchdogThread();
_exit(EXIT_SUCCESS);
}
LOG(INFO) << "Clearing queue and starting userspace-reboot-requested trigger";
auto& am = ActionManager::GetInstance();
am.ClearQueue();