Refactor: Split item_updater to common and ubi

The existing item_updater is highly coupled with ubifs.
It will support static layout and ubi in future.
So split the functions in to common ones and ubi specific ones, and move
the ubi specific code in ubi dir.

1. Keep common functions and make them virtual for extension.
    createActiveAssociation()
    updateFunctionalAssociation()
    removeAssociation()
    erase()
2. Create ubi/item_updater_ubi and move other functions into it.
3. Change updateFunctionalAssociation() parameter for future use.

To support static layout, a new item_updater_static will be written.

Tested: On the last commit of the patch series, run code update and
        factory reset on Witherspoon and all work fine.

Change-Id: I4cc55b31ee3f37c5b27168611305dee8ce02880a
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/Makefile.am b/Makefile.am
index e012ae5..c924948 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,12 @@
 	item_updater.cpp \
 	item_updater_main.cpp
 
+if UBIFS_LAYOUT
+include ubi/Makefile.am.include
+else
+include static/Makefile.am.include
+endif
+
 if WANT_SIGNATURE_VERIFY_BUILD
 openpower_update_manager_SOURCES += \
 	image_verify.cpp \
diff --git a/configure.ac b/configure.ac
index f2d8766..0213ed4 100755
--- a/configure.ac
+++ b/configure.ac
@@ -146,6 +146,14 @@
 AC_DEFINE(PNOR_PRSV_ACTIVE_PATH, "/var/lib/phosphor-software-manager/pnor/prsv",
     [Path to the active preserved pnor partitions])
 
+# Setup ubifs layout support
+# For now make it default enabled
+AC_ARG_ENABLE([ubifs_layout],
+    AS_HELP_STRING([--disable-ubifs_layout], [Disable ubifs support.]))
+AS_IF([test "x$enable_ubifs_layout" != "xno"], \
+    [AC_DEFINE([UBIFS_LAYOUT],[],[Enable ubifs support.])])
+AM_CONDITIONAL([UBIFS_LAYOUT], [test "x$enable_ubifs_layout" != "xno"])
+
 AC_ARG_VAR(ACTIVE_PNOR_MAX_ALLOWED, [The maximum allowed active pnor versions])
 AS_IF([test "x$ACTIVE_PNOR_MAX_ALLOWED" == "x"], [ACTIVE_PNOR_MAX_ALLOWED=2])
 AC_DEFINE_UNQUOTED([ACTIVE_PNOR_MAX_ALLOWED], [$ACTIVE_PNOR_MAX_ALLOWED], [The maximum allowed active pnor versions])
diff --git a/item_updater.cpp b/item_updater.cpp
index f920661..06f3bc8 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -2,18 +2,10 @@
 
 #include "item_updater.hpp"
 
