bmc_state: Update last update time after timesync

Currently the lastRebootTime is updated at service boot up and reuses
the values on future requests. This can cause incorrect values like

```
$ busctl get-property xyz.openbmc_project.State.BMC /xyz/openbmc_project/state/bmc0 xyz.openbmc_project.State.BMC LastRebootTime
t 1680555476000
$ uptime
 11:23:05 up 1 day, 24 min,  load average: 3.08, 2.89, 2.84
```

1680555476000 -> Mon Apr 03 2023 20:57:56 GMT+0000
which is more than 1 day and 24 minutes ago.

The change will detect property changes to `time-sync.target` which
would be activated after timesync happens. It will then deactivate the
matcher after update the lastReboot time once.

Tested:
After bootup and timesync, the lastReboot time is now correct.

Change-Id: Iee8a0bc9f0c5b22d5010f1a677011e44b5d425d3
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/bmc_state_manager.cpp b/bmc_state_manager.cpp
index 9f67a31..efaa0a2 100644
--- a/bmc_state_manager.cpp
+++ b/bmc_state_manager.cpp
@@ -242,6 +242,20 @@
     return server::BMC::lastRebootCause(value);
 }
 
+void BMC::updateLastRebootTime()
+{
+    using namespace std::chrono;
+    struct sysinfo info;
+
+    auto rc = sysinfo(&info);
+    assert(rc == 0);
+    // Since uptime is in seconds, also get the current time in seconds.
+    auto now = time_point_cast<seconds>(system_clock::now());
+    auto rebootTimeTs = now - seconds(info.uptime);
+    rebootTime =
+        duration_cast<milliseconds>(rebootTimeTs.time_since_epoch()).count();
+}
+
 uint64_t BMC::lastRebootTime() const
 {
     return rebootTime;
diff --git a/bmc_state_manager.hpp b/bmc_state_manager.hpp
index d50d4f3..7ffa67b 100644
--- a/bmc_state_manager.hpp
+++ b/bmc_state_manager.hpp
@@ -43,23 +43,35 @@
             sdbusRule::type::signal() + sdbusRule::member("JobRemoved") +
                 sdbusRule::path("/org/freedesktop/systemd1") +
                 sdbusRule::interface("org.freedesktop.systemd1.Manager"),
-            [this](sdbusplus::message_t& m) { bmcStateChange(m); }))
+            [this](sdbusplus::message_t& m) { bmcStateChange(m); })),
+
+        timeSyncSignal(std::make_unique<decltype(timeSyncSignal)::element_type>(
+            bus,
+            sdbusRule::propertiesChanged(
+                "/org/freedesktop/systemd1/unit/time_2dsync_2etarget",
+                "org.freedesktop.systemd1.Unit"),
+            [this](sdbusplus::message_t& m) {
+        std::string interface;
+        std::unordered_map<std::string, std::variant<std::string>>
+            propertyChanged;
+        m.read(interface, propertyChanged);
+
+        for (const auto& [key, value] : propertyChanged)
+        {
+            if (key == "ActiveState" &&
+                std::holds_alternative<std::string>(value) &&
+                std::get<std::string>(value) == "active")
+            {
+                updateLastRebootTime();
+                timeSyncSignal.reset();
+            }
+        }
+            }))
     {
         utils::subscribeToSystemdSignals(bus);
         discoverInitialState();
         discoverLastRebootCause();
-
-        using namespace std::chrono;
-        struct sysinfo info;
-
-        auto rc = sysinfo(&info);
-        assert(rc == 0);
-        // Since uptime is in seconds, also get the current time in seconds.
-        auto now = time_point_cast<seconds>(system_clock::now());
-        auto rebootTimeTs = now - seconds(info.uptime);
-        rebootTime =
-            duration_cast<milliseconds>(rebootTimeTs.time_since_epoch())
-                .count();
+        updateLastRebootTime();
 
         this->emit_object_added();
     };
@@ -115,12 +127,20 @@
     /** @brief Used to subscribe to dbus system state changes **/
     std::unique_ptr<sdbusplus::bus::match_t> stateSignal;
 
+    /** @brief Used to subscribe to timesync **/
+    std::unique_ptr<sdbusplus::bus::match_t> timeSyncSignal;
+
     /**
      * @brief discover the last reboot cause of the bmc
      **/
     void discoverLastRebootCause();
 
     /**
+     * @brief update the last reboot time of the bmc
+     **/
+    void updateLastRebootTime();
+
+    /**
      * @brief the lastRebootTime calcuated at startup.
      **/
     uint64_t rebootTime;