Update time stamp on VPD collection status update

StartTime and CompletedTime indicates time duration for VPD collection,
which is useful information to analyze how much time is taken to
collect VPD for any FRU.
This commits handles updating time stamp during VPD collection.

Output:
```
Time stamps reset to zero, when FRU is deleted :

Before Delete method:
root@p11bmc:/tmp/images# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/lcd_op_panel_hill xyz.openbmc_project.Common.Progress Status; busctl introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/lcd_op_panel_hill  xyz.openbmc_project.Common.Progress
s "xyz.openbmc_project.Common.Progress.OperationStatus.Completed"
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         1756486364                               emits-change writable
.StartTime                          property  t         1756486363                               emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable

Call Delete FRU VPD method:
root@p11bmc:/tmp/images# busctl  call com.ibm.VPD.Manager /com/ibm/VPD/Manager com.ibm.VPD.Manager deleteFRUVPD o "/xyz/openbmc_project/inventory/system/chassis/motherboard/lcd_op_panel_hill"

After Delete FRU VPD:
root@p11bmc:/tmp/images# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/lcd_op_panel_hill xyz.openbmc_project.Common.Progress Status; busctl introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/lcd_op_panel_hill  xyz.openbmc_project.Common.Progress
s "xyz.openbmc_project.Common.Progress.OperationStatus.NotStarted"
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         0                                        emits-change writable
.StartTime                          property  t         0                                        emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable

Time stamp updated to all Sub FRUs, ex for failed VPD collection scenario:

Before:
busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_bot xyz.openbmc_project.Common.Progress Status; busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0 xyz.openbmc_project.Common.Progress Status; busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_top xyz.openbmc_project.Common.Progress Status
s "xyz.openbmc_project.Common.Progress.OperationStatus.NotStarted"
s "xyz.openbmc_project.Common.Progress.OperationStatus.NotStarted"
s "xyz.openbmc_project.Common.Progress.OperationStatus.NotStarted"

root@p11bmc:/tmp/images# busctl  introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0 xyz.openbmc_project.Common.Progress;  busctl  introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_top xyz.openbmc_project.Common.Progress; busctl  introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_bot xyz.openbmc_project.Common.Progress
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         0                                        emits-change writable
.StartTime                          property  t         0                                        emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         0                                        emits-change writable
.StartTime                          property  t         0                                        emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         0                                        emits-change writable
.StartTime                          property  t         0                                        emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable

Call Collect FRU VPD method:
root@p11bmc:/tmp/images# busctl  call com.ibm.VPD.Manager /com/ibm/VPD/Manager com.ibm.VPD.Manager CollectFRUVPD o "/xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0"

After Collect FRU VPD Failed:
root@p11bmc:/tmp/images# busctl  introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0 xyz.openbmc_project.Common.Progress;  busctl  introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_top xyz.openbmc_project.Common.Progress; busctl  introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_bot xyz.openbmc_project.Common.Progress
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         1756486110                               emits-change writable
.StartTime                          property  t         1756486110                               emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         1756486110                               emits-change writable
.StartTime                          property  t         1756486110                               emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.CompletedTime                      property  t         1756486110                               emits-change writable
.StartTime                          property  t         1756486110                               emits-change writable
.Status                             property  s         "xyz.openbmc_project.Common.Progress.Op… emits-change writable
root@p11bmc:/tmp/images# busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_bot xyz.openbmc_project.Common.Progress Status; busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0 xyz.openbmc_project.Common.Progress Status; busctl get-property xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/pcieslot0/pcie_card0/cxp_top xyz.openbmc_project.Common.Progress Status
s "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"
s "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"
s "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"

```

