Support to update PFR D-Bus properties cache data

1) Added support to update the PFR D-Bus properties cache
   data when Host/Chassis State changes.
2) Optimized code to use list for creating Software
   versions object.
3) Added missing "ufm_locked" state property to Attributes.

Tested:
Did chassis power on/off/soft/reset using ipmitool and
validated the d-bus properties updated or not. Also checked
for proper object creation with right data.

Change-Id: I706e53d47c2bcca5f3374e632b300622429f6f1b
Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
diff --git a/service/inc/pfr_mgr.hpp b/service/inc/pfr_mgr.hpp
index d1bd7e5..749abe3 100644
--- a/service/inc/pfr_mgr.hpp
+++ b/service/inc/pfr_mgr.hpp
@@ -21,27 +21,46 @@
 #include <phosphor-logging/log.hpp>
 #include <boost/asio.hpp>
 
+#include "pfr.hpp"
+
 namespace intel
 {
 namespace pfr
 {
 
+static constexpr const char *versionPurposeBMC =
+    "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
+static constexpr const char *versionPurposeHost =
+    "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
+static constexpr const char *versionPurposeOther =
+    "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
+
+static constexpr const char *versionStr = "Version";
+static constexpr const char *ufmProvisionedStr = "ufm_provisioned";
+static constexpr const char *ufmLockedStr = "ufm_locked";
+
 class PfrVersion
 {
   public:
     PfrVersion(sdbusplus::asio::object_server &srv_,
                std::shared_ptr<sdbusplus::asio::connection> &conn_,
-               const std::string &path_);
+               const std::string &path_, const ImageType &imgType_,
+               const std::string &purpose_);
     ~PfrVersion() = default;
 
     std::shared_ptr<sdbusplus::asio::connection> conn;
 
+    void updateVersion();
+
   private:
     sdbusplus::asio::object_server &server;
+    std::shared_ptr<sdbusplus::asio::dbus_interface> versionIface;
+    bool internalSet = false;
 
     std::string path;
     std::string version;
     std::string purpose;
+    ImageType imgType;
 };
 
 class PfrConfig
@@ -53,12 +72,15 @@
 
     std::shared_ptr<sdbusplus::asio::connection> conn;
 
+    void updateProvisioningStatus();
+
   private:
     sdbusplus::asio::object_server &server;
+    std::shared_ptr<sdbusplus::asio::dbus_interface> pfrCfgIface;
+    bool internalSet = false;
 
-    bool getPFRProvisionedState();
-    std::string getBIOSVersion(uint8_t type);
-    std::string getBMCVersion(uint8_t type);
+    bool ufmProvisioned;
+    bool ufmLocked;
 };
 
 } // namespace pfr
diff --git a/service/src/mainapp.cpp b/service/src/mainapp.cpp
index cc5f9ff..f044d8a 100644
--- a/service/src/mainapp.cpp
+++ b/service/src/mainapp.cpp
@@ -20,9 +20,6 @@
 #include "pfr.hpp"
 #include <boost/asio.hpp>
 
