fw_update: Introduce AggregateUpdateManager

Description:
This commit introduces the `AggregateUpdateManager` class for handling
multiple firmware update sessions simultaneously. The
`AggregateUpdateManager` acts as a reverse proxy for PLDM messages,
routing them to the appropriate `UpdateManager` instance based on the
`instanceId`. This allows for concurrent firmware updates, improving
the efficiency and flexibility of the firmware update process.

Motivation:
We have introduced the `FirmwareInventory`/`FirmwareInventoryManager`
classes to manage D-Bus interfaces for firmware update, After that, we
would like to implement the `StartUpdate` method for `FirmwareInventory`
properly for the update process implementation[1], which
`AggregateUpdateManager` will help route the command to the specific
update sessions.

Details of the PLDM message reverse proxy:
By the implementation, different update session would be handled with
different `instanceId`s, which can help `UpdateManager`s to identify
whether the message is for them or not.
Whenever a PLDM response message is received, the flow that
the `AggregateUpdateManager` do:
 1. Handle the message for existing update flow if the instance_id
    (the pldm instance numbers) matches the update task which using the
    existing update flow.
 2. Traverse forward the message to each `ItemUpdateManager`
    (implementation in the next patch) instances if there's no match in
    step 1.
 3. Return error message PLDM_FWUP_COMMAND_NOT_EXPECTED if no matches in
    step 2.

[1]: https://gerrit.openbmc.org/c/openbmc/pldm/+/74774

Change-Id: Icfdb8d238121f9f44a624396e00b378e491ce652
Signed-off-by: Unive Tien <unive.tien.wiwynn@gmail.com>
diff --git a/fw-update/aggregate_update_manager.cpp b/fw-update/aggregate_update_manager.cpp
new file mode 100644
index 0000000..c27db95
--- /dev/null
+++ b/fw-update/aggregate_update_manager.cpp
@@ -0,0 +1,54 @@
+#include "aggregate_update_manager.hpp"
+
+namespace pldm::fw_update
+{
+
+Response AggregateUpdateManager::handleRequest(
+    mctp_eid_t eid, uint8_t command, const pldm_msg* request, size_t reqMsgLen)
+{
+    Response response;
+    response = UpdateManager::handleRequest(eid, command, request, reqMsgLen);
+    auto responseMsg = new (response.data()) pldm_msg;
+    if (responseMsg->payload[0] != PLDM_FWUP_COMMAND_NOT_EXPECTED)
+    {
+        return response;
+    }
+    for (auto& [_, updateManager] : updateManagers)
+    {
+        response =
+            updateManager->handleRequest(eid, command, request, reqMsgLen);
+        if (responseMsg->payload[0] != PLDM_FWUP_COMMAND_NOT_EXPECTED)
+        {
+            return response;
+        }
+    }
+    return response;
+}
+
+void AggregateUpdateManager::eraseUpdateManager(
+    const SoftwareIdentifier& softwareIdentifier)
+{
+    updateManagers.erase(softwareIdentifier);
+    descriptorMap.erase(softwareIdentifier);
+    componentInfoMap.erase(softwareIdentifier);
+}
+
+void AggregateUpdateManager::eraseUpdateManagerIf(
+    std::function<bool(const SoftwareIdentifier&)>&& predicate)
+{
+    for (auto it = updateManagers.begin(); it != updateManagers.end();)
+    {
+        if (predicate(it->first))
+        {
+            descriptorMap.erase(it->first);
+            componentInfoMap.erase(it->first);
+            it = updateManagers.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
+}
+
+} // namespace pldm::fw_update