Output:
Change-Id: I835c1cc9082b8be411c4460aac3845fba249a120
Signed-off-by: Anupama B R <anupama.b.r1@ibm.com>
diff --git a/vpd-manager/include/utility/vpd_specific_utility.hpp b/vpd-manager/include/utility/vpd_specific_utility.hpp
index d72b7f3..a3f8921 100644
--- a/vpd-manager/include/utility/vpd_specific_utility.hpp
+++ b/vpd-manager/include/utility/vpd_specific_utility.hpp
@@ -628,6 +628,8 @@
                                 l_propertyMap.emplace(
                                     l_propertyName,
                                     constants::vpdCollectionNotStarted);
+                                l_propertyMap.emplace("StartTime", 0);
+                                l_propertyMap.emplace("CompletedTime", 0);
                             }
                             else
                             {
@@ -1073,49 +1075,6 @@
 }
 
 /**
- * @brief API to save current time stamp in PIM.
- *
- * This API will capture current time stamp and save it in progress interface
- * for the given inventory path.
- *
- * @param[in] i_inventoryPath - Inventory path of FRU.
- * @param[in] i_property - Property to save the time.
- */
-inline void saveTimeStampInPim(const std::string& i_inventoryPath,
-                               const std::string& i_property) noexcept
-{
-    if (i_inventoryPath.empty() || i_property.empty())
-    {
-        logging::logMessage("Invalid input parameter. Can't save time in PIM.");
-        return;
-    }
-
-    try
-    {
-        types::ObjectMap l_ObjMap = {std::make_pair(
-            i_inventoryPath,
-            types::InterfaceMap{std::make_pair(
-                constants::vpdCollectionInterface,
-                types::PropertyMap{std::make_pair(
-                    i_property,
-                    types::DbusVariantType{
-                        commonUtility::getCurrentTimeSinceEpoch()})})})};
-
-        if (!dbusUtility::callPIM(move(l_ObjMap)))
-        {
-            logging::logMessage(
-                "Call to PIM failed while saving time for path " +
-                i_inventoryPath);
-        }
-    }
-    catch (const std::exception& l_ex)
-    {
-        logging::logMessage("Failed to save time stamp under PIM for reason: " +
-                            std::string(l_ex.what()));
-    }
-}
-
-/**
  * @brief API to get error code message.
  *
  * @param[in] i_errCode - error code.
diff --git a/vpd-manager/include/worker.hpp b/vpd-manager/include/worker.hpp
index a40ea24..bb778a1 100644
--- a/vpd-manager/include/worker.hpp
+++ b/vpd-manager/include/worker.hpp
@@ -189,6 +189,18 @@
      */
     void setDeviceTreeAndJson();
 
+    /**
+     * @brief API to set CollectionStatus property.
+     *
+     * This API updates the CollectionStatus property of the given FRU with the
+     * given value.
+     *
+     * @param[in] i_vpdPath - EEPROM or inventory path.
+     * @param[in] i_value - Value to be set.
+     */
+    void setCollectionStatusProperty(const std::string& i_fruPath,
+                                     const std::string& i_value) const noexcept;
+
   private:
     /**
      * @brief An API to parse and publish a FRU VPD over D-Bus.
@@ -533,18 +545,6 @@
                i_fru.value("handlePresence", true);
     }
 
-    /**
-     * @brief API to set CollectionStatus property.
-     *
-     * This API updates the CollectionStatus property of the given FRU with the
-     * given value.
-     *
-     * @param[in] i_vpdPath - EEPROM or inventory path.
-     * @param[in] i_value - Value to be set.
-     */
-    void setCollectionStatusProperty(const std::string& i_fruPath,
-                                     const std::string& i_value) const noexcept;
-
     // Parsed JSON file.
     nlohmann::json m_parsedJson{};
 
