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.
diff --git a/init/service.cpp b/init/service.cpp
index d0a0751..d72433a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -890,22 +890,6 @@
     } /* else: Service is restarting anyways. */
 }
 
-void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
-    boot_clock::time_point now = boot_clock::now();
-    boot_clock::time_point next_start = time_started_ + 5s;
-    if (now > next_start) {
-        flags_ &= (~SVC_RESTARTING);
-        Start();
-        return;
-    }
-
-    time_t next_start_time_t = time(nullptr) +
-        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
-    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
-        *process_needs_restart_at = next_start_time_t;
-    }
-}
-
 // The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
 void Service::StopOrReset(int how) {
     // The service is still SVC_RUNNING until its process exits, but if it has
@@ -1123,15 +1107,6 @@
     }
 }
 
-void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
-                                             void (*func)(Service* svc)) const {
-    for (const auto& s : services_) {
-        if (s->flags() & matchflags) {
-            func(s.get());
-        }
-    }
-}
-
 void ServiceManager::RemoveService(const Service& svc) {
     auto svc_it = std::find_if(services_.begin(), services_.end(),
                                [&svc] (const std::unique_ptr<Service>& s) {
diff --git a/init/service.h b/init/service.h
index 976f431..850aca4 100644
--- a/init/service.h
+++ b/init/service.h
@@ -83,7 +83,6 @@
     void Stop();
     void Terminate();
     void Restart();
-    void RestartIfNeeded(time_t* process_needs_restart_at);
     void Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
@@ -94,6 +93,7 @@
     const std::set<std::string>& classnames() const { return classnames_; }
     unsigned flags() const { return flags_; }
     pid_t pid() const { return pid_; }
+    android::base::boot_clock::time_point time_started() const { return time_started_; }
     int crash_count() const { return crash_count_; }
     uid_t uid() const { return uid_; }
     gid_t gid() const { return gid_; }
@@ -217,8 +217,6 @@
     void ForEachServiceShutdownOrder(const std::function<void(Service*)>& callback) const;
     void ForEachServiceInClass(const std::string& classname,
                                void (*func)(Service* svc)) const;
-    void ForEachServiceWithFlags(unsigned matchflags,
-                             void (*func)(Service* svc)) const;
     void ReapAnyOutstandingChildren();
     void RemoveService(const Service& svc);
     void DumpState() const;