-#include "activation.hpp"
-#include "serialize.hpp"
-#include "version.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
-#include <experimental/filesystem>
-#include <fstream>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
-#include <queue>
-#include <string>
-#include <xyz/openbmc_project/Software/Version/server.hpp>
 
 namespace openpower
 {
@@ -21,357 +13,91 @@
 {
 namespace updater
 {
-
-// When you see server:: you know we're referencing our base class
-namespace server = sdbusplus::xyz::openbmc_project::Software::server;
-namespace fs = std::experimental::filesystem;
-
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 using namespace phosphor::logging;
 
-constexpr auto squashFSImage = "pnor.xz.squashfs";
-
-// TODO: Change paths once openbmc/openbmc#1663 is completed.
-constexpr auto MBOXD_INTERFACE = "org.openbmc.mboxd";
-constexpr auto MBOXD_PATH = "/org/openbmc/mboxd";
-
-void ItemUpdater::createActivation(sdbusplus::message::message& m)
+void ItemUpdater::createActiveAssociation(const std::string& path)
 {
-    using SVersion = server::Version;
-    using VersionPurpose = SVersion::VersionPurpose;
-    namespace msg = sdbusplus::message;
-    namespace variant_ns = msg::variant_ns;
-
-    sdbusplus::message::object_path objPath;
-    std::map<std::string, std::map<std::string, msg::variant<std::string>>>
-        interfaces;
-    m.read(objPath, interfaces);
-
-    std::string path(std::move(objPath));
-    std::string filePath;
-    auto purpose = VersionPurpose::Unknown;
-    std::string version;
-
-    for (const auto& intf : interfaces)
-    {
-        if (intf.first == VERSION_IFACE)
-        {
-            for (const auto& property : intf.second)
-            {
-                if (property.first == "Purpose")
-                {
-                    // Only process the Host and System images
-                    auto value = SVersion::convertVersionPurposeFromString(
-                        variant_ns::get<std::string>(property.second));
-
-                    if (value == VersionPurpose::Host ||
-                        value == VersionPurpose::System)
-                    {
-                        purpose = value;
-                    }
-                }
-                else if (property.first == "Version")
-                {
-                    version = variant_ns::get<std::string>(property.second);
-                }
-            }
-        }
-        else if (intf.first == FILEPATH_IFACE)
-        {
-            for (const auto& property : intf.second)
-            {
-                if (property.first == "Path")
-                {
-                    filePath = variant_ns::get<std::string>(property.second);
-                }
-            }
-        }
-    }
-    if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
-    {
-        return;
-    }
-
-    // Version id is the last item in the path
-    auto pos = path.rfind("/");
-    if (pos == std::string::npos)
-    {
-        log<level::ERR>("No version id found in object path",
-                        entry("OBJPATH=%s", path.c_str()));
-        return;
-    }
-
-    auto versionId = path.substr(pos + 1);
-
-    if (activations.find(versionId) == activations.end())
-    {
-        // Determine the Activation state by processing the given image dir.
-        auto activationState = server::Activation::Activations::Invalid;
-        AssociationList associations = {};
-        if (ItemUpdater::validateSquashFSImage(filePath) == 0)
-        {
-            activationState = server::Activation::Activations::Ready;
-            // Create an association to the host inventory item
-            associations.emplace_back(std::make_tuple(
-                ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
-                HOST_INVENTORY_PATH));
-        }
-
-        fs::path manifestPath(filePath);
-        manifestPath /= MANIFEST_FILE;
-        std::string extendedVersion =
-            (Version::getValue(
-                 manifestPath.string(),
-                 std::map<std::string, std::string>{{"extended_version", ""}}))
-                .begin()
-                ->second;
-
-        activations.insert(std::make_pair(
-            versionId, std::make_unique<Activation>(
-                           bus, path, *this, versionId, extendedVersion,
-                           activationState, associations)));
-
-        auto versionPtr = std::make_unique<Version>(
-            bus, path, *this, versionId, version, purpose, filePath,
-            std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
-        versionPtr->deleteObject =
-            std::make_unique<Delete>(bus, path, *versionPtr);
-        versions.insert(std::make_pair(versionId, std::move(versionPtr)));
-    }
-    return;
+    assocs.emplace_back(
+        std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
+    associations(assocs);
 }
 
-void ItemUpdater::processPNORImage()
+void ItemUpdater::updateFunctionalAssociation(const std::string& versionId)
 {
-    // Read pnor.toc from folders under /media/
-    // to get Active Software Versions.
-    for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
+    std::string path = std::string{SOFTWARE_OBJPATH} + '/' + versionId;
+    // remove all functional associations
+    for (auto iter = assocs.begin(); iter != assocs.end();)
     {
-        auto activationState = server::Activation::Activations::Active;
-
-        static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
-        static const auto PNOR_RW_PREFIX_LEN = strlen(PNOR_RW_PREFIX);
-
-        // Check if the PNOR_RO_PREFIX is the prefix of the iter.path
-        if (0 ==
-            iter.path().native().compare(0, PNOR_RO_PREFIX_LEN, PNOR_RO_PREFIX))
+        if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
         {
-            // The versionId is extracted from the path
-            // for example /media/pnor-ro-2a1022fe.
-            auto id = iter.path().native().substr(PNOR_RO_PREFIX_LEN);
-            auto pnorTOC = iter.path() / PNOR_TOC_FILE;
-            if (!fs::is_regular_file(pnorTOC))
-            {
-                log<level::ERR>("Failed to read pnorTOC.",
-                                entry("FILENAME=%s", pnorTOC.c_str()));
-                ItemUpdater::erase(id);
-                continue;
-            }
-            auto keyValues = Version::getValue(
-                pnorTOC, {{"version", ""}, {"extended_version", ""}});
-            auto& version = keyValues.at("version");
-            if (version.empty())
-            {
-                log<level::ERR>("Failed to read version from pnorTOC",
-                                entry("FILENAME=%s", pnorTOC.c_str()));
-                activationState = server::Activation::Activations::Invalid;
-            }
-
-            auto& extendedVersion = keyValues.at("extended_version");
-            if (extendedVersion.empty())
-            {
-                log<level::ERR>("Failed to read extendedVersion from pnorTOC",
-                                entry("FILENAME=%s", pnorTOC.c_str()));
-                activationState = server::Activation::Activations::Invalid;
-            }
-
-            auto purpose = server::Version::VersionPurpose::Host;
-            auto path = fs::path(SOFTWARE_OBJPATH) / id;
-            AssociationList associations = {};
-
-            if (activationState == server::Activation::Activations::Active)
-            {
-                // Create an association to the host inventory item
-                associations.emplace_back(std::make_tuple(
-                    ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
-                    HOST_INVENTORY_PATH));
-
-                // Create an active association since this image is active
-                createActiveAssociation(path);
-            }
-
-            // Create Activation instance for this version.
-            activations.insert(
-                std::make_pair(id, std::make_unique<Activation>(
-                                       bus, path, *this, id, extendedVersion,
-                                       activationState, 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.c_str()));
-                }
-                activations.find(id)->second->redundancyPriority =
-                    std::make_unique<RedundancyPriority>(
-                        bus, path, *(activations.find(id)->second), priority);
-            }
-
-            // Create Version instance for this version.
-            auto versionPtr = std::make_unique<Version>(
-                bus, path, *this, id, version, purpose, "",
-                std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
-            versionPtr->deleteObject =
-                std::make_unique<Delete>(bus, path, *versionPtr);
-            versions.insert(std::make_pair(id, std::move(versionPtr)));
+            iter = assocs.erase(iter);
         }
-        else if (0 == iter.path().native().compare(0, PNOR_RW_PREFIX_LEN,
-                                                   PNOR_RW_PREFIX))
+        else
         {
-            auto id = iter.path().native().substr(PNOR_RW_PREFIX_LEN);
-            auto roDir = PNOR_RO_PREFIX + id;
-            if (!fs::is_directory(roDir))
-            {
-                log<level::ERR>("No corresponding read-only volume found.",
-                                entry("DIRNAME=%s", roDir.c_str()));
-                ItemUpdater::erase(id);
-            }
+            ++iter;
         }
     }
-
-    // Look at the RO symlink to determine if there is a functional image
-    auto id = determineId(PNOR_RO_ACTIVE_PATH);
-    if (!id.empty())
-    {
-        updateFunctionalAssociation(std::string{SOFTWARE_OBJPATH} + '/' + id);
-    }
-    return;
+    assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
+                                        FUNCTIONAL_REV_ASSOCIATION, path));
+    associations(assocs);
 }
 
-int ItemUpdater::validateSquashFSImage(const std::string& filePath)
+void ItemUpdater::removeAssociation(const std::string& path)
 {
-    auto file = fs::path(filePath) / squashFSImage;
-    if (fs::is_regular_file(file))
+    for (auto iter = assocs.begin(); iter != assocs.end();)
     {
-        return 0;
+        if ((std::get<2>(*iter)).compare(path) == 0)
+        {
+            iter = assocs.erase(iter);
+            associations(assocs);
+        }
+        else
+        {
+            ++iter;
+        }
+    }
+}
+
+bool ItemUpdater::erase(std::string entryId)
+{
+    if (isVersionFunctional(entryId) && isChassisOn())
+    {
+        log<level::ERR>(("Error: Version " + entryId +
+                         " is currently active and running on the host."
+                         " Unable to remove.")
+                            .c_str());
+        return false;
+    }
+
+    // Removing entry in versions map
+    auto it = versions.find(entryId);
+    if (it == versions.end())
+    {
+        log<level::ERR>(("Error: Failed to find version " + entryId +
+                         " in item updater versions map."
+                         " Unable to remove.")
+                            .c_str());
     }
     else
     {
-        log<level::ERR>("Failed to find the SquashFS image.");
-        return -1;
+        versions.erase(entryId);
     }
-}
 
-void ItemUpdater::removeReadOnlyPartition(std::string versionId)
-{
-    auto serviceFile = "obmc-flash-bios-ubiumount-ro@" + versionId + ".service";
-
-    // Remove the read-only partitions.
-    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
-                                      SYSTEMD_INTERFACE, "StartUnit");
-    method.append(serviceFile, "replace");
-    bus.call_noreply(method);
-}
-
-void ItemUpdater::removeReadWritePartition(std::string versionId)
-{
-    auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + versionId + ".service";
-
-    // Remove the read-write partitions.
-    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
-                                      SYSTEMD_INTERFACE, "StartUnit");
-    method.append(serviceFile, "replace");
-    bus.call_noreply(method);
-}
-
-void ItemUpdater::reset()
-{
-    std::vector<uint8_t> mboxdArgs;
-
-    // Suspend mboxd - no args required.
-    auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
-                                        MBOXD_INTERFACE, "cmd");
-
-    dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
-
-    auto responseMsg = bus.call(dbusCall);
-    if (responseMsg.is_method_error())
+    // Removing entry in activations map
+    auto ita = activations.find(entryId);
+    if (ita == activations.end())
     {
-        log<level::ERR>("Error in mboxd suspend call");
-        elog<InternalFailure>();
+        log<level::ERR>(("Error: Failed to find version " + entryId +
+                         " in item updater activations map."
+                         " Unable to remove.")
+                            .c_str());
     }
-
-    constexpr static auto patchDir = "/usr/local/share/pnor";
-    if (fs::is_directory(patchDir))
+    else
     {
-        for (const auto& iter : fs::directory_iterator(patchDir))
-        {
-            fs::remove_all(iter);
-        }
+        removeAssociation(ita->second->path);
+        activations.erase(entryId);
     }
-
-    // Clear the read-write partitions.
-    for (const auto& it : activations)
-    {
-        auto rwDir = PNOR_RW_PREFIX + it.first;
-        if (fs::is_directory(rwDir))
-        {
-            for (const auto& iter : fs::directory_iterator(rwDir))
-            {
-                fs::remove_all(iter);
-            }
-        }
-    }
-
-    // Clear the preserved partition.
-    if (fs::is_directory(PNOR_PRSV))
-    {
-        for (const auto& iter : fs::directory_iterator(PNOR_PRSV))
-        {
-            fs::remove_all(iter);
-        }
-    }
-
-    // Resume mboxd with arg 1, indicating that the flash was modified.
-    dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
-                                   "cmd");
-
-    mboxdArgs.push_back(1);
-    dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
-
-    responseMsg = bus.call(dbusCall);
-    if (responseMsg.is_method_error())
-    {
-        log<level::ERR>("Error in mboxd resume call");
-        elog<InternalFailure>();
-    }
-
-    return;
-}
-
-bool ItemUpdater::isVersionFunctional(const std::string& versionId)
-{
-    if (!fs::exists(PNOR_RO_ACTIVE_PATH))
-    {
-        return false;
-    }
-
-    fs::path activeRO = fs::read_symlink(PNOR_RO_ACTIVE_PATH);
-
-    if (!fs::is_directory(activeRO))
-    {
-        return false;
-    }
-
-    if (activeRO.string().find(versionId) == std::string::npos)
-    {
-        return false;
-    }
-
-    // active PNOR is the version we're checking
     return true;
 }
 
