#ifndef CHROME_BROWSER_ASH_PLUGIN_VM_PLUGIN_VM_INSTALLER_H_
#define CHROME_BROWSER_ASH_PLUGIN_VM_PLUGIN_VM_INSTALLER_H_
#include <memory>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/guest_os/guest_os_dlc_helper.h"
#include "chrome/browser/ash/plugin_vm/plugin_vm_license_checker.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "chromeos/ash/components/dbus/vm_concierge/concierge_service.pb.h"
#include "components/download/public/background_service/download_params.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
namespace download {
class BackgroundDownloadService;
struct CompletionInfo;
}
class Profile;
namespace plugin_vm {
class PluginVmDriveImageDownloadService;
class PluginVmInstaller : public KeyedService,
public ash::ConciergeClient::DiskImageObserver {
public:
enum class FailureReason {
SIGNAL_NOT_CONNECTED = 1,
OPERATION_IN_PROGRESS = 2,
NOT_ALLOWED = 3,
INVALID_IMAGE_URL = 4,
UNEXPECTED_DISK_IMAGE_STATUS = 5,
INVALID_DISK_IMAGE_STATUS_RESPONSE = 6,
DOWNLOAD_FAILED_UNKNOWN = 7,
DOWNLOAD_FAILED_NETWORK = 8,
DOWNLOAD_FAILED_ABORTED = 9,
HASH_MISMATCH = 10,
DISPATCHER_NOT_AVAILABLE = 11,
CONCIERGE_NOT_AVAILABLE = 12,
COULD_NOT_OPEN_IMAGE = 13,
INVALID_IMPORT_RESPONSE = 14,
IMAGE_IMPORT_FAILED = 15,
DLC_INTERNAL = 18,
DLC_UNSUPPORTED = 19,
DLC_BUSY = 20,
DLC_NEED_REBOOT = 21,
DLC_NEED_SPACE = 22,
INSUFFICIENT_DISK_SPACE = 23,
INVALID_LICENSE = 24,
OFFLINE = 25,
LIST_VM_DISKS_FAILED = 26,
OUT_OF_DISK_SPACE = 27,
DOWNLOAD_FAILED_401 = 28,
DOWNLOAD_FAILED_403 = 29,
DOWNLOAD_FAILED_404 = 30,
DOWNLOAD_SIZE_MISMATCH = 31,
EXISTING_IMAGE_INVALID = 32,
kMaxValue = EXISTING_IMAGE_INVALID,
};
enum class InstallingState {
kInactive,
kCheckingLicense,
kCheckingForExistingVm,
kCheckingDiskSpace,
kDownloadingDlc,
kStartingDispatcher,
kDownloadingImage,
kImporting,
};
static constexpr int64_t kImageSizeUnknown = -1;
static constexpr int64_t kImageSizeError = -2;
class Observer {
public:
virtual ~Observer() = default;
virtual void OnStateUpdated(InstallingState new_state) = 0;
virtual void OnProgressUpdated(double fraction_complete) = 0;
virtual void OnDownloadProgressUpdated(uint64_t bytes_downloaded,
int64_t content_length) = 0;
virtual void OnVmExists() = 0;
virtual void OnCreated() = 0;
virtual void OnImported() = 0;
virtual void OnError(FailureReason reason) = 0;
virtual void OnCancelFinished() = 0;
};
explicit PluginVmInstaller(Profile* profile);
PluginVmInstaller(const PluginVmInstaller&) = delete;
PluginVmInstaller& operator=(const PluginVmInstaller&) = delete;
~PluginVmInstaller() override;
std::optional<FailureReason> Start();
void Cancel();
bool IsProcessing();
void SetObserver(Observer* observer);
void RemoveObserver();
std::string GetCurrentDownloadGuid();
void OnDownloadStarted();
void OnDownloadProgressUpdated(uint64_t bytes_downloaded,
int64_t content_length);
void OnDownloadCompleted(const download::CompletionInfo& info);
void OnDownloadFailed(FailureReason reason);
void OnDiskImageProgress(
const vm_tools::concierge::DiskImageStatusResponse& signal) override;
bool VerifyDownload(const std::string& download_hash);
int64_t RequiredFreeDiskSpace();
void SkipLicenseCheckForTesting() { skip_license_check_for_testing_ = true; }
void SetFreeDiskSpaceForTesting(int64_t bytes) {
free_disk_space_for_testing_ = bytes;
}
void SetDownloadServiceForTesting(
download::BackgroundDownloadService* download_service);
void SetDownloadedImageForTesting(const base::FilePath& downloaded_image);
void SetDriveDownloadServiceForTesting(
std::unique_ptr<PluginVmDriveImageDownloadService>
drive_download_service);
private:
enum class State {
kIdle,
kInstalling,
kCancelling,
};
void CheckLicense();
void OnLicenseChecked(bool license_is_valid);
void CheckForExistingVm();
void OnConciergeAvailable(bool success);
void OnListVmDisks(
std::optional<vm_tools::concierge::ListVmDisksResponse> response);
void CheckDiskSpace();
void OnAvailableDiskSpace(std::optional<int64_t> bytes);
void StartDlcDownload();
void OnDlcDownloadProgressUpdated(double progress);
void OnDlcDownloadCompleted(
guest_os::GuestOsDlcInstallation::Result install_result);
void StartDispatcher();
void OnDispatcherStarted(bool success);
void StartDownload();
void OnStartDownload(const std::string& download_guid,
download::DownloadParams::StartResult start_result);
void StartImport();
void OnImageTypeDetected(bool is_iso_image);
void OnFDPrepared(std::optional<base::ScopedFD> maybe_fd);
template <typename ReplyType>
void OnImportDiskImage(std::optional<ReplyType> reply);
void RequestFinalStatus();
void OnFinalDiskImageStatus(
std::optional<vm_tools::concierge::DiskImageStatusResponse> response);
void OnImported(std::optional<FailureReason> failure_reason);
void UpdateInstallingState(InstallingState installing_state);
void UpdateProgress(double state_progress);
void InstallFailed(FailureReason reason);
void InstallFinished();
void CancelDownload();
void CancelImport();
void OnImportDiskImageCancelled(
std::optional<vm_tools::concierge::SuccessFailureResponse> response);
void CancelFinished();
static std::string GetStateName(State state);
static std::string GetInstallingStateName(InstallingState state);
GURL GetPluginVmImageDownloadUrl();
download::DownloadParams GetDownloadParams(const GURL& url);
void RemoveTemporaryImageIfExists();
void OnTemporaryImageRemoved(bool success);
device::mojom::WakeLock* GetWakeLock();
raw_ptr<Profile> profile_ = nullptr;
raw_ptr<Observer, DanglingUntriaged> observer_ = nullptr;
raw_ptr<download::BackgroundDownloadService, DanglingUntriaged>
download_service_ = nullptr;
State state_ = State::kIdle;
InstallingState installing_state_ = InstallingState::kInactive;
std::string current_download_guid_;
base::FilePath downloaded_image_;
std::string current_import_command_uuid_;
int64_t expected_image_size_;
int64_t downloaded_image_size_;
bool creating_new_vm_ = false;
double progress_ = 0;
std::unique_ptr<PluginVmDriveImageDownloadService> drive_download_service_;
std::unique_ptr<PluginVmLicenseChecker> license_checker_;
std::unique_ptr<guest_os::GuestOsDlcInstallation> dlc_installation_;
bool using_drive_download_service_ = false;
bool skip_license_check_for_testing_ = false;
int64_t free_disk_space_for_testing_ = -1;
std::optional<base::FilePath> downloaded_image_for_testing_;
mojo::Remote<device::mojom::WakeLock> wake_lock_;
base::WeakPtrFactory<PluginVmInstaller> weak_ptr_factory_{this};
};
}
#endif