BMC: Restore version and activation dbus objects on BMC reboot.

- Read the /media/ dir for active bmc versions. Each active
  version has a /etc/os-release inside /media/ which is used to
  recreate the version and activation objects.

Resolves openbmc/openbmc#2137

Change-Id: I40e97396b0912095868172a5a6566e2189a3446b
Signed-off-by: Saqib Khan <khansa@us.ibm.com>
diff --git a/item_updater.cpp b/item_updater.cpp
index aa072ef..7d7df3f 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -145,40 +145,88 @@
 
 void ItemUpdater::processBMCImage()
 {
-    using VersionClass = phosphor::software::manager::Version;
-
-    auto purpose = server::Version::VersionPurpose::BMC;
-    auto version = phosphor::software::manager::Version::getBMCVersion();
-    auto id = phosphor::software::manager::Version::getId(version);
-    auto path =  std::string{SOFTWARE_OBJPATH} + '/' + id;
-
     // Create an association to the BMC inventory item
     AssociationList associations{(std::make_tuple(
                                       ACTIVATION_FWD_ASSOCIATION,
                                       ACTIVATION_REV_ASSOCIATION,
                                       bmcInventoryPath))};
 
-    activations.insert(std::make_pair(
-                           id,
-                           std::make_unique<Activation>(
-                               bus,
-                               path,
-                               *this,
-                               id,
-                               server::Activation::Activations::Active,
-                               associations)));
-    versions.insert(std::make_pair(
-                        id,
-                        std::make_unique<VersionClass>(
+    // Read os-release from folders under /media/ to get
+    // BMC Software Versions.
+    for(const auto& iter : fs::directory_iterator(MEDIA_DIR))
+    {
+        auto activationState = server::Activation::Activations::Active;
+        static const auto BMC_RO_PREFIX_LEN = strlen(BMC_RO_PREFIX);
+
+        // Check if the BMC_RO_PREFIXis the prefix of the iter.path
+        if (0 == iter.path().native().compare(0, BMC_RO_PREFIX_LEN,
+                                              BMC_RO_PREFIX))
+        {
+            auto osRelease = iter.path() / OS_RELEASE_FILE;
+            if (!fs::is_regular_file(osRelease))
+            {
+                log<level::ERR>("Failed to read osRelease\n",
+                                entry("FileName=%s", osRelease.string()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+            auto version =
+                    phosphor::software::manager::Version::
+                            getBMCVersion(osRelease);
+            if (version.empty())
+            {
+                log<level::ERR>("Failed to read version from osRelease",
+                                entry("FILENAME=%s", osRelease.string()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+            // The versionId is extracted from the path
+            // for example /media/ro-2a1022fe
+            auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
+            auto purpose = server::Version::VersionPurpose::BMC;
+            auto path = fs::path(SOFTWARE_OBJPATH) / id;
+
+            // Create Activation instance for this version.
+            activations.insert(std::make_pair(
+                                   id,
+                                   std::make_unique<Activation>(
+                                       bus,
+                                       path,
+                                       *this,
+                                       id,
+                                       server::Activation::Activations::Active,
+                                       associations)));
+
+            // If Active, create RedundancyPriority instance for this version.
+            if (activationState == server::Activation::Activations::Active)
+            {
+                uint8_t priority = std::numeric_limits<uint8_t>::max();
+                if (!restoreFromFile(id, priority))
+                {
+                    log<level::ERR>("Unable to restore priority from file.",
+                            entry("VERSIONID=%s", id));
+                }
+                activations.find(id)->second->redundancyPriority =
+                        std::make_unique<RedundancyPriority>(
                              bus,
                              path,
-                             version,
-                             purpose,
-                             "",
-                             std::bind(&ItemUpdater::erase,
+                             *(activations.find(id)->second),
+                             priority);
+            }
+
+            // Create Version instance for this version.
+            versions.insert(std::make_pair(
+                                id,
+                                std::make_unique<
+                                     phosphor::software::manager::Version>(
+                                     bus,
+                                     path,
+                                     version,
+                                     purpose,
+                                     "",
+                                     std::bind(&ItemUpdater::erase,
                                        this,
                                        std::placeholders::_1))));
-
+        }
+    }
     return;
 }
 
@@ -186,6 +234,17 @@
 {
     // Delete ReadOnly partitions
     removeReadOnlyPartition(entryId);
+    removeFile(entryId);
+
+    // Remove the priority environment variable.
+    auto serviceFile = "obmc-flash-bmc-setenv@" + entryId + ".service";
+    auto method = bus.new_method_call(
+            SYSTEMD_BUSNAME,
+            SYSTEMD_PATH,
+            SYSTEMD_INTERFACE,
+            "StartUnit");
+    method.append(serviceFile, "replace");
+    bus.call_noreply(method);
 
     // Removing entry in versions map
     auto it = versions.find(entryId);
@@ -212,7 +271,6 @@
     //       If not, don't continue.
 
     this->activations.erase(entryId);
-    removeFile(entryId);
 }
 
 ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(