diff --git a/vpd-manager/oem-handler/ibm_handler.cpp b/vpd-manager/oem-handler/ibm_handler.cpp
index debdbca..02a92f5 100644
--- a/vpd-manager/oem-handler/ibm_handler.cpp
+++ b/vpd-manager/oem-handler/ibm_handler.cpp
@@ -436,6 +436,8 @@
     }
     catch (const std::exception& l_ex)
     {
+        m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
+                                              constants::vpdCollectionFailed);
         // Any issue in system's inital set up is handled in this catch. Error
         // will not propogate to manager.
         EventLogger::createSyncPel(
diff --git a/vpd-manager/src/worker.cpp b/vpd-manager/src/worker.cpp
index 04f060f..b725745 100644
--- a/vpd-manager/src/worker.cpp
+++ b/vpd-manager/src/worker.cpp
@@ -359,6 +359,9 @@
 
 void Worker::setDeviceTreeAndJson()
 {
+    setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
+                                constants::vpdCollectionInProgress);
+
     // JSON is madatory for processing of this API.
     if (m_parsedJson.empty())
     {
@@ -429,6 +432,8 @@
 
         // proceed to publish system VPD.
         publishSystemVPD(parsedVpdMap);
+        setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
+                                    constants::vpdCollectionCompleted);
         return;
     }
 
@@ -1059,14 +1064,6 @@
             processFunctionalProperty(inventoryPath, interfaces);
             processEnabledProperty(inventoryPath, interfaces);
 
-            // Update collection status as successful
-            types::PropertyMap l_collectionProperty = {
-                {"Status", constants::vpdCollectionCompleted}};
-
-            vpdSpecificUtility::insertOrMerge(interfaces,
-                                              constants::vpdCollectionInterface,
-                                              std::move(l_collectionProperty));
-
             objectInterfaceMap.emplace(std::move(fruObjectPath),
                                        std::move(interfaces));
         }
@@ -1403,36 +1400,8 @@
         m_activeCollectionThreadCount++;
         m_mutex.unlock();
 
-        uint16_t l_errCode = 0;
-
-        // Set CollectionStatus as InProgress. Since it's an intermediate state
-        // D-bus set-property call is good enough to update the status.
-        l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
-            m_parsedJson, i_vpdFilePath, l_errCode);
-
-        if (!l_inventoryPath.empty())
-        {
-            // save time stamp under PIM.
-            vpdSpecificUtility::saveTimeStampInPim(l_inventoryPath,
-                                                   "StartTime");
-
-            if (!dbusUtility::writeDbusProperty(
-                    jsonUtility::getServiceName(m_parsedJson, l_inventoryPath),
-                    l_inventoryPath, constants::vpdCollectionInterface,
-                    "Status",
-                    types::DbusVariantType{constants::vpdCollectionInProgress}))
-            {
-                logging::logMessage(
-                    "Unable to set collection Status as InProgress for " +
-                    i_vpdFilePath + ". Error : " + "DBus write failed");
-            }
-        }
-        else if (l_errCode)
-        {
-            logging::logMessage(
-                "Failed to get inventory path for FRU [" + i_vpdFilePath +
-                "], error : " + vpdSpecificUtility::getErrCodeMsg(l_errCode));
-        }
+        setCollectionStatusProperty(i_vpdFilePath,
+                                    constants::vpdCollectionInProgress);
 
         const types::VPDMapVariant& parsedVpdMap = parseVpdFile(i_vpdFilePath);
         if (!std::holds_alternative<std::monostate>(parsedVpdMap))
@@ -1440,10 +1409,6 @@
             types::ObjectMap objectInterfaceMap;
             populateDbus(parsedVpdMap, objectInterfaceMap, i_vpdFilePath);
 
-            // save end time stamp under PIM.
-            vpdSpecificUtility::saveTimeStampInPim(l_inventoryPath,
-                                                   "CompletedTime");
-
             // Notify PIM
             if (!dbusUtility::callPIM(move(objectInterfaceMap)))
             {
@@ -1456,6 +1421,10 @@
         {
             logging::logMessage("Empty parsedVpdMap recieved for path [" +
                                 i_vpdFilePath + "]. Check PEL for reason.");
+
+            // As empty parsedVpdMap recieved for some reason, but still
+            // considered VPD collection is completed. Hence FRU collection
+            // Status will be set as completed.
         }
     }
     catch (const std::exception& ex)
