watchdog: Collect hostboot dump when watchdog times out

The hostboot dump collection to be initiated by watchdog_timeout
is disabled by default. When watchdog times out, only error
message corresponding to watchdog timeout is logged. To enable
hostboot dump collection whenever watchdog times out, the meson
option 'hostboot-dump-collection' must be enabled.

Testing - with meson option 'hostboot-dump-collection' enabled:
Ran watchdog_timeout:
case-1: CurrentHostState - off, AutoReboot - false
- Verified PEL object was not created
- Verified hostboot dump was not created
- Verified the Host State changed to Quiesce

case-2: CurrentHostState - off, AutoReboot - true
- Verified PEL object was created
- Verified hostboot dump was not created
- Verified the Host State changed to Running

case-3: CurrentHostState - Running, AutoBoot - false
- Verified PEL object was not created
- Verified hostboot dump was not created
- Verified the Host State changed to Quiesce

case-4: CurrentHostState - Running, AutoBoot - true, default timeout = 300s
- Verified PEL object was created
- Verified hostboot dump was created
- Observed Host state moving to either Running or Quiesce

case-5: CurrentHostState - Running, AutoBoot - true, specified timeout = 5s
- Verified PEL object was created
- Verified hostboot dump was created
- Observed Host state moving to either Running or Quiesce

Docker Unit test: passed

Signed-off-by: Shantappa Teekappanavar <sbteeks@yahoo.com>
Change-Id: Ib92d0c2f282816fb742cf07c1cb876b2cc093c12
diff --git a/watchdog/watchdog_dbus.cpp b/watchdog/watchdog_dbus.cpp
new file mode 100644
index 0000000..6fe7563
--- /dev/null
+++ b/watchdog/watchdog_dbus.cpp
@@ -0,0 +1,134 @@
+#include <unistd.h>
+
+#include <phosphor-logging/log.hpp>
+#include <watchdog_dbus.hpp>
+#include <watchdog_logging.hpp>
+#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
+
+#include <string>
+#include <vector>
+
+namespace watchdog
+{
+namespace dump
+{
+
+using namespace phosphor::logging;
+
+int dbusMethod(const std::string& path, const std::string& interface,
+               const std::string& function, sdbusplus::message::message& method,
+               const std::string& extended)
+{
+    int rc = RC_DBUS_ERROR; // assume error
+
+    try
+    {
+        constexpr auto serviceFind = "xyz.openbmc_project.ObjectMapper";
+        constexpr auto pathFind = "/xyz/openbmc_project/object_mapper";
+        constexpr auto interfaceFind = "xyz.openbmc_project.ObjectMapper";
+        constexpr auto functionFind = "GetObject";
+
+        auto bus = sdbusplus::bus::new_system(); // using system dbus
+
+        // method to find service from object path and object interface
+        auto newMethod = bus.new_method_call(serviceFind, pathFind,
+                                             interfaceFind, functionFind);
+
+        // find the service for specified object path and interface
+        newMethod.append(path.c_str());
+        newMethod.append(std::vector<std::string>({interface}));
+        auto reply = bus.call(newMethod);
+
+        // dbus call results
+        std::map<std::string, std::vector<std::string>> responseFindService;
+        reply.read(responseFindService);
+
+        // If we successfully found the service associated with the dbus object
+        // path and interface then create a method for the specified interface
+        // and function.
+        if (!responseFindService.empty())
+        {
+            auto service = responseFindService.begin()->first;
+
+            // Some methods (e.g. get attribute) take an extended parameter
+            if (extended == "")
+            {
+                // return the method
+                method =
+                    bus.new_method_call(service.c_str(), path.c_str(),
+                                        interface.c_str(), function.c_str());
+            }
+            else
+            {
+                // return extended method
+                method =
+                    bus.new_method_call(service.c_str(), path.c_str(),
+                                        extended.c_str(), function.c_str());
+            }
+
+            rc = RC_SUCCESS;
+        }
+        else
+        {
+            // This trace will be picked up in event log
+            log<level::INFO>("dbusMethod service not found");
+            std::string traceMsgPath = std::string(path, maxTraceLen);
+            log<level::INFO>(traceMsgPath.c_str());
+            std::string traceMsgIface = std::string(interface, maxTraceLen);
+            log<level::INFO>(traceMsgIface.c_str());
+        }
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        log<level::ERR>("Error in dbusMethod", entry("ERROR=%s", e.what()));
+    }
+
+    return rc;
+}
+
+uint32_t createPel(const std::string& eventType,
+                   std::map<std::string, std::string>& additional,
+                   const std::vector<FFDCTuple>& ffdc)
+{
+    // Create returns plid
+    int plid = 0;
+
+    // Need to provide pid when using create or create-with-ffdc methods
+    additional.emplace("_PID", std::to_string(getpid()));
+
+    // Sdbus call specifics
+    constexpr auto interface = "org.open_power.Logging.PEL";
+    constexpr auto function = "CreatePELWithFFDCFiles";
+
+    sdbusplus::message::message method;
+
+    if (0 == dbusMethod(pathLogging, interface, function, method))
+    {
+        try
+        {
+            // append additional dbus call paramaters
+            method.append(eventType, levelPelError, additional, ffdc);
+
+            // using system dbus
+            auto bus = sdbusplus::bus::new_system();
+            auto response = bus.call(method);
+
+            // reply will be tuple containing bmc log id, platform log id
+            std::tuple<uint32_t, uint32_t> reply = {0, 0};
+
+            // parse dbus response into reply
+            response.read(reply);
+            plid = std::get<1>(reply); // platform log id is tuple "second"
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            log<level::ERR>("Error in createPel CreatePELWithFFDCFiles",
+                            entry("ERROR=%s", e.what()));
+        }
+    }
+
+    return plid; // platform log id or 0
+}
+
+} // namespace dump
+} // namespace watchdog