-static std::array<std::string, 5> listVersionPaths = {
-    "bmc_active", "bmc_recovery", "bios_active", "bios_recovery", "cpld"};
-
 // Caches the last Recovery/Panic Count to
 // identify any new Recovery/panic actions.
 /* TODO: When BMC Reset's, these values will be lost
@@ -39,6 +36,22 @@
 std::unique_ptr<boost::asio::steady_timer> stateTimer = nullptr;
 std::unique_ptr<boost::asio::steady_timer> initTimer = nullptr;
 
+std::vector<std::unique_ptr<intel::pfr::PfrVersion>> pfrVersionObjects;
+std::unique_ptr<intel::pfr::PfrConfig> pfrConfigObject;
+
+using namespace intel::pfr;
+// List holds <ObjPath> <ImageType> <VersionPurpose>
+static std::vector<std::tuple<std::string, ImageType, std::string>>
+    verComponentList = {
+        std::make_tuple("bmc_active", ImageType::bmcActive, versionPurposeBMC),
+        std::make_tuple("bmc_recovery", ImageType::bmcRecovery,
+                        versionPurposeBMC),
+        std::make_tuple("bios_active", ImageType::biosActive,
+                        versionPurposeHost),
+        std::make_tuple("bios_recovery", ImageType::biosRecovery,
+                        versionPurposeHost),
+        std::make_tuple("cpld", ImageType::cpld, versionPurposeOther)};
+
 // Recovery reason map. { <CPLD association>, <Recovery Reason> }
 static std::map<uint8_t, std::string> recoveryReasonMap = {
     {0x01, "PCH active authentication failure"},
@@ -71,6 +84,20 @@
     {0x10, "PCH recovery update intent"},
     {0x11, "BMC recovery update intent"}};
 
+static void updateDbusPropertiesCache()
+{
+    for (const auto& pfrVerObj : pfrVersionObjects)
+    {
+        pfrVerObj->updateVersion();
+    }
+
+    // Update provisoningStatus properties
+    pfrConfigObject->updateProvisioningStatus();
+
+    phosphor::logging::log<phosphor::logging::level::INFO>(
+        "PFR Manager service cache data updated.");
+}
+
 static void logLastRecoveryEvent()
 {
     uint8_t reason = 0;
@@ -249,15 +276,18 @@
     stateTimer = std::make_unique<boost::asio::steady_timer>(io);
     initTimer = std::make_unique<boost::asio::steady_timer>(io);
     conn->request_name("xyz.openbmc_project.Intel.PFR.Manager");
-    auto server = sdbusplus::asio::object_server(conn, true);
+    auto server = sdbusplus::asio::object_server(conn);
 
     // Create Intel PFR attributes object and interface
-    intel::pfr::PfrConfig obj(server, conn);
+    pfrConfigObject = std::make_unique<intel::pfr::PfrConfig>(server, conn);
 
+    pfrVersionObjects.clear();
     // Create Software objects using Versions interface
-    for (const auto& path : listVersionPaths)
+    for (const auto& entry : verComponentList)
     {
-        intel::pfr::PfrVersion obj(server, conn, path);
+        pfrVersionObjects.emplace_back(std::make_unique<intel::pfr::PfrVersion>(
+            server, conn, std::get<0>(entry), std::get<1>(entry),
+            std::get<2>(entry)));
     }
 
     // Monitor Boot finished signal and set the checkpoint 9 to
@@ -313,6 +343,9 @@
                         stateTimerRunning = false;
                     }
                 }
+
+                // Update the D-Bus properties when chassis state changes.
+                updateDbusPropertiesCache();
             }
         });
 
@@ -355,6 +388,9 @@
                         stateTimerRunning = false;
                     }
                 }
+
+                // Update the D-Bus properties when host state changes.
+                updateDbusPropertiesCache();
             }
         });
 
diff --git a/service/src/pfr_mgr.cpp b/service/src/pfr_mgr.cpp
index 3fbbe36..9186916 100644
--- a/service/src/pfr_mgr.cpp
+++ b/service/src/pfr_mgr.cpp
@@ -15,7 +15,6 @@
 */
 
 #include "pfr_mgr.hpp"
-#include "pfr.hpp"
 
 namespace intel
 {
@@ -27,54 +26,34 @@
 
 PfrVersion::PfrVersion(sdbusplus::asio::object_server &srv_,
                        std::shared_ptr<sdbusplus::asio::connection> &conn_,
-                       const std::string &path_) :
+                       const std::string &path_, const ImageType &imgType_,
+                       const std::string &purpose_) :
     server(srv_),
