PHAL: add phal-export-devtree app

d-bus signal based watch app for software path interface add.

This implements methods for watching for software path
interface add signal and call appropriate function to
initiate phal devtree attribute data collection and save
to preserve partition.
Rules:
  - Watch for interfaces added for the software path
  - If interface added is “Activation”
  - if Activation property value is “Ready”
  - Then software update is going to start
  - Collect phal devtree required attribute list and
    save to pre-defined location

This commit enables the d-bus app only.

Tested : verified manually the signals by forcing
         code update.
Jul 30 14:27:35 xxx phal-export-devtree[2624]: Software path
                    interface add signal received

Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Change-Id: Ia1b7a87ef5a64e3c51c8dfa2d2e4ccef34a3e934
diff --git a/extensions/phal/devtree_export.cpp b/extensions/phal/devtree_export.cpp
new file mode 100644
index 0000000..922c341
--- /dev/null
+++ b/extensions/phal/devtree_export.cpp
@@ -0,0 +1,34 @@
+#include "fw_update_watch.hpp"
+
+#include <fmt/format.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <sdeventplus/event.hpp>
+
+int main()
+{
+    auto eventRet = 0;
+
+    try
+    {
+        auto bus = sdbusplus::bus::new_default();
+
+        auto event = sdeventplus::Event::get_default();
+
+        // create watch for interface added in software update.
+        openpower::phal::fwupdate::Watch eWatch(bus);
+
+        bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+
+        // Watch for software update
+        eventRet = event.loop();
+    }
+    catch (std::exception& e)
+    {
+        using namespace phosphor::logging;
+        log<level::ERR>(
+            fmt::format("Exception reported: [{}]", e.what()).c_str());
+    }
+
+    return eventRet;
+}
diff --git a/extensions/phal/fw_update_watch.cpp b/extensions/phal/fw_update_watch.cpp
new file mode 100644
index 0000000..a49cc9c
--- /dev/null
+++ b/extensions/phal/fw_update_watch.cpp
@@ -0,0 +1,87 @@
+#include "fw_update_watch.hpp"
+
+#include <fmt/format.h>
+
+#include <phosphor-logging/elog.hpp>
+#include <sdbusplus/exception.hpp>
+
+namespace openpower
+{
+namespace phal
+{
+namespace fwupdate
+{
+using namespace phosphor::logging;
+using Message = std::string;
+using Attributes = std::variant<Message>;
+using PropertyName = std::string;
+using PropertyMap = std::map<PropertyName, Attributes>;
+using InterfaceName = std::string;
+using InterfaceMap = std::map<InterfaceName, PropertyMap>;
+
+void Watch::fwIntfAddedCallback(sdbusplus::message::message& msg)
+{
+    //  DBusInterfaceAdded interfaces;
+    sdbusplus::message::object_path objectPath;
+    InterfaceMap interfaceMap;
+
+    try
+    {
+        msg.read(objectPath, interfaceMap);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        log<level::ERR>(fmt::format("Failed to parse software add signal"
+                                    "Exception [{}] REPLY_SIG [{}]",
+                                    e.what(), msg.get_signature())
+                            .c_str());
+        return;
+    }
+
+    auto iter = interfaceMap.find("xyz.openbmc_project.Software.Activation");
+    if (iter == interfaceMap.end())
+    {
+        // Skip not related Software Activation
+        return;
+    }
+
+    auto attr = iter->second.find("Activation");
+    if (attr == iter->second.end())
+    {
+        // Skip not related to Activation property.
+        return;
+    }
+
+    auto& imageProperty = std::get<InterfaceName>(attr->second);
+    if (imageProperty.empty())
+    {
+        // Skip, no image property
+        return;
+    }
+
+    if (imageProperty ==
+            "xyz.openbmc_project.Software.Activation.Activations.Ready" &&
+        !isSoftwareUpdateInProgress())
+    {
+        log<level::INFO>("Software path interface add signal received");
+
+        // Set status to code update in progress.
+        // Interface added signal triggered multiple times in code update path,
+        // it's due to additional interfaces added by the software manager app
+        // after the version interface is created.
+        // Device tree data collection is required only for the first trigger
+        setSoftwareUpdateProgress(true);
+
+        // Colect device tree data
+        openpower::phal::fwupdate::exportDevtree();
+    }
+
+    return;
+}
+
+void exportDevtree()
+{}
+
+} // namespace fwupdate
+} // namespace phal
+} // namespace openpower
diff --git a/extensions/phal/fw_update_watch.hpp b/extensions/phal/fw_update_watch.hpp
new file mode 100644
index 0000000..615e10c
--- /dev/null
+++ b/extensions/phal/fw_update_watch.hpp
@@ -0,0 +1,92 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
+
+namespace openpower
+{
+namespace phal
+{
+namespace fwupdate
+{
+
+static constexpr auto OBJ_SOFTWARE = "/xyz/openbmc_project/software";
+
+/** @class Watch
+ *  @brief Adds d-bus signal based watch for software path interface add.
+ *  @details This implements methods for watching for software path
+ *  interface add signal and call appropriate function to initiate phal
+ *  devtree attribute data collection and save to preserve partition.
+ *  Rules:
+ *   - Watch for interfaces added for the software path
+ *   - If interface added is “Activation”
+ *   - if Activation property value is “Ready”
+ *   - Then software update is going to start
+ *   - Collect phal devtree required attribute list and save to
+ *     pre-defined location
+ *
+ */
+class Watch
+{
+  public:
+    Watch() = delete;
+    ~Watch() = default;
+    Watch(const Watch&) = delete;
+    Watch& operator=(const Watch&) = delete;
+    Watch(Watch&&) = default;
+    Watch& operator=(Watch&&) = default;
+
+    /** @brief constructs watch for interface add signals.
+     *  @param[in] bus -  The Dbus bus object
+     */
+
+    Watch(sdbusplus::bus::bus& bus) :
+        addMatch(bus,
+                 sdbusplus::bus::match::rules::interfacesAdded() +
+                     sdbusplus::bus::match::rules::path(OBJ_SOFTWARE),
+                 std::bind(std::mem_fn(&Watch::fwIntfAddedCallback), this,
+                           std::placeholders::_1))
+    {}
+
+  private:
+    /** @brief Method to check whether software update is in progress
+     *  @return - bool
+     */
+    bool isSoftwareUpdateInProgress() const
+    {
+        return softwareUpdateInProgress;
+    }
+
+    /** @brief Method to indicate whether software update is in progress
+     *
+     *  @param[in] progress
+     *
+     */
+    void setSoftwareUpdateProgress(bool progress)
+    {
+        softwareUpdateInProgress = progress;
+    }
+
+    /** @brief Callback function for software path add signal.
+     *  @details Function provide required data related to new
+     *  software path interface added to see software update progress.
+     *
+     *  @param[in] msg  - Data associated with subscribed signal
+     */
+    void fwIntfAddedCallback(sdbusplus::message::message& msg);
+
+    /** @brief sdbusplus signal match for software path add */
+    sdbusplus::bus::match_t addMatch;
+
+    /** @brief indicates whether software update is going on */
+    bool softwareUpdateInProgress = false;
+};
+
+/** @brief function to export phal devtree data file based
+ * on the filter file,
+ */
+void exportDevtree();
+
+} // namespace fwupdate
+} // namespace phal
+} // namespace openpower
diff --git a/meson.build b/meson.build
index b16f045..c1ff741 100644
--- a/meson.build
+++ b/meson.build
@@ -127,6 +127,23 @@
    install: true
 )
 
+if build_phal
+    executable(
+        'phal-export-devtree',
+        [
+            'extensions/phal/devtree_export.cpp',
+            'extensions/phal/fw_update_watch.cpp',
+        ],
+        dependencies: [
+            dependency('phosphor-logging'),
+            dependency('sdbusplus'),
+            dependency('sdeventplus'),
+            dependency('fmt'),
+       ],
+       install: true
+   )
+endif
+
 unit_files = [
     'service_files/pcie-poweroff@.service',
     'service_files/xyz.openbmc_project.Control.Host.NMI.service',