usb: Update the RequestedActivation property
Subscribe to the add software interface, when an update is detected,
call back the updateActivation method and verify whether it needs
to be updated. If necessary:
1. Set ApplyTime to OnReset to prevent the bmc from restarting
immediately after the update.
2. Change the RequestedActivation attribute value and start to update
the image bmc.
Tested: Manually start the phopshor-usb-manager daemon, and saw that
the bmc upgrade file(*.tar) has been copied to /tmp/images and
the update has been triggered, and bmc has not been restarted
immediately.
Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: Ic650e34f8ec61d3c826332d28275db90f9ef348e
diff --git a/subprojects/sdeventplus.wrap b/subprojects/sdeventplus.wrap
new file mode 100644
index 0000000..085bb5e
--- /dev/null
+++ b/subprojects/sdeventplus.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/openbmc/sdeventplus.git
+revision = HEAD
diff --git a/usb/meson.build b/usb/meson.build
index 9ac5876..bc4462a 100644
--- a/usb/meson.build
+++ b/usb/meson.build
@@ -13,6 +13,14 @@
'../utils.cpp',
]
+sdeventplus_dep = dependency(
+ 'sdeventplus',
+ fallback: [
+ 'sdeventplus',
+ 'sdeventplus_dep'
+ ],
+)
+
phosphor_logging_dep = dependency(
'phosphor-logging',
fallback: ['phosphor-logging', 'phosphor_logging_dep'],
@@ -26,6 +34,7 @@
CLI11_dep,
phosphor_logging_dep,
sdbusplus_dep,
+ sdeventplus_dep,
],
install: true,
install_dir: get_option('bindir')
diff --git a/usb/usb_manager.cpp b/usb/usb_manager.cpp
index b002dbd..ed831dd 100644
--- a/usb/usb_manager.cpp
+++ b/usb/usb_manager.cpp
@@ -46,5 +46,79 @@
return false;
}
+void USBManager::setApplyTime()
+{
+ utils::PropertyValue value =
+ "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
+ constexpr auto objectPath = "/xyz/openbmc_project/software/apply_time";
+ constexpr auto interface = "xyz.openbmc_project.Software.ApplyTime";
+ constexpr auto propertyName = "RequestedApplyTime";
+ try
+ {
+ utils::setProperty(bus, objectPath, interface, propertyName, value);
+ }
+ catch (const std::exception& e)
+ {
+ lg2::error("Failed to set RequestedApplyTime property, ERROR:{ERROR}",
+ "ERROR", e.what());
+ }
+}
+
+void USBManager::setRequestedActivation(const std::string& path)
+{
+ utils::PropertyValue value =
+ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active";
+ constexpr auto interface = "xyz.openbmc_project.Software.Activation";
+ constexpr auto propertyName = "RequestedActivation";
+ try
+ {
+ utils::setProperty(bus, path, interface, propertyName, value);
+ }
+ catch (const std::exception& e)
+ {
+ lg2::error("Failed to set RequestedActivation property, ERROR:{ERROR}",
+ "ERROR", e.what());
+ }
+
+ return;
+}
+
+void USBManager::updateActivation(sdbusplus::message::message& msg)
+{
+ std::map<std::string, std::map<std::string, std::variant<std::string>>>
+ interfaces;
+ sdbusplus::message::object_path path;
+ msg.read(path, interfaces);
+
+ constexpr auto imageInterface = "xyz.openbmc_project.Software.Activation";
+ constexpr auto readyPro =
+ "xyz.openbmc_project.Software.Activation.Activations.Ready";
+ for (auto& interface : interfaces)
+ {
+ if (interface.first != imageInterface)
+ {
+ continue;
+ }
+
+ try
+ {
+ auto propVal =
+ utils::getProperty(bus, path.str, imageInterface, "Activation");
+ const auto& imageProp = std::get<std::string>(propVal);
+ if (imageProp == readyPro && isUSBCodeUpdate)
+ {
+ setApplyTime();
+ setRequestedActivation(path.str);
+ event.exit(0);
+ }
+ }
+ catch (const std::exception& e)
+ {
+ lg2::error("Failed in getting Activation status, ERROR:{ERROR}",
+ "ERROR", e.what());
+ }
+ }
+}
+
} // namespace usb
-} // namespace phosphor
\ No newline at end of file
+} // namespace phosphor
diff --git a/usb/usb_manager.hpp b/usb/usb_manager.hpp
index f3323a8..e67115c 100644
--- a/usb/usb_manager.hpp
+++ b/usb/usb_manager.hpp
@@ -1,6 +1,9 @@
#pragma once
+#include "utils.hpp"
+
#include <phosphor-logging/lg2.hpp>
+#include <sdeventplus/event.hpp>
#include <filesystem>
@@ -9,6 +12,7 @@
namespace usb
{
namespace fs = std::filesystem;
+namespace MatchRules = sdbusplus::bus::match::rules;
class USBManager
{
@@ -20,8 +24,25 @@
USBManager& operator=(const USBManager&) = delete;
USBManager& operator=(USBManager&&) = default;
- explicit USBManager(const fs::path& path) : usbPath(path)
- {}
+ explicit USBManager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
+ const fs::path& path) :
+ bus(bus),
+ event(event), usbPath(path), isUSBCodeUpdate(false),
+ fwUpdateMatcher(bus,
+ MatchRules::interfacesAdded() +
+ MatchRules::path("/xyz/openbmc_project/software"),
+ std::bind(std::mem_fn(&USBManager::updateActivation),
+ this, std::placeholders::_1))
+ {
+ if (!run())
+ {
+ lg2::error("Failed to FW Update via USB, usbPath:{USBPATH}",
+ "USBPATH", usbPath);
+ event.exit(0);
+ }
+
+ isUSBCodeUpdate = true;
+ }
/** @brief Find the first file with a .tar extension according to the USB
* file path.
@@ -30,9 +51,38 @@
*/
bool run();
+ /** @brief Creates an Activation D-Bus object.
+ *
+ * @param[in] msg - Data associated with subscribed signal
+ */
+ void updateActivation(sdbusplus::message::message& msg);
+
+ /** @brief Set Apply Time to OnReset.
+ *
+ */
+ void setApplyTime();
+
+ /** @brief Method to set the RequestedActivation D-Bus property.
+ *
+ * @param[in] path - Update the object path of the firmware
+ */
+ void setRequestedActivation(const std::string& path);
+
private:
+ /** @brief Persistent sdbusplus DBus bus connection. */
+ sdbusplus::bus::bus& bus;
+
+ /** sd event handler. */
+ sdeventplus::Event& event;
+
/** The USB path detected. */
const fs::path& usbPath;
+
+ /** Indicates whether USB codeupdate is going on. */
+ bool isUSBCodeUpdate;
+
+ /** sdbusplus signal match for new image. */
+ sdbusplus::bus::match_t fwUpdateMatcher;
};
} // namespace usb
diff --git a/usb/usb_manager_main.cpp b/usb/usb_manager_main.cpp
index 143125d..1f3ac81 100644
--- a/usb/usb_manager_main.cpp
+++ b/usb/usb_manager_main.cpp
@@ -2,10 +2,16 @@
#include <CLI/CLI.hpp>
#include <phosphor-logging/lg2.hpp>
+#include <sdeventplus/event.hpp>
int main(int argc, char** argv)
{
namespace fs = std::filesystem;
+ // Dbus constructs
+ auto bus = sdbusplus::bus::new_default();
+
+ // Get a default event loop
+ auto event = sdeventplus::Event::get_default();
std::string fileName{};
@@ -22,14 +28,11 @@
}
fs::path usbPath = fs::path{"/run/media/usb"} / fileName;
- phosphor::usb::USBManager manager(usbPath);
+ phosphor::usb::USBManager manager(bus, event, usbPath);
- if (!manager.run())
- {
- lg2::error("Failed to FW Update via USB, usbPath:{USBPATH}", "USBPATH",
- usbPath);
- return -1;
- }
+ // Attach the bus to sd_event to service user requests
+ bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+ event.loop();
return 0;
}