-    conn(conn_), path(path_)
+    conn(conn_), path(path_), imgType(imgType_), purpose(purpose_)
 {
-    if (path == "bmc_active")
-    {
-        purpose = "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
-        ImageType imgType = ImageType::bmcActive;
-        version = getVersionInfoCPLD(imgType);
-    }
-    else if (path == "bmc_recovery")
-    {
-        purpose = "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
-        ImageType imgType = ImageType::bmcRecovery;
-        version = getVersionInfoCPLD(imgType);
-    }
-    else if (path == "bios_active")
-    {
-        purpose = "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
-        ImageType imgType = ImageType::biosActive;
-        version = getVersionInfoCPLD(imgType);
-    }
-    else if (path == "bios_recovery")
-    {
-        purpose = "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
-        ImageType imgType = ImageType::biosRecovery;
-        version = getVersionInfoCPLD(imgType);
-    }
-    else if (path == "cpld")
-    {
-        purpose = "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
-        ImageType imgType = ImageType::cpld;
-        version = getVersionInfoCPLD(imgType);
-    }
-    else
-    {
-        phosphor::logging::log<phosphor::logging::level::ERR>(
-            "Invalid path specified for PfrVersion");
-        return;
-    }
+    version = getVersionInfoCPLD(imgType);
 
     std::string objPath = "/xyz/openbmc_project/software/" + path;
-    auto iface =
+    versionIface =
         server.add_interface(objPath, "xyz.openbmc_project.Software.Version");
-    iface->register_property("Purpose", purpose);
-    iface->register_property("Version", version);
+    versionIface->register_property("Purpose", purpose);
+    versionIface->register_property(
+        versionStr, version,
+        // Override set
+        [this](const std::string &req, std::string &propertyValue) {
+            if (internalSet)
+            {
+                if (req != propertyValue)
+                {
+                    version = req;
+                    propertyValue = req;
+                    return 1;
+                }
+            }
+            return 0;
+        });
 
-    iface->initialize();
+    versionIface->initialize();
 
     /* Activation interface represents activation state for an associated
      * xyz.openbmc_project.Software.Version. since these versions are already
@@ -92,13 +71,16 @@
     activationIface->initialize();
 }
 
-bool PfrConfig::getPFRProvisionedState()
+void PfrVersion::updateVersion()
 {
-    bool ufmProvisioned = false;
-    bool ufmLocked = false;
-    getProvisioningStatus(ufmLocked, ufmProvisioned);
-
-    return ufmProvisioned;
+    if (versionIface && versionIface->is_initialized())
+    {
+        std::string ver = getVersionInfoCPLD(imgType);
+        internalSet = true;
+        versionIface->set_property(versionStr, ver);
+        internalSet = false;
+    }
+    return;
 }
 
 PfrConfig::PfrConfig(sdbusplus::asio::object_server &srv_,
@@ -106,13 +88,58 @@
     server(srv_),
     conn(conn_)
 {
-    auto pfrIntf =
+    pfrCfgIface =
         server.add_interface("/xyz/openbmc_project/intel_pfr",
                              "xyz.openbmc_project.Intel_PFR.Attributes");
 
-    pfrIntf->register_property("provisioned_state", getPFRProvisionedState());
+    getProvisioningStatus(ufmLocked, ufmProvisioned);
 
-    pfrIntf->initialize();
+    pfrCfgIface->register_property(ufmProvisionedStr, ufmProvisioned,
+                                   // Override set
+                                   [this](const bool req, bool propertyValue) {
+                                       if (internalSet)
+                                       {
+                                           if (req != propertyValue)
+                                           {
+                                               ufmProvisioned = req;
+                                               propertyValue = req;
+                                               return 1;
+                                           }
+                                       }
+                                       return 0;
+                                   });
+
+    pfrCfgIface->register_property(ufmLockedStr, ufmLocked,
+                                   // Override set
+                                   [this](const bool req, bool propertyValue) {
+                                       if (internalSet)
+                                       {
+                                           if (req != propertyValue)
+                                           {
+                                               ufmLocked = req;
+                                               propertyValue = req;
+                                               return 1;
+                                           }
+                                       }
+                                       return 0;
+                                   });
+
+    pfrCfgIface->initialize();
+}
+
+void PfrConfig::updateProvisioningStatus()
+{
+    if (pfrCfgIface && pfrCfgIface->is_initialized())
+    {
+        bool lockVal = false;
+        bool provVal = false;
+        getProvisioningStatus(lockVal, provVal);
+        internalSet = true;
+        pfrCfgIface->set_property(ufmProvisionedStr, provVal);
+        pfrCfgIface->set_property(ufmLockedStr, lockVal);
+        internalSet = false;
+    }
+    return;
 }
 
 } // namespace pfr