blob: 985785bd3864ced1ce485733079e8584e84e95b4 [file] [log] [blame] [edit]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modemfwd/flash_task.h"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <base/logging.h>
#include "modemfwd/logging.h"
#include "modemfwd/modem.h"
#include "modemfwd/modem_helper.h"
namespace modemfwd {
namespace {
class InhibitMode {
public:
explicit InhibitMode(Modem* modem) : modem_(modem) {
if (!modem_->SetInhibited(true))
ELOG(INFO) << "Inhibiting failed";
}
~InhibitMode() {
if (!modem_->SetInhibited(false))
ELOG(INFO) << "Uninhibiting failed";
}
private:
Modem* modem_;
};
uint32_t GetFirmwareTypesForMetrics(std::vector<FirmwareConfig> flash_cfg) {
uint32_t fw_types = 0;
if (flash_cfg.empty())
return 0;
for (const auto& info : flash_cfg) {
std::string fw_type = info.fw_type;
if (fw_type == kFwMain) {
fw_types |=
static_cast<int>(metrics::ModemFirmwareType::kModemFirmwareTypeMain);
} else if (fw_type == kFwOem) {
fw_types |=
static_cast<int>(metrics::ModemFirmwareType::kModemFirmwareTypeOem);
} else if (fw_type == kFwCarrier) {
fw_types |= static_cast<int>(
metrics::ModemFirmwareType::kModemFirmwareTypeCarrier);
} else if (fw_type == kFwAp) {
fw_types |=
static_cast<int>(metrics::ModemFirmwareType::kModemFirmwareTypeAp);
} else if (fw_type == kFwDev) {
fw_types |=
static_cast<int>(metrics::ModemFirmwareType::kModemFirmwareTypeDev);
} else {
fw_types |= static_cast<int>(
metrics::ModemFirmwareType::kModemFirmwareTypeUnknown);
}
}
ELOG(INFO) << "metrics_fw_types " << fw_types;
return fw_types;
}
} // namespace
FlashTask::FlashTask(Delegate* delegate,
Journal* journal,
NotificationManager* notification_mgr,
Metrics* metrics,
ModemFlasher* modem_flasher)
: delegate_(delegate),
journal_(journal),
notification_mgr_(notification_mgr),
metrics_(metrics),
modem_flasher_(modem_flasher) {}
bool FlashTask::Start(Modem* modem,
const FlashTask::Options& options,
brillo::ErrorPtr* err) {
if (!options.should_always_flash &&
!modem_flasher_->ShouldFlash(modem, err)) {
notification_mgr_->NotifyUpdateFirmwareCompletedFailure(err->get());
return false;
}
// Clear the attach APN if needed for a specific modem/carrier combination.
std::string carrier_id = modem->GetCarrierId();
if (!carrier_id.empty() && !modem->ClearAttachAPN(carrier_id)) {
ELOG(INFO) << "Clear attach APN failed for current carrier.";
}
std::unique_ptr<FlashConfig> flash_cfg = modem_flasher_->BuildFlashConfig(
modem, options.carrier_override_uuid, err);
if (!flash_cfg) {
notification_mgr_->NotifyUpdateFirmwareCompletedFailure(err->get());
return false;
}
// End early if we don't have any new firmware.
if (flash_cfg->fw_configs.empty()) {
// This message is used by tests to track the end of flashing.
LOG(INFO) << "The modem already has the correct firmware installed";
notification_mgr_->NotifyUpdateFirmwareCompletedSuccess(false, 0);
return true;
}
std::string device_id = modem->GetDeviceId();
InhibitMode _inhibit(modem);
std::vector<std::string> fw_types;
std::transform(flash_cfg->fw_configs.begin(), flash_cfg->fw_configs.end(),
std::back_inserter(fw_types),
[](const FirmwareConfig& cfg) { return cfg.fw_type; });
std::optional<std::string> entry_id = journal_->MarkStartOfFlashingFirmware(
fw_types, device_id, flash_cfg->carrier_id);
if (!entry_id.has_value()) {
LOG(WARNING) << "Couldn't write operation to journal";
}
uint32_t types_for_metrics =
GetFirmwareTypesForMetrics(flash_cfg->fw_configs);
base::TimeDelta flash_duration;
if (!modem_flasher_->RunFlash(modem, *flash_cfg, &flash_duration, err)) {
if (entry_id.has_value()) {
journal_->MarkEndOfFlashingFirmware(*entry_id);
}
notification_mgr_->NotifyUpdateFirmwareCompletedFlashFailure(
err->get(), types_for_metrics);
return false;
}
// Report flashing time in successful cases
metrics_->SendFwFlashTime(flash_duration);
delegate_->RegisterOnModemReappearanceCallback(
modem->GetEquipmentId(),
base::BindOnce(&FlashTask::FlashFinished, weak_ptr_factory_.GetWeakPtr(),
entry_id, types_for_metrics));
return true;
}
void FlashTask::FlashFinished(std::optional<std::string> journal_entry_id,
uint32_t fw_types) {
if (journal_entry_id.has_value()) {
journal_->MarkEndOfFlashingFirmware(*journal_entry_id);
}
notification_mgr_->NotifyUpdateFirmwareCompletedSuccess(true, fw_types);
}
} // namespace modemfwd