@@ -1463,10 +1432,6 @@
         setCollectionStatusProperty(i_vpdFilePath,
                                     constants::vpdCollectionFailed);
 
-        // save end time stamp under PIM.
-        vpdSpecificUtility::saveTimeStampInPim(l_inventoryPath,
-                                               "CompletedTime");
-
         // handle all the exceptions internally. Return only true/false
         // based on status of execution.
         if (typeid(ex) == std::type_index(typeid(DataException)))
@@ -1525,6 +1490,9 @@
         m_semaphore.release();
         return std::make_tuple(false, i_vpdFilePath);
     }
+
+    setCollectionStatusProperty(i_vpdFilePath,
+                                constants::vpdCollectionCompleted);
     m_semaphore.release();
     return std::make_tuple(true, i_vpdFilePath);
 }
@@ -2034,18 +2002,8 @@
         // D-bus set-property call is good enough to update the status.
         const std::string& l_collStatusProp = "Status";
 
-        if (!dbusUtility::writeDbusProperty(
-                jsonUtility::getServiceName(m_parsedJson,
-                                            std::string(i_dbusObjPath)),
-                std::string(i_dbusObjPath), constants::vpdCollectionInterface,
-                l_collStatusProp,
-                types::DbusVariantType{constants::vpdCollectionInProgress}))
-        {
-            logging::logMessage(
-                "Unable to set collection Status as InProgress for " +
-                std::string(i_dbusObjPath) +
-                ". Continue single FRU VPD collection.");
-        }
+        setCollectionStatusProperty(l_fruPath,
+                                    constants::vpdCollectionInProgress);
 
         // Parse VPD
         types::VPDMapVariant l_parsedVpd = parseVpdFile(l_fruPath);
@@ -2075,6 +2033,8 @@
                 "Notify PIM failed. Single FRU VPD collection failed for " +
                 std::string(i_dbusObjPath));
         }
+        setCollectionStatusProperty(l_fruPath,
+                                    constants::vpdCollectionCompleted);
     }
     catch (const std::exception& l_error)
     {
@@ -2095,6 +2055,27 @@
                 "Given path is empty. Can't set collection Status property");
         }
 
+        types::PropertyMap l_timeStampMap;
+        if (i_value == constants::vpdCollectionCompleted ||
+            i_value == constants::vpdCollectionFailed)
+        {
+            l_timeStampMap.emplace(
+                "CompletedTime",
+                types::DbusVariantType{
+                    commonUtility::getCurrentTimeSinceEpoch()});
+        }
+        else if (i_value == constants::vpdCollectionInProgress)
+        {
+            l_timeStampMap.emplace(
+                "StartTime", types::DbusVariantType{
+                                 commonUtility::getCurrentTimeSinceEpoch()});
+        }
+        else if (i_value == constants::vpdCollectionNotStarted)
+        {
+            l_timeStampMap.emplace("StartTime", 0);
+            l_timeStampMap.emplace("CompletedTime", 0);
+        }
+
         types::ObjectMap l_objectInterfaceMap;
 
         if (m_parsedJson["frus"].contains(i_vpdPath))
@@ -2106,6 +2087,8 @@
 
                 types::PropertyMap l_propertyValueMap;
                 l_propertyValueMap.emplace("Status", i_value);
+                l_propertyValueMap.insert(l_timeStampMap.begin(),
+                                          l_timeStampMap.end());
 
                 types::InterfaceMap l_interfaces;
                 vpdSpecificUtility::insertOrMerge(
@@ -2128,6 +2111,8 @@
 
             types::PropertyMap l_propertyValueMap;
             l_propertyValueMap.emplace("Status", i_value);
+            l_propertyValueMap.insert(l_timeStampMap.begin(),
+                                      l_timeStampMap.end());
 
             types::InterfaceMap l_interfaces;
             vpdSpecificUtility::insertOrMerge(l_interfaces,