blob: 883b254c4fb634fada730ed63e05f0e0073a48cf [file]
#pragma once
#include "common/instance_id.hpp"
#include "common/types.hpp"
#include "device_updater.hpp"
#include "fw-update/activation.hpp"
#include "fw-update/update.hpp"
#ifdef FW_UPDATE_INOTIFY_ENABLED
#include "fw-update/watch.hpp"
#endif
#include "package_parser.hpp"
#include "requester/handler.hpp"
#include <libpldm/base.h>
#include <sdbusplus/async.hpp>
#include <sdbusplus/server/object.hpp>
#include <xyz/openbmc_project/Software/Activation/server.hpp>
#include <chrono>
#include <filesystem>
#include <fstream>
#include <functional>
#include <unordered_map>
#include <utility>
namespace pldm
{
namespace fw_update
{
using namespace sdeventplus;
using namespace sdeventplus::source;
using namespace pldm;
using DeviceIDRecordOffset = size_t;
using DeviceUpdaterInfo = std::pair<mctp_eid_t, DeviceIDRecordOffset>;
using DeviceUpdaterInfos = std::vector<DeviceUpdaterInfo>;
using TotalComponentUpdates = size_t;
/**
* @brief The base class of the UpdateManager and the
* ItemBaseUpdateManager
*/
class UpdateManagerBase
{
public:
virtual ~UpdateManagerBase() = default;
UpdateManagerBase() = delete;
UpdateManagerBase(const UpdateManagerBase&) = delete;
UpdateManagerBase(UpdateManagerBase&&) = delete;
UpdateManagerBase& operator=(const UpdateManagerBase&) = delete;
UpdateManagerBase& operator=(UpdateManagerBase&&) = delete;
/** @brief Constructor
*
* @param[in] event - PLDM daemon's main event loop
* @param[in] handler - PLDM request handler
* @param[in] instanceIdDb - Managing instance ID for PLDM requests
*/
UpdateManagerBase(
Event& event,
pldm::requester::Handler<pldm::requester::Request>& handler,
InstanceIdDb& instanceIdDb) :
event(event), handler(handler), instanceIdDb(instanceIdDb)
{}
virtual void updateDeviceCompletion(mctp_eid_t eid, bool status) = 0;
virtual void updateActivationProgress() = 0;
virtual void activatePackage() = 0;
virtual void resetActivationState() = 0;
Event& event; //!< reference to PLDM daemon's main event loop
pldm::requester::Handler<pldm::requester::Request>& handler;
InstanceIdDb& instanceIdDb; //!< reference to an InstanceIdDb
};
class UpdateManager : public UpdateManagerBase
{
public:
UpdateManager() = delete;
UpdateManager(const UpdateManager&) = delete;
UpdateManager(UpdateManager&&) = delete;
UpdateManager& operator=(const UpdateManager&) = delete;
UpdateManager& operator=(UpdateManager&&) = delete;
virtual ~UpdateManager() = default;
explicit UpdateManager(
Event& event,
pldm::requester::Handler<pldm::requester::Request>& handler,
InstanceIdDb& instanceIdDb, const DescriptorMap& descriptorMap,
const ComponentInfoMap& componentInfoMap,
const ConditionPaths& conditionPathPair = ConditionPaths{},
const std::string& conditionArg = std::string{},
std::function<void()> taskCompletionCallback = nullptr) :
UpdateManagerBase(event, handler, instanceIdDb),
descriptorMap(descriptorMap), componentInfoMap(componentInfoMap),
#ifdef FW_UPDATE_INOTIFY_ENABLED
watch(event.get(),
[this](const std::string& packageFilePath) {
return this->processPackage(
std::filesystem::path(packageFilePath));
}),
#else
updater(std::make_unique<Update>(pldm::utils::DBusHandler::getBus(),
"/xyz/openbmc_project/software/pldm",
this)),
#endif
totalNumComponentUpdates(0), preConditionPath(conditionPathPair.first),
postConditionPath(conditionPathPair.second), conditionArg(conditionArg),
taskCompletionCallback(std::move(taskCompletionCallback))
{}
/** @brief Handle PLDM request for the commands in the FW update
* specification
*
* @param[in] eid - Remote MCTP Endpoint ID
* @param[in] command - PLDM command code
* @param[in] request - PLDM request message
* @param[in] requestLen - PLDM request message length
*
* @return PLDM response message
*/
virtual Response handleRequest(mctp_eid_t eid, uint8_t command,
const pldm_msg* request, size_t reqMsgLen);
int processPackage(const std::filesystem::path& packageFilePath);
/** @brief Process the firmware update package
*
* @param[in] packageStream - Stream of the firmware update package
* @param[in] packageSize - Size of the firmware update package
*
* @return Object path of the created Software object
*/
void processStream(std::istream& packageStream, uintmax_t packageSize);
/** @brief Defers processing the package stream
*
* @param[in] packageStream - Stream of the firmware update package
* @param[in] packageSize - Size of the firmware update package
*
* @return Object path of the created Software object as a string
*/
std::string processStreamDefer(std::istream& packageStream,
uintmax_t packageSize);
void updateDeviceCompletion(mctp_eid_t eid, bool status) override;
void updateActivationProgress() override;
/** @brief Callback function that will be invoked when the
* RequestedActivation will be set to active in the Activation
* interface
*/
void activatePackage() override;
void resetActivationState() override;
/** @brief
*
*/
DeviceUpdaterInfos associatePkgToDevices(
const FirmwareDeviceIDRecords& fwDeviceIDRecords,
const DescriptorMap& descriptorMap,
TotalComponentUpdates& totalNumComponentUpdates);
/** @brief Generate a unique software ID based on current timestamp
*
* @return String representation of the current timestamp in seconds
*/
static std::string getSwId();
const std::string swRootPath{"/xyz/openbmc_project/software/"};
std::unique_ptr<Activation> activation;
private:
/** @brief Starts firmware activation for all associated devices.
*/
void startFirmwareUpdate();
/** @brief Completes the update flow and sets final activation state.
*
* @param[in] status - Overall update status, true on success
*/
void completeUpdate(bool status);
/** @brief Device identifiers of the managed FDs */
const DescriptorMap& descriptorMap;
/** @brief Component information needed for the update of the managed FDs */
const ComponentInfoMap& componentInfoMap;
#ifdef FW_UPDATE_INOTIFY_ENABLED
Watch watch;
#else
std::unique_ptr<Update> updater;
#endif
std::unique_ptr<ActivationProgress> activationProgress;
std::string objPath;
std::filesystem::path fwPackageFilePath;
std::unique_ptr<PackageParser> parser;
std::ifstream package;
std::unordered_map<mctp_eid_t, std::unique_ptr<DeviceUpdater>>
deviceUpdaterMap;
std::unordered_map<mctp_eid_t, bool> deviceUpdateCompletionMap;
/** @brief Total number of component updates to calculate the progress of
* the Firmware activation
*/
size_t totalNumComponentUpdates;
decltype(std::chrono::steady_clock::now()) startTime;
std::unique_ptr<sdeventplus::source::Defer> updateDeferHandler;
std::string preConditionPath;
std::string postConditionPath;
std::string conditionArg;
std::function<void()> taskCompletionCallback;
bool updateInProgress = false;
/** @brief The last progress that was calculated. Used to avoid spamming
* dbus
*
*/
uint8_t lastProgress;
};
} // namespace fw_update
} // namespace pldm