init: fix process restarting

The time data types associated with restarting processes halfway moved
to std::chrono and halfway didn't.  In this intermediate state, the
times would get converted from nanoseconds to seconds then to
milliseconds.  The precision lost when converting to seconds would
cause the main loop of init to spin whenever a process was within a
second of being restarted.

This patch cleans up this logic and uses nanoseconds and milliseconds
explicitly, with a ceiling to milliseconds to prevent unneeded
spinning.

Test: boot bullhead, kill processes, see that they restart sanely.

Change-Id: I0b017ba0e50c09704b0c5cdfcde1dba461804593
diff --git a/init/init.cpp b/init/init.cpp
index f063c3f..03f0bb7 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -53,6 +53,7 @@
 
 #include <fstream>
 #include <memory>
+#include <optional>
 #include <vector>
 
 #include "bootchart.h"
@@ -84,7 +85,6 @@
 static char qemu[32];
 
 std::string default_console = "/dev/console";
-static time_t process_needs_restart_at;
 
 const char *ENV[32];
 
@@ -219,12 +219,21 @@
     }
 }
 
-static void restart_processes()
-{
-    process_needs_restart_at = 0;
-    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
-        s->RestartIfNeeded(&process_needs_restart_at);
+static std::optional<boot_clock::time_point> RestartProcesses() {
+    std::optional<boot_clock::time_point> next_process_restart_time;
+    ServiceManager::GetInstance().ForEachService([&next_process_restart_time](Service* s) {
+        if (!(s->flags() & SVC_RESTARTING)) return;
+
+        auto restart_time = s->time_started() + 5s;
+        if (boot_clock::now() > restart_time) {
+            s->Start();
+        } else {
+            if (!next_process_restart_time || restart_time < *next_process_restart_time) {
+                next_process_restart_time = restart_time;
+            }
+        }
     });
+    return next_process_restart_time;
 }
 
 void handle_control_message(const std::string& msg, const std::string& name) {
@@ -1175,12 +1184,16 @@
             am.ExecuteOneCommand();
         }
         if (!(waiting_for_prop || sm.IsWaitingForExec())) {
-            if (!shutting_down) restart_processes();
+            if (!shutting_down) {
+                auto next_process_restart_time = RestartProcesses();
 
-            // If there's a process that needs restarting, wake up in time for that.
-            if (process_needs_restart_at != 0) {
-                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
-                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
+                // If there's a process that needs restarting, wake up in time for that.
+                if (next_process_restart_time) {
+                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
+                                           *next_process_restart_time - boot_clock::now())
+                                           .count();
+                    if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
+                }
             }
 
             // If there's more work to do, wake up again immediately.