@@ -416,252 +142,6 @@
     return (strParam != CHASSIS_STATE_OFF);
 }
 
-void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
-{
-    // TODO openbmc/openbmc#1896 Improve the performance of this function
-    for (const auto& intf : activations)
-    {
-        if (intf.second->redundancyPriority)
-        {
-            if (intf.second->redundancyPriority.get()->priority() == value &&
-                intf.second->versionId != versionId)
-            {
-                intf.second->redundancyPriority.get()->priority(value + 1);
-            }
-        }
-    }
-}
-
-bool ItemUpdater::isLowestPriority(uint8_t value)
-{
-    for (const auto& intf : activations)
-    {
-        if (intf.second->redundancyPriority)
-        {
-            if (intf.second->redundancyPriority.get()->priority() < value)
-            {
-                return false;
-            }
-        }
-    }
-    return true;
-}
-
-void ItemUpdater::erase(std::string entryId)
-{
-    if (isVersionFunctional(entryId) && isChassisOn())
-    {
-        log<level::ERR>(("Error: Version " + entryId +
-                         " is currently active and running on the host."
-                         " Unable to remove.")
-                            .c_str());
-        return;
-    }
-    // Remove priority persistence file
-    removeFile(entryId);
-
-    // Removing read-only and read-write partitions
-    removeReadWritePartition(entryId);
-    removeReadOnlyPartition(entryId);
-
-    // Removing entry in versions map
-    auto it = versions.find(entryId);
-    if (it == versions.end())
-    {
-        log<level::ERR>(("Error: Failed to find version " + entryId +
-                         " in item updater versions map."
-                         " Unable to remove.")
-                            .c_str());
-    }
-    else
-    {
-        versions.erase(entryId);
-    }
-
-    // Removing entry in activations map
-    auto ita = activations.find(entryId);
-    if (ita == activations.end())
-    {
-        log<level::ERR>(("Error: Failed to find version " + entryId +
-                         " in item updater activations map."
-                         " Unable to remove.")
-                            .c_str());
-    }
-    else
-    {
-        removeAssociation(ita->second->path);
-        activations.erase(entryId);
-    }
-    return;
-}
-
-void ItemUpdater::deleteAll()
-{
-    auto chassisOn = isChassisOn();
-
-    for (const auto& activationIt : activations)
-    {
-        if (isVersionFunctional(activationIt.first) && chassisOn)
-        {
-            continue;
-        }
-        else
-        {
-            ItemUpdater::erase(activationIt.first);
-        }
-    }
-
-    // Remove any remaining pnor-ro- or pnor-rw- volumes that do not match
-    // the current version.
-    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
-                                      SYSTEMD_INTERFACE, "StartUnit");
-    method.append("obmc-flash-bios-cleanup.service", "replace");
-    bus.call_noreply(method);
-}
-
-// TODO: openbmc/openbmc#1402 Monitor flash usage
-void ItemUpdater::freeSpace()
-{
-    //  Versions with the highest priority in front
-    std::priority_queue<std::pair<int, std::string>,
-                        std::vector<std::pair<int, std::string>>,
-                        std::less<std::pair<int, std::string>>>
-        versionsPQ;
-
-    std::size_t count = 0;
-    for (const auto& iter : activations)
-    {
-        if (iter.second.get()->activation() ==
-            server::Activation::Activations::Active)
-        {
-            count++;
-            // Don't put the functional version on the queue since we can't
-            // remove the "running" PNOR version if it allows multiple PNORs
-            // But removing functional version if there is only one PNOR.
-            if (ACTIVE_PNOR_MAX_ALLOWED > 1 &&
-                isVersionFunctional(iter.second->versionId))
-            {
-                continue;
-            }
-            versionsPQ.push(std::make_pair(
-                iter.second->redundancyPriority.get()->priority(),
-                iter.second->versionId));
-        }
-    }
-
-    // If the number of PNOR versions is over ACTIVE_PNOR_MAX_ALLOWED -1,
-    // remove the highest priority one(s).
-    while ((count >= ACTIVE_PNOR_MAX_ALLOWED) && (!versionsPQ.empty()))
-    {
-        erase(versionsPQ.top().second);
-        versionsPQ.pop();
-        count--;
-    }
-}
-
-void ItemUpdater::createActiveAssociation(const std::string& path)
-{
-    assocs.emplace_back(
-        std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
-    associations(assocs);
-}
-
-void ItemUpdater::updateFunctionalAssociation(const std::string& path)
-{
-    // remove all functional associations
-    for (auto iter = assocs.begin(); iter != assocs.end();)
-    {
-        if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
-        {
-            iter = assocs.erase(iter);
-        }
-        else
-        {
-            ++iter;
-        }
-    }
-    assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
-                                        FUNCTIONAL_REV_ASSOCIATION, path));
-    associations(assocs);
-}
-
-void ItemUpdater::removeAssociation(const std::string& path)
-{
-    for (auto iter = assocs.begin(); iter != assocs.end();)
-    {
-        if ((std::get<2>(*iter)).compare(path) == 0)
-        {
-            iter = assocs.erase(iter);
-            associations(assocs);
-        }
-        else
-        {
-            ++iter;
-        }
-    }
-}
-
-std::string ItemUpdater::determineId(const std::string& symlinkPath)
-{
-    if (!fs::exists(symlinkPath))
-    {
-        return {};
-    }
-
-    auto target = fs::canonical(symlinkPath).string();
-
-    // check to make sure the target really exists
-    if (!fs::is_regular_file(target + "/" + PNOR_TOC_FILE))
-    {
-        return {};
-    }
-    // Get the image <id> from the symlink target
-    // for example /media/ro-2a1022fe
-    static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
-    return target.substr(PNOR_RO_PREFIX_LEN);
-}
-
-void GardReset::reset()
-{
-    // The GARD partition is currently misspelled "GUARD." This file path will
-    // need to be updated in the future.
-    auto path = fs::path(PNOR_PRSV_ACTIVE_PATH);
-    path /= "GUARD";
-    std::vector<uint8_t> mboxdArgs;
-
-    auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
-                                        MBOXD_INTERFACE, "cmd");
-
-    // Suspend mboxd - no args required.
-    dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
-
-    auto responseMsg = bus.call(dbusCall);
-    if (responseMsg.is_method_error())
-    {
-        log<level::ERR>("Error in mboxd suspend call");
-        elog<InternalFailure>();
-    }
-
-    if (fs::is_regular_file(path))
-    {
-        fs::remove(path);
-    }
-
-    dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
-                                   "cmd");
-
-    // Resume mboxd with arg 1, indicating that the flash is modified.
-    mboxdArgs.push_back(1);
-    dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
-
-    responseMsg = bus.call(dbusCall);
-    if (responseMsg.is_method_error())
-    {
-        log<level::ERR>("Error in mboxd resume call");
-        elog<InternalFailure>();
-    }
-}
-
 } // namespace updater
 } // namespace software
 } // namespace openpower
diff --git a/item_updater.hpp b/item_updater.hpp
index 1dc0868..96ef29c 100644
--- a/item_updater.hpp
+++ b/item_updater.hpp
@@ -89,14 +89,10 @@
                      std::bind(std::mem_fn(&ItemUpdater::createActivation),
                                this, std::placeholders::_1))
     {
-        processPNORImage();
-        gardReset = std::make_unique<GardReset>(bus, GARD_PATH);
-        volatileEnable = std::make_unique<ObjectEnable>(bus, volatilePath);
-
-        // Emit deferred signal.
-        emit_object_added();
     }
 
+    virtual ~ItemUpdater() = default;
+
     /** @brief Sets the given priority free by incrementing
      *  any existing priority with the same value by 1
      *
@@ -105,7 +101,7 @@
      *                         are trying to free up the priority.
      *  @return None
      */
-    void freePriority(uint8_t value, const std::string& versionId);
+    virtual void freePriority(uint8_t value, const std::string& versionId) = 0;
 
     /** @brief Determine is the given priority is the lowest
      *
@@ -114,25 +110,25 @@
      *  @return boolean corresponding to whether the given
      *           priority is lowest.
      */
-    bool isLowestPriority(uint8_t value);
+    virtual bool isLowestPriority(uint8_t value) = 0;
 
     /**
      * @brief Create and populate the active PNOR Version.
      */
-    void processPNORImage();
+    virtual void processPNORImage() = 0;
 
     /** @brief Deletes version
      *
      *  @param[in] entryId - Id of the version to delete
      *
-     *  @return None
+     *  @return - Returns true if the version is deleted.
      */
-    void erase(std::string entryId);
+    virtual bool erase(std::string entryId);
 
     /**
      * @brief Erases any non-active pnor versions.
      */
-    void deleteAll();
+    virtual void deleteAll() = 0;
 
     /** @brief Brings the total number of active PNOR versions to
      *         ACTIVE_PNOR_MAX_ALLOWED -1. This function is intended to be
@@ -141,7 +137,7 @@
      *         version(s) with the highest priority, skipping the
      *         functional PNOR version.
      */
-    void freeSpace();
+    virtual void freeSpace() = 0;
 
     /** @brief Determine the software version id
      *         from the symlink target (e.g. /media/ro-2a1022fe).
@@ -156,20 +152,20 @@
      *
      * @param[in]  path - The path to create the association to.
      */
-    void createActiveAssociation(const std::string& path);
+    virtual void createActiveAssociation(const std::string& path);
 
     /** @brief Updates the functional association to the
      *  new "running" PNOR image
      *
-     * @param[in]  path - The path to update the association to.
+     * @param[in]  versionId - The id of the image to update the association to.
      */
-    void updateFunctionalAssociation(const std::string& path);
+    virtual void updateFunctionalAssociation(const std::string& versionId);
 
     /** @brief Removes the associations from the provided software image path
      *
      * @param[in]  path - The path to remove the association from.
      */
-    void removeAssociation(const std::string& path);
+    virtual void removeAssociation(const std::string& path);
 
     /** @brief Persistent GardReset dbus object */
     std::unique_ptr<GardReset> gardReset;
@@ -180,27 +176,18 @@
      *
      * @return - Returns true if this version is currently functional.
      */
-    static bool isVersionFunctional(const std::string& versionId);
+    virtual bool isVersionFunctional(const std::string& versionId) = 0;
 
     /** @brief Persistent ObjectEnable D-Bus object */
     std::unique_ptr<ObjectEnable> volatileEnable;
 
-  private:
+  protected:
     /** @brief Callback function for Software.Version match.
      *  @details Creates an Activation D-Bus object.
      *
      * @param[in]  msg       - Data associated with subscribed signal
      */
-    void createActivation(sdbusplus::message::message& msg);
-
-    /**
-     * @brief Validates the presence of SquashFS image in the image dir.
-     *
-     * @param[in]  filePath - The path to the SquashFS image.
-     * @param[out] result    - 0 --> if validation was successful
-     *                       - -1--> Otherwise
-     */
-    static int validateSquashFSImage(const std::string& filePath);
+    virtual void createActivation(sdbusplus::message::message& msg) = 0;
 
     /** @brief Persistent sdbusplus D-Bus bus connection. */
     sdbusplus::bus::bus& bus;
@@ -219,26 +206,9 @@
     /** @brief This entry's associations */
     AssociationList assocs = {};
 
-    /** @brief Clears read only PNOR partition for
-     *  given Activation D-Bus object
-     *
-     * @param[in]  versionId - The id of the ro partition to remove.
-     */
-    void removeReadOnlyPartition(std::string versionId);
-
-    /** @brief Clears read write PNOR partition for
-     *  given Activation D-Bus object
-     *
-     *  @param[in]  versionId - The id of the rw partition to remove.
-     */
-    void removeReadWritePartition(std::string versionId);
-
-    /** @brief Clears preserved PNOR partition */
-    void removePreservedPartition();
-
     /** @brief Host factory reset - clears PNOR partitions for each
      * Activation D-Bus object */
-    void reset() override;
+    void reset() override = 0;
 
     /** @brief Check whether the host is running
      *
diff --git a/item_updater_main.cpp b/item_updater_main.cpp
index d773142..d0d7554 100644
--- a/item_updater_main.cpp
+++ b/item_updater_main.cpp
@@ -1,6 +1,8 @@
 #include "config.h"
 
-#include "item_updater.hpp"
+#ifdef UBIFS_LAYOUT
+#include "ubi/item_updater_ubi.hpp"
+#endif
 #include "watch.hpp"
 
 #include <phosphor-logging/log.hpp>
@@ -26,7 +28,9 @@
     // Add sdbusplus ObjectManager.
     sdbusplus::server::manager::manager objManager(bus, SOFTWARE_OBJPATH);
 
-    ItemUpdater updater(bus, SOFTWARE_OBJPATH);
+#ifdef UBIFS_LAYOUT
+    ItemUpdaterUbi updater(bus, SOFTWARE_OBJPATH);
+#endif
 
     bus.request_name(BUSNAME_UPDATER);
     try
diff --git a/static/Makefile.am.include b/static/Makefile.am.include
new file mode 100644
index 0000000..73f96e3
--- /dev/null
+++ b/static/Makefile.am.include
@@ -0,0 +1,2 @@
+openpower_update_manager_SOURCES += \
+	%reldir%/item_updater.cpp
diff --git a/ubi/Makefile.am.include b/ubi/Makefile.am.include
new file mode 100644
index 0000000..fba30d9
--- /dev/null
+++ b/ubi/Makefile.am.include
@@ -0,0 +1,2 @@
+openpower_update_manager_SOURCES += \
+	%reldir%/item_updater_ubi.cpp
diff --git a/ubi/item_updater_ubi.cpp b/ubi/item_updater_ubi.cpp
new file mode 100644
index 0000000..1c2926a
--- /dev/null
+++ b/ubi/item_updater_ubi.cpp
@@ -0,0 +1,553 @@
+#include "config.h"
+
+#include "item_updater_ubi.hpp"
+
+#include "activation.hpp"
+#include "serialize.hpp"
+#include "version.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <experimental/filesystem>
+#include <fstream>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <queue>
+#include <string>
+#include <xyz/openbmc_project/Software/Version/server.hpp>
+
+namespace openpower
+{
+namespace software
+{
+namespace updater
+{
+
+// When you see server:: you know we're referencing our base class
+namespace server = sdbusplus::xyz::openbmc_project::Software::server;
+namespace fs = std::experimental::filesystem;
+
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using namespace phosphor::logging;
+
+constexpr auto squashFSImage = "pnor.xz.squashfs";
+
+// TODO: Change paths once openbmc/openbmc#1663 is completed.
+constexpr auto MBOXD_INTERFACE = "org.openbmc.mboxd";
+constexpr auto MBOXD_PATH = "/org/openbmc/mboxd";
+
+void ItemUpdaterUbi::createActivation(sdbusplus::message::message& m)
+{
+    using SVersion = server::Version;
+    using VersionPurpose = SVersion::VersionPurpose;
+    namespace msg = sdbusplus::message;
+    namespace variant_ns = msg::variant_ns;
+
+    sdbusplus::message::object_path objPath;
+    std::map<std::string, std::map<std::string, msg::variant<std::string>>>
+        interfaces;
+    m.read(objPath, interfaces);
+
+    std::string path(std::move(objPath));
+    std::string filePath;
+    auto purpose = VersionPurpose::Unknown;
+    std::string version;
+
+    for (const auto& intf : interfaces)
+    {
+        if (intf.first == VERSION_IFACE)
+        {
+            for (const auto& property : intf.second)
+            {
+                if (property.first == "Purpose")
+                {
+                    // Only process the Host and System images
+                    auto value = SVersion::convertVersionPurposeFromString(
+                        variant_ns::get<std::string>(property.second));
+
+                    if (value == VersionPurpose::Host ||
+                        value == VersionPurpose::System)
+                    {
+                        purpose = value;
+                    }
+                }
+                else if (property.first == "Version")
+                {
+                    version = variant_ns::get<std::string>(property.second);
+                }
+            }
+        }
+        else if (intf.first == FILEPATH_IFACE)
+        {
+            for (const auto& property : intf.second)
+            {
+                if (property.first == "Path")
+                {
+                    filePath = variant_ns::get<std::string>(property.second);
+                }
+            }
+        }
+    }
+    if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
+    {
+        return;
+    }
+
+    // Version id is the last item in the path
+    auto pos = path.rfind("/");
+    if (pos == std::string::npos)
+    {
+        log<level::ERR>("No version id found in object path",
+                        entry("OBJPATH=%s", path.c_str()));
+        return;
+    }
+
+    auto versionId = path.substr(pos + 1);
+
+    if (activations.find(versionId) == activations.end())
+    {
+        // Determine the Activation state by processing the given image dir.
+        auto activationState = server::Activation::Activations::Invalid;
+        AssociationList associations = {};
+        if (validateSquashFSImage(filePath) == 0)
+        {
+            activationState = server::Activation::Activations::Ready;
+            // Create an association to the host inventory item
+            associations.emplace_back(std::make_tuple(
+                ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
+                HOST_INVENTORY_PATH));
+        }
+
+        fs::path manifestPath(filePath);
+        manifestPath /= MANIFEST_FILE;
+        std::string extendedVersion =
+            (Version::getValue(
+                 manifestPath.string(),
+                 std::map<std::string, std::string>{{"extended_version", ""}}))
+                .begin()
+                ->second;
+
+        activations.insert(std::make_pair(
+            versionId, std::make_unique<Activation>(
+                           bus, path, *this, versionId, extendedVersion,
+                           activationState, associations)));
+
+        auto versionPtr = std::make_unique<Version>(
+            bus, path, *this, versionId, version, purpose, filePath,
+            std::bind(&ItemUpdaterUbi::erase, this, std::placeholders::_1));
+        versionPtr->deleteObject =
+            std::make_unique<Delete>(bus, path, *versionPtr);
+        versions.insert(std::make_pair(versionId, std::move(versionPtr)));
+    }
+    return;
+}
+
+void ItemUpdaterUbi::processPNORImage()
+{
+    // Read pnor.toc from folders under /media/
+    // to get Active Software Versions.
+    for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
+    {
+        auto activationState = server::Activation::Activations::Active;
+
+        static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
+        static const auto PNOR_RW_PREFIX_LEN = strlen(PNOR_RW_PREFIX);
+
+        // Check if the PNOR_RO_PREFIX is the prefix of the iter.path
+        if (0 ==
+            iter.path().native().compare(0, PNOR_RO_PREFIX_LEN, PNOR_RO_PREFIX))
+        {
+            // The versionId is extracted from the path
+            // for example /media/pnor-ro-2a1022fe.
+            auto id = iter.path().native().substr(PNOR_RO_PREFIX_LEN);
+            auto pnorTOC = iter.path() / PNOR_TOC_FILE;
+            if (!fs::is_regular_file(pnorTOC))
+            {
+                log<level::ERR>("Failed to read pnorTOC.",
+                                entry("FILENAME=%s", pnorTOC.c_str()));
+                ItemUpdaterUbi::erase(id);
+                continue;
+            }
+            auto keyValues = Version::getValue(
+                pnorTOC, {{"version", ""}, {"extended_version", ""}});
+            auto& version = keyValues.at("version");
+            if (version.empty())
+            {
+                log<level::ERR>("Failed to read version from pnorTOC",
+                                entry("FILENAME=%s", pnorTOC.c_str()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+
+            auto& extendedVersion = keyValues.at("extended_version");
+            if (extendedVersion.empty())
+            {
+                log<level::ERR>("Failed to read extendedVersion from pnorTOC",
+                                entry("FILENAME=%s", pnorTOC.c_str()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+
+            auto purpose = server::Version::VersionPurpose::Host;
+            auto path = fs::path(SOFTWARE_OBJPATH) / id;
+            AssociationList associations = {};
+
+            if (activationState == server::Activation::Activations::Active)
+            {
+                // Create an association to the host inventory item
+                associations.emplace_back(std::make_tuple(
+                    ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
+                    HOST_INVENTORY_PATH));
+
+                // Create an active association since this image is active
+                createActiveAssociation(path);
+            }
+
+            // Create Activation instance for this version.
+            activations.insert(
+                std::make_pair(id, std::make_unique<Activation>(
+                                       bus, path, *this, id, extendedVersion,
+                                       activationState, 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.c_str()));
+                }
+                activations.find(id)->second->redundancyPriority =
+                    std::make_unique<RedundancyPriority>(
+                        bus, path, *(activations.find(id)->second), priority);
+            }
+
+            // Create Version instance for this version.
+            auto versionPtr = std::make_unique<Version>(
+                bus, path, *this, id, version, purpose, "",
+                std::bind(&ItemUpdaterUbi::erase, this, std::placeholders::_1));
+            versionPtr->deleteObject =
+                std::make_unique<Delete>(bus, path, *versionPtr);
+            versions.insert(std::make_pair(id, std::move(versionPtr)));
+        }
+        else if (0 == iter.path().native().compare(0, PNOR_RW_PREFIX_LEN,
+                                                   PNOR_RW_PREFIX))
+        {
+            auto id = iter.path().native().substr(PNOR_RW_PREFIX_LEN);
+            auto roDir = PNOR_RO_PREFIX + id;
+            if (!fs::is_directory(roDir))
+            {
+                log<level::ERR>("No corresponding read-only volume found.",
+                                entry("DIRNAME=%s", roDir.c_str()));
+                ItemUpdaterUbi::erase(id);
+            }
+        }
+    }
+
+    // Look at the RO symlink to determine if there is a functional image
+    auto id = determineId(PNOR_RO_ACTIVE_PATH);
+    if (!id.empty())
+    {
+        updateFunctionalAssociation(id);
+    }
+    return;
+}
+
+int ItemUpdaterUbi::validateSquashFSImage(const std::string& filePath)
+{
+    auto file = fs::path(filePath) / squashFSImage;
+    if (fs::is_regular_file(file))
+    {
+        return 0;
+    }
+    else
+    {
+        log<level::ERR>("Failed to find the SquashFS image.");
+        return -1;
+    }
+}
+
+void ItemUpdaterUbi::removeReadOnlyPartition(std::string versionId)
+{
+    auto serviceFile = "obmc-flash-bios-ubiumount-ro@" + versionId + ".service";
+
+    // Remove the read-only partitions.
+    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+                                      SYSTEMD_INTERFACE, "StartUnit");
+    method.append(serviceFile, "replace");
+    bus.call_noreply(method);
+}
+
+void ItemUpdaterUbi::removeReadWritePartition(std::string versionId)
+{
+    auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + versionId + ".service";
+
+    // Remove the read-write partitions.
+    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+                                      SYSTEMD_INTERFACE, "StartUnit");
+    method.append(serviceFile, "replace");
+    bus.call_noreply(method);
+}
+
+void ItemUpdaterUbi::reset()
+{
+    std::vector<uint8_t> mboxdArgs;
+
+    // Suspend mboxd - no args required.
+    auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
+                                        MBOXD_INTERFACE, "cmd");
+
+    dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
+
+    auto responseMsg = bus.call(dbusCall);
+    if (responseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mboxd suspend call");
+        elog<InternalFailure>();
+    }
+
+    constexpr static auto patchDir = "/usr/local/share/pnor";
+    if (fs::is_directory(patchDir))
+    {
+        for (const auto& iter : fs::directory_iterator(patchDir))
+        {
+            fs::remove_all(iter);
+        }
+    }
+
+    // Clear the read-write partitions.
+    for (const auto& it : activations)
+    {
+        auto rwDir = PNOR_RW_PREFIX + it.first;
+        if (fs::is_directory(rwDir))
+        {
+            for (const auto& iter : fs::directory_iterator(rwDir))
+            {
+                fs::remove_all(iter);
+            }
+        }
+    }
+
+    // Clear the preserved partition.
+    if (fs::is_directory(PNOR_PRSV))
+    {
+        for (const auto& iter : fs::directory_iterator(PNOR_PRSV))
+        {
+            fs::remove_all(iter);
+        }
+    }
+
+    // Resume mboxd with arg 1, indicating that the flash was modified.
+    dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
+                                   "cmd");
+
+    mboxdArgs.push_back(1);
+    dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
+
+    responseMsg = bus.call(dbusCall);
+    if (responseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mboxd resume call");
+        elog<InternalFailure>();
+    }
+
+    return;
+}
+
+bool ItemUpdaterUbi::isVersionFunctional(const std::string& versionId)
+{
+    if (!fs::exists(PNOR_RO_ACTIVE_PATH))
+    {
+        return false;
+    }
+
+    fs::path activeRO = fs::read_symlink(PNOR_RO_ACTIVE_PATH);
+
+    if (!fs::is_directory(activeRO))
+    {
+        return false;
+    }
+
+    if (activeRO.string().find(versionId) == std::string::npos)
+    {
+        return false;
+    }
+
+    // active PNOR is the version we're checking
+    return true;
+}
+
+void ItemUpdaterUbi::freePriority(uint8_t value, const std::string& versionId)
+{
+    // TODO openbmc/openbmc#1896 Improve the performance of this function
+    for (const auto& intf : activations)
+    {
+        if (intf.second->redundancyPriority)
+        {
+            if (intf.second->redundancyPriority.get()->priority() == value &&
+                intf.second->versionId != versionId)
+            {
+                intf.second->redundancyPriority.get()->priority(value + 1);
+            }
+        }
+    }
+}
+
+bool ItemUpdaterUbi::isLowestPriority(uint8_t value)
+{
+    for (const auto& intf : activations)
+    {
+        if (intf.second->redundancyPriority)
+        {
+            if (intf.second->redundancyPriority.get()->priority() < value)
+            {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool ItemUpdaterUbi::erase(std::string entryId)
+{
+    if (!ItemUpdater::erase(entryId))
+    {
+        return false;
+    }
+
+    // Remove priority persistence file
+    removeFile(entryId);
+
+    // Removing read-only and read-write partitions
+    removeReadWritePartition(entryId);
+    removeReadOnlyPartition(entryId);
+
+    return true;
+}
+
+void ItemUpdaterUbi::deleteAll()
+{
+    auto chassisOn = isChassisOn();
+
+    for (const auto& activationIt : activations)
+    {
+        if (isVersionFunctional(activationIt.first) && chassisOn)
+        {
+            continue;
+        }
+        else
+        {
+            ItemUpdaterUbi::erase(activationIt.first);
+        }
+    }
+
+    // Remove any remaining pnor-ro- or pnor-rw- volumes that do not match
+    // the current version.
+    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+                                      SYSTEMD_INTERFACE, "StartUnit");
+    method.append("obmc-flash-bios-cleanup.service", "replace");
+    bus.call_noreply(method);
+}
+
+// TODO: openbmc/openbmc#1402 Monitor flash usage
+void ItemUpdaterUbi::freeSpace()
+{
+    //  Versions with the highest priority in front
+    std::priority_queue<std::pair<int, std::string>,
+                        std::vector<std::pair<int, std::string>>,
+                        std::less<std::pair<int, std::string>>>
+        versionsPQ;
+
+    std::size_t count = 0;
+    for (const auto& iter : activations)
+    {
+        if (iter.second.get()->activation() ==
+            server::Activation::Activations::Active)
+        {
+            count++;
+            // Don't put the functional version on the queue since we can't
+            // remove the "running" PNOR version if it allows multiple PNORs
+            // But removing functional version if there is only one PNOR.
+            if (ACTIVE_PNOR_MAX_ALLOWED > 1 &&
+                isVersionFunctional(iter.second->versionId))
+            {
+                continue;
+            }
+            versionsPQ.push(std::make_pair(
+                iter.second->redundancyPriority.get()->priority(),
+                iter.second->versionId));
+        }
+    }
+
+    // If the number of PNOR versions is over ACTIVE_PNOR_MAX_ALLOWED -1,
+    // remove the highest priority one(s).
+    while ((count >= ACTIVE_PNOR_MAX_ALLOWED) && (!versionsPQ.empty()))
+    {
+        erase(versionsPQ.top().second);
+        versionsPQ.pop();
+        count--;
+    }
+}
+
+std::string ItemUpdater::determineId(const std::string& symlinkPath)
+{
+    if (!fs::exists(symlinkPath))
+    {
+        return {};
+    }
+
+    auto target = fs::canonical(symlinkPath).string();
+
+    // check to make sure the target really exists
+    if (!fs::is_regular_file(target + "/" + PNOR_TOC_FILE))
+    {
+        return {};
+    }
+    // Get the image <id> from the symlink target
+    // for example /media/ro-2a1022fe
+    static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
+    return target.substr(PNOR_RO_PREFIX_LEN);
+}
+
+void GardReset::reset()
+{
+    // The GARD partition is currently misspelled "GUARD." This file path will
+    // need to be updated in the future.
+    auto path = fs::path(PNOR_PRSV_ACTIVE_PATH);
+    path /= "GUARD";
+    std::vector<uint8_t> mboxdArgs;
+
+    auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
+                                        MBOXD_INTERFACE, "cmd");
+
+    // Suspend mboxd - no args required.
+    dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
+
+    auto responseMsg = bus.call(dbusCall);
+    if (responseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mboxd suspend call");
+        elog<InternalFailure>();
+    }
+
+    if (fs::is_regular_file(path))
+    {
+        fs::remove(path);
+    }
+
+    dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
+                                   "cmd");
+
+    // Resume mboxd with arg 1, indicating that the flash is modified.
+    mboxdArgs.push_back(1);
+    dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
+
+    responseMsg = bus.call(dbusCall);
+    if (responseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mboxd resume call");
+        elog<InternalFailure>();
+    }
+}
+
+} // namespace updater
+} // namespace software
+} // namespace openpower
diff --git a/ubi/item_updater_ubi.hpp b/ubi/item_updater_ubi.hpp
new file mode 100644
index 0000000..af330a8
--- /dev/null
+++ b/ubi/item_updater_ubi.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "item_updater.hpp"
+
+namespace openpower
+{
+namespace software
+{
+namespace updater
+{
+
+/** @class ItemUpdaterUbi
+ *  @brief Manages the activation of the host version items for ubi layout
+ */
+class ItemUpdaterUbi : public ItemUpdater
+{
+  public:
+    ItemUpdaterUbi(sdbusplus::bus::bus& bus, const std::string& path) :
+        ItemUpdater(bus, path)
+    {
+        processPNORImage();
+        gardReset = std::make_unique<GardReset>(bus, GARD_PATH);
+        volatileEnable = std::make_unique<ObjectEnable>(bus, volatilePath);
+
+        // Emit deferred signal.
+        emit_object_added();
+    }
+    virtual ~ItemUpdaterUbi() = default;
+
+    void freePriority(uint8_t value, const std::string& versionId) override;
+
+    bool isLowestPriority(uint8_t value) override;
+
+    void processPNORImage() override;
+
+    bool erase(std::string entryId) override;
+
+    void deleteAll() override;
+
+    void freeSpace() override;
+
+    bool isVersionFunctional(const std::string& versionId) override;
+
+  private:
+    /** @brief Callback function for Software.Version match.
+     *  @details Creates an Activation D-Bus object.
+     *
+     * @param[in]  msg       - Data associated with subscribed signal
+     */
+    void createActivation(sdbusplus::message::message& msg) override;
+
+    /** @brief Host factory reset - clears PNOR partitions for each
+     * Activation D-Bus object */
+    void reset() override;
+
+    /**
+     * @brief Validates the presence of SquashFS image in the image dir.
+     *
+     * @param[in]  filePath - The path to the SquashFS image.
+     * @param[out] result    - 0 --> if validation was successful
+     *                       - -1--> Otherwise
+     */
+    static int validateSquashFSImage(const std::string& filePath);
+
+    /** @brief Clears read only PNOR partition for
+     *  given Activation D-Bus object
+     *
+     * @param[in]  versionId - The id of the ro partition to remove.
+     */
+    void removeReadOnlyPartition(std::string versionId);
+
+    /** @brief Clears read write PNOR partition for
+     *  given Activation D-Bus object
+     *
+     *  @param[in]  versionId - The id of the rw partition to remove.
+     */
+    void removeReadWritePartition(std::string versionId);
+
+    /** @brief Clears preserved PNOR partition */
+    void removePreservedPartition();
+};
+
+} // namespace updater
+} // namespace software
+} // namespace openpower
diff --git a/watch.cpp b/watch.cpp
index 35cbb15..192d3d9 100644
--- a/watch.cpp
+++ b/watch.cpp
@@ -26,7 +26,7 @@
 namespace fs = std::experimental::filesystem;
 
 Watch::Watch(sd_event* loop,
-             std::function<void(std::string&)> functionalCallback) :
+             std::function<void(const std::string&)> functionalCallback) :
     functionalCallback(functionalCallback),
     fd(inotifyInit())
 
@@ -94,9 +94,7 @@
         if (fs::equivalent(path, PNOR_RO_ACTIVE_PATH))
         {
             auto id = ItemUpdater::determineId(path);
-            auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
-
-            static_cast<Watch*>(userdata)->functionalCallback(objPath);
+            static_cast<Watch*>(userdata)->functionalCallback(id);
         }
         offset += offsetof(inotify_event, name) + event->len;
     }
diff --git a/watch.hpp b/watch.hpp
index f7ae6af..a04967e 100644
--- a/watch.hpp
+++ b/watch.hpp
@@ -80,7 +80,8 @@
      *  @param[in] functionalCallback - The callback function for updating
      *                                  the functional associations.
      */
-    Watch(sd_event* loop, std::function<void(std::string&)> functionalCallback);
+    Watch(sd_event* loop,
+          std::function<void(const std::string&)> functionalCallback);
 
     Watch(const Watch&) = delete;
     Watch& operator=(const Watch&) = delete;