Synchronize NTP settings with systemd-timedated

Bmcweb get/set the "NTP settings" on phosphor-settings.
phosphor-time-manager and phosphor-settings are responsible to sync the
settings with systemd-timedated. So the services like bmcweb and ipmid
will only have to get/set the property on phosphor-settings.

However, in order to avoid a race condition issue with NTP set, bmcweb
now directly uses systemd instead of routing through phosphor-settings.
As a result, there may be differences in the "NTP settings" between
phosphor-setttings and systemd-timedated. To address this, this commit
adds a match to monitor time sync method changes on systemd-timedated
and updates it to phosphor-settings.

Tested:
```
1. Get current NTP setting:
busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP
b true

busctl get-property xyz.openbmc_project.Settings /xyz/openbmc_project/time/sync_method xyz.openbmc_project.Time.Synchronization TimeSyncMethod -j
{
    "type" : "s",
    "data" : "xyz.openbmc_project.Time.Synchronization.Method.NTP"
}

2. Call method in systemd timedate, to change NTP setting:
busctl call org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 SetNTP bb false false

journal log:
phosphor-time-manager[28150]: Time mode has been changed to xyz.openbmc_project.Time.Synchronization.Method.Manual
phosphor-time-manager[28150]: NTP property changed in systemd time service, update to phosphor-settings.
phosphor-time-manager[28150]: NTP mode is already the same, skip setting to systemd time service again.

3. Get NTP setting again, NTP in phosphor-settings is synced with systemd-timedated:
busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP
b false

busctl get-property xyz.openbmc_project.Settings /xyz/openbmc_project/time/sync_method xyz.openbmc_project.Time.Synchronization TimeSyncMethod -j
{
    "type" : "s",
    "data" : "xyz.openbmc_project.Time.Synchronization.Method.Manual"
}

4. Set property in phosphor-settings, to change NTP setting:
busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/time/sync_method xyz.openbmc_project.Time.Synchronization TimeSyncMethod s "xyz.openbmc_project.Time.Synchronization.Method.NTP"

journal log:
phosphor-time-manager[28150]: Updated NTP setting: True
phosphor-time-manager[28150]: Time mode has been changed to xyz.openbmc_project.Time.Synchronization.Method.NTP
phosphor-time-manager[28150]: NTP property changed in phosphor-settings, update to systemd time service.
phosphor-time-manager[28150]: NTP mode is already the same, skip setting to phosphor-settings again.

5. Get NTP setting again, NTP in phosphor-settings is synced with systemd-timedated:
busctl get-property org.freedesktop.timedate1 /org/freedesktop/timedate1 org.freedesktop.timedate1 NTP
b true

busctl get-property xyz.openbmc_project.Settings /xyz/openbmc_project/time/sync_method xyz.openbmc_project.Time.Synchronization TimeSyncMethod -j
{
    "type" : "s",
    "data" : "xyz.openbmc_project.Time.Synchronization.Method.NTP"
}
```

Signed-off-by: Jason Zhu <zhujiesen@bytedance.com>
Change-Id: I192d2257569f46aa0f5473331595c5242d816964
diff --git a/manager.cpp b/manager.cpp
index 1aeaf4b..c59c174 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -15,6 +15,7 @@
 constexpr auto systemdTimePath = "/org/freedesktop/timedate1";
 constexpr auto systemdTimeInterface = "org.freedesktop.timedate1";
 constexpr auto methodSetNtp = "SetNTP";
+constexpr auto propertyNtp = "NTP";
 } // namespace
 
 namespace phosphor
@@ -27,6 +28,9 @@
 Manager::Manager(sdbusplus::bus_t& bus) : bus(bus), settings(bus)
 {
     using namespace sdbusplus::bus::match::rules;
+    timedateMatches.emplace_back(
+        bus, propertiesChanged(systemdTimePath, systemdTimeInterface),
+        [&](sdbusplus::message_t& m) { onTimedateChanged(m); });
     settingsMatches.emplace_back(
         bus, propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf),
         [&](sdbusplus::message_t& m) { onSettingsChanged(m); });
@@ -35,17 +39,29 @@
     auto mode = getSetting(settings.timeSyncMethod.c_str(),
                            settings::timeSyncIntf, propertyTimeMode);
 
-    onPropertyChanged(propertyTimeMode, mode);
+    onPropertyChanged(propertyTimeMode, mode, true);
 }
 
 void Manager::onPropertyChanged(const std::string& key,
-                                const std::string& value)
+                                const std::string& value, bool forceSet)
 {
     assert(key == propertyTimeMode);
 
-    // Notify listeners
-    setCurrentTimeMode(value);
-    onTimeModeChanged(value);
+    bool newNtpMode = (settings::ntpSync == value);
+    bool oldNtpMode = (Mode::NTP == getTimeMode());
+    if (forceSet || (newNtpMode != oldNtpMode))
+    {
+        // Notify listeners
+        onTimeModeChanged(value);
+        setCurrentTimeMode(value);
+        debug("NTP property changed in phosphor-settings, update to systemd"
+              " time service.");
+    }
+    else
+    {
+        debug("NTP mode is already the same, skip setting to systemd time"
+              " service again.");
+    }
 }
 
 int Manager::onSettingsChanged(sdbusplus::message_t& msg)
@@ -68,6 +84,52 @@
     return 0;
 }
 
+int Manager::onTimedateChanged(sdbusplus::message_t& msg)
+{
+    using Properties = std::map<std::string, std::variant<std::string, bool>>;
+
+    std::string interface;
+    Properties properties;
+
+    msg.read(interface, properties);
+
+    auto iter = properties.find(propertyNtp);
+    if (iter == properties.end())
+    {
+        return -1;
+    }
+
+    try
+    {
+        bool newNtpMode = std::get<bool>(iter->second);
+        bool oldNtpMode = (Mode::NTP == getTimeMode());
+        if (newNtpMode != oldNtpMode)
+        {
+            const auto& timeMode = newNtpMode ? settings::ntpSync
+                                              : settings::manualSync;
+            std::string settingManager = utils::getService(
+                bus, settings.timeSyncMethod.c_str(), settings::timeSyncIntf);
+            utils::setProperty(bus, settingManager, settings.timeSyncMethod,
+                               settings::timeSyncIntf, propertyTimeMode,
+                               timeMode);
+            setCurrentTimeMode(timeMode);
+            debug("NTP property changed in systemd time service, update to"
+                  " phosphor-settings.");
+        }
+        else
+        {
+            debug("NTP mode is already the same, skip setting to"
+                  " phosphor-settings again.");
+        }
+    }
+    catch (const std::exception& ex)
+    {
+        error("Failed to sync NTP: {ERROR}", "ERROR", ex);
+    }
+
+    return 0;
+}
+
 void Manager::updateNtpSetting(const std::string& value)
 {
     try