#ifndef CHROMEOS_ASH_COMPONENTS_FWUPD_FIRMWARE_UPDATE_MANAGER_H_
#define CHROMEOS_ASH_COMPONENTS_FWUPD_FIRMWARE_UPDATE_MANAGER_H_
#include <optional>
#include <string>
#include "ash/webui/firmware_update_ui/mojom/firmware_update.mojom.h"
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/task/sequenced_task_runner.h"
#include "chromeos/ash/components/dbus/fwupd/fwupd_client.h"
#include "chromeos/ash/components/dbus/fwupd/fwupd_device.h"
#include "chromeos/ash/components/dbus/fwupd/fwupd_properties.h"
#include "chromeos/ash/components/dbus/fwupd/fwupd_request.h"
#include "chromeos/ash/components/dbus/fwupd/fwupd_update.h"
#include "chromeos/ash/components/network/network_state_handler_observer.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote_set.h"
namespace network {
class SimpleURLLoader;
}
namespace ash {
enum class FwupdStatus {
kUnknown,
kIdle,
kLoading,
kDecompressing,
kDeviceRestart,
kDeviceWrite,
kDeviceVerify,
kScheduling,
kDownloading,
kDeviceRead,
kDeviceErase,
kWaitingForAuth,
kDeviceBusy,
kShutdown,
kWaitingForUser,
kMaxValue = kWaitingForUser,
};
enum class MethodResult {
kSuccess = 0,
kFailedToCreateUpdateDirectory = 2,
kInvalidFile = 4,
kFailedToDownloadToFile = 5,
kFailedToCreatePatchFile = 6,
kEmptyPatchFile = 7,
kInvalidPatchFileUri = 8,
kInvalidPatchFile = 9,
kInstallFailedTimeout = 10,
kFailedToGetFirmwareFilename = 11,
kUnknownDeviceId = 12,
kInternalError = 100,
kVersionNewerError = 101,
kVersionSameError = 102,
kAlreadyPendingError = 103,
kAuthFailedError = 104,
kReadError = 105,
kWriteError = 106,
kInvalidFileError = 107,
kNotFoundError = 108,
kNothingToDoError = 109,
kNotSupportedError = 110,
kSignatureInvalidError = 111,
kAcPowerRequiredError = 112,
kPermissionDeniedError = 113,
kBrokenSystemError = 114,
kBatteryLevelTooLowError = 115,
kNeedsUserActionError = 116,
kAuthExpiredError = 117,
kUnknownError = 118,
kMaxValue = kUnknownError,
};
class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_FWUPD) FirmwareUpdateManager
: public FwupdClient::Observer,
public firmware_update::mojom::UpdateProvider,
public firmware_update::mojom::InstallController,
public firmware_update::mojom::SystemUtils,
public NetworkStateHandlerObserver {
public:
enum class Source {
kUI = 0,
kStartup = 1,
kUSBChange = 2,
kInstallComplete = 3,
kNetworkChange = 4,
kMaxValue = kNetworkChange,
};
FirmwareUpdateManager();
FirmwareUpdateManager(const FirmwareUpdateManager&) = delete;
FirmwareUpdateManager& operator=(const FirmwareUpdateManager&) = delete;
~FirmwareUpdateManager() override;
class Observer : public base::CheckedObserver {
public:
~Observer() override = default;
virtual void OnFirmwareUpdateReceived() = 0;
};
static bool IsInitialized();
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
void ObservePeripheralUpdates(
mojo::PendingRemote<firmware_update::mojom::UpdateObserver> observer)
override;
void PrepareForUpdate(const std::string& device_id,
PrepareForUpdateCallback callback) override;
void FetchInProgressUpdate(FetchInProgressUpdateCallback callback) override;
void BeginUpdate(const std::string& device_id,
const base::FilePath& filepath) override;
void AddDeviceRequestObserver(
mojo::PendingRemote<firmware_update::mojom::DeviceRequestObserver>
observer) override;
void AddUpdateProgressObserver(
mojo::PendingRemote<firmware_update::mojom::UpdateProgressObserver>
observer) override;
static FirmwareUpdateManager* Get();
size_t GetUpdateCount() { return updates_.size(); }
void OnDeviceListResponse(FwupdDeviceList* devices) override;
void OnDeviceRequestResponse(FwupdRequest request) override;
void OnUpdateListResponse(const std::string& device_id,
FwupdUpdateList* updates) override;
void OnPropertiesChangedResponse(FwupdProperties* properties) override;
void RequestAllUpdates(Source source);
void DefaultNetworkChanged(const NetworkState* network) override;
void BindInterface(
mojo::PendingReceiver<firmware_update::mojom::UpdateProvider>
pending_receiver);
void set_should_show_notification_for_test(bool show_notification) {
should_show_notification_for_test_ = show_notification;
}
void set_refresh_remote_for_testing(bool for_testing) {
refresh_remote_for_testing_ = for_testing;
}
void Restart() override;
void BindInterface(mojo::PendingReceiver<firmware_update::mojom::SystemUtils>
pending_receiver);
protected:
friend class FirmwareUpdateManagerTest;
int on_device_list_response_count_for_testing_ = 0;
int on_update_list_response_count_for_testing_ = 0;
private:
friend class FirmwareUpdateManagerTest;
void RequestDevices();
void RequestUpdates(const std::string& device_id);
typedef base::OnceCallback<void(MethodResult)> MethodCallback;
void StartInstall(const std::string& device_id,
const base::FilePath& filepath,
MethodCallback callback);
void OnGetFile(const std::string& device_id,
FirmwareInstallOptions options,
MethodCallback callback,
base::File file);
void InstallUpdate(const std::string& device_id,
FirmwareInstallOptions options,
MethodCallback callback,
base::File patch_file);
void OnInstallResponse(MethodCallback callback, FwupdDbusResult result);
void InstallComplete(MethodResult result);
void CreateLocalPatchFile(const base::FilePath& cache_path,
const std::string& device_id,
const base::FilePath& filepath,
MethodCallback callback,
bool create_dir_success);
void MaybeDownloadFileToInternal(const base::FilePath& patch_path,
const std::string& device_id,
const base::FilePath& filepath,
MethodCallback callback,
bool write_file_success);
void DownloadFileToInternal(const base::FilePath& patch_path,
const std::string& device_id,
const base::FilePath& filepath,
MethodCallback callback);
void OnUrlDownloadedToFile(
const std::string& device_id,
std::unique_ptr<network::SimpleURLLoader> simple_loader,
MethodCallback callback,
base::FilePath download_path);
void MaybeRefreshRemote(bool refresh_allowed);
using DownloadCompleteCallback =
base::OnceCallback<void(base::FilePath, base::File)>;
void RefreshRemote();
void CreateTempFileAndDownload(base::FilePath local_file,
std::string download_filename,
DownloadCompleteCallback callback,
bool create_dir_success);
void DownloadLvfsMirrorFile(std::string filename,
base::FilePath download_filepath,
DownloadCompleteCallback callback,
bool write_file_success);
void GetFileDescriptor(
std::unique_ptr<network::SimpleURLLoader> simple_loader,
DownloadCompleteCallback callback,
base::FilePath download_path);
void OnGetChecksumFile(base::FilePath checksum_filepath,
base::File checksum_file);
void GetFirmwareFilename(std::string file_contents);
void TriggerDownloadOfFirmwareFile(std::string firmware_filename);
void UpdateMetadata(base::FilePath firmware_filepath,
base::File firmware_file);
void OnUpdateMetadataResponse(FwupdDbusResult result);
void RefreshRemoteComplete(MethodResult result);
void NotifyUpdateListObservers();
bool HasPendingUpdates();
void set_fake_url_for_testing(const std::string& fake_url) {
fake_url_for_testing_ = fake_url;
}
void ResetInstallState();
void ShowNotificationIfRequired();
void NotifyCriticalFirmwareUpdateReceived();
void RecordDeviceMetrics(int num_devices);
void RecordUpdateMetrics();
int GetNumCriticalUpdates();
const base::FilePath GetCacheDirPath();
base::flat_map<std::string, FwupdDevice> devices_pending_update_;
base::flat_set<std::string> devices_already_notified_;
std::vector<firmware_update::mojom::FirmwareUpdatePtr> updates_;
std::string fake_url_for_testing_;
firmware_update::mojom::FirmwareUpdatePtr inflight_update_;
FwupdStatus last_fwupd_status_ = FwupdStatus::kUnknown;
firmware_update::mojom::DeviceRequestPtr last_device_request_ = nullptr;
std::optional<base::Time> last_request_started_timestamp_;
bool is_first_response_ = true;
bool is_fetching_updates_ = false;
bool is_refresh_pending_ = false;
base::FilePath checksum_filepath_;
base::FilePath firmware_filepath_;
base::File checksum_file_;
base::File firmware_file_;
bool should_show_notification_for_test_ = false;
bool refresh_remote_for_testing_ = false;
mojo::RemoteSet<firmware_update::mojom::UpdateObserver>
update_list_observers_;
mojo::Remote<firmware_update::mojom::DeviceRequestObserver>
device_request_observer_;
mojo::Remote<firmware_update::mojom::UpdateProgressObserver>
update_progress_observer_;
base::ObserverList<Observer> observer_list_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
mojo::Receiver<firmware_update::mojom::UpdateProvider> receiver_{this};
mojo::Receiver<firmware_update::mojom::InstallController>
install_controller_receiver_{this};
mojo::Receiver<firmware_update::mojom::SystemUtils> system_utils_receiver_{
this};
base::WeakPtrFactory<FirmwareUpdateManager> weak_ptr_factory_{this};
};
}
#endif