blob: 00bfbb35e1f9dde608a367bdca20af5d873217cb [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modemfwd/modem_flasher.h"
#include <memory>
#include <utility>
#include <base/stl_util.h>
#include "modemfwd/firmware_file.h"
#include "modemfwd/modem.h"
namespace modemfwd {
ModemFlasher::ModemFlasher(
std::unique_ptr<FirmwareDirectory> firmware_directory,
std::unique_ptr<Journal> journal)
: firmware_directory_(std::move(firmware_directory)),
journal_(std::move(journal)) {}
base::Closure ModemFlasher::TryFlash(Modem* modem) {
std::string equipment_id = modem->GetEquipmentId();
FlashState* flash_state = &modem_info_[equipment_id];
if (!flash_state->ShouldFlash()) {
LOG(WARNING) << "Modem with equipment ID \"" << equipment_id
<< "\" failed to flash too many times; not flashing";
return base::Closure();
}
std::string device_id = modem->GetDeviceId();
FirmwareFileInfo file_info;
// Check if we need to update the main firmware.
if (flash_state->ShouldFlashMainFirmware() &&
firmware_directory_->FindMainFirmware(device_id, &file_info)) {
DLOG(INFO) << "Found main firmware blob " << file_info.version
<< ", currently installed main firmware version: "
<< modem->GetMainFirmwareVersion();
if (file_info.version == modem->GetMainFirmwareVersion()) {
// We don't need to check the main firmware again if there's nothing new.
// Pretend that we successfully flashed it.
flash_state->OnFlashedMainFirmware();
} else {
FirmwareFile firmware_file;
if (!firmware_file.PrepareFrom(file_info))
return base::Closure();
// We found different firmware! Flash the modem, and since it will
// reboot afterwards, we can wait to get called again to check the
// carrier firmware.
journal_->MarkStartOfFlashingMainFirmware(device_id);
if (modem->FlashMainFirmware(firmware_file.path_on_filesystem())) {
// Refer to |firmware_file.path_for_logging()| in the log and journal.
flash_state->OnFlashedMainFirmware();
DLOG(INFO) << "Flashed " << firmware_file.path_for_logging().value()
<< " to the modem";
return base::Bind(&Journal::MarkEndOfFlashingMainFirmware,
base::Unretained(journal_.get()), device_id);
} else {
flash_state->OnFlashFailed();
journal_->MarkEndOfFlashingMainFirmware(device_id);
return base::Closure();
}
}
}
// If there's no SIM, we can stop here.
std::string current_carrier = modem->GetCarrierId();
if (current_carrier.empty()) {
DLOG(INFO) << "No carrier found. Is a SIM card inserted?";
return base::Closure();
}
// Check if we have carrier firmware matching the SIM's carrier. If not,
// there's nothing to flash.
if (!firmware_directory_->FindCarrierFirmware(device_id, &current_carrier,
&file_info)) {
DLOG(INFO) << "No carrier firmware found for carrier " << current_carrier;
return base::Closure();
}
if (!flash_state->ShouldFlashCarrierFirmware(file_info.firmware_path)) {
DLOG(INFO) << "Already flashed carrier firmware for " << current_carrier;
return base::Closure();
}
DLOG(INFO) << "Found carrier firmware blob " << file_info.version
<< " for carrier " << current_carrier;
// Carrier firmware operates a bit differently. We need to flash if
// the carrier or the version has changed, or if there wasn't any carrier
// firmware to begin with.
std::string carrier_fw_id = modem->GetCarrierFirmwareId();
std::string carrier_fw_version = modem->GetCarrierFirmwareVersion();
bool has_carrier_fw = !(carrier_fw_id.empty() || carrier_fw_version.empty());
if (has_carrier_fw) {
DLOG(INFO) << "Currently installed carrier firmware version "
<< carrier_fw_version << " for carrier " << carrier_fw_id;
} else {
DLOG(INFO) << "No carrier firmware is currently installed";
}
if (!has_carrier_fw || carrier_fw_id != current_carrier ||
carrier_fw_version != file_info.version) {
FirmwareFile firmware_file;
if (!firmware_file.PrepareFrom(file_info))
return base::Closure();
journal_->MarkStartOfFlashingCarrierFirmware(device_id, current_carrier);
if (modem->FlashCarrierFirmware(firmware_file.path_on_filesystem())) {
// Refer to |firmware_file.path_for_logging()| in the log and journal.
flash_state->OnFlashedCarrierFirmware(firmware_file.path_for_logging());
DLOG(INFO) << "Flashed " << firmware_file.path_for_logging().value()
<< " to the modem";
return base::Bind(&Journal::MarkEndOfFlashingCarrierFirmware,
base::Unretained(journal_.get()), device_id,
current_carrier);
} else {
flash_state->OnFlashFailed();
journal_->MarkEndOfFlashingCarrierFirmware(device_id, current_carrier);
return base::Closure();
}
}
return base::Closure();
}
} // namespace modemfwd