blob: 5aa80ec1da229baf7f799bb2701a55e9250d98fe [file] [log] [blame]
#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 <sstream>
#include <tuple>
#include <unordered_map>
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;
class UpdateManager
{
public:
UpdateManager() = delete;
UpdateManager(const UpdateManager&) = delete;
UpdateManager(UpdateManager&&) = delete;
UpdateManager& operator=(const UpdateManager&) = delete;
UpdateManager& operator=(UpdateManager&&) = delete;
~UpdateManager() = default;
explicit UpdateManager(
Event& event,
pldm::requester::Handler<pldm::requester::Request>& handler,
InstanceIdDb& instanceIdDb, const DescriptorMap& descriptorMap,
const ComponentInfoMap& componentInfoMap) :
event(event), handler(handler), instanceIdDb(instanceIdDb),
descriptorMap(descriptorMap), componentInfoMap(componentInfoMap),
#ifdef FW_UPDATE_INOTIFY_ENABLED
watch(event.get(),
[this](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), compUpdateCompletedCount(0)
{}
/** @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
*/
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);
void updateActivationProgress();
/** @brief Callback function that will be invoked when the
* RequestedActivation will be set to active in the Activation
* interface
*/
void activatePackage();
void clearActivationInfo();
/** @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/"};
Event& event; //!< reference to PLDM daemon's main event loop
/** @brief PLDM request handler */
pldm::requester::Handler<pldm::requester::Request>& handler;
InstanceIdDb& instanceIdDb; //!< reference to an InstanceIdDb
std::unique_ptr<Activation> activation;
private:
/** @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;
/** @brief FW update package can contain updates for multiple firmware
* devices and each device can have multiple components. Once
* each component is updated (Transfer completed, Verified and
* Applied) ActivationProgress is updated.
*/
size_t compUpdateCompletedCount;
decltype(std::chrono::steady_clock::now()) startTime;
std::unique_ptr<sdeventplus::source::Defer> updateDeferHandler;
};
} // namespace fw_update
} // namespace pldm