// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_CROSTINI_CROSTINI_UPGRADER_H_
#define CHROME_BROWSER_ASH_CROSTINI_CROSTINI_UPGRADER_H_
#include <optional>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/browser/ash/crostini/crostini_export_import.h"
#include "chrome/browser/ash/crostini/crostini_export_import_status_tracker.h"
#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/crostini/crostini_upgrader_ui_delegate.h"
#include "chrome/browser/ash/guest_os/guest_id.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "components/keyed_service/core/keyed_service.h"
class Profile;
namespace crostini {
class CrostiniUpgrader : public KeyedService,
public UpgradeContainerProgressObserver,
public chromeos::PowerManagerClient::Observer,
public CrostiniUpgraderUIDelegate {
public:
static CrostiniUpgrader* GetForProfile(Profile* profile);
explicit CrostiniUpgrader(Profile* profile);
CrostiniUpgrader(const CrostiniUpgrader&) = delete;
CrostiniUpgrader& operator=(const CrostiniUpgrader&) = delete;
~CrostiniUpgrader() override;
// KeyedService:
void Shutdown() override;
// CrostiniUpgraderUIDelegate:
void AddObserver(CrostiniUpgraderUIObserver* observer) override;
void RemoveObserver(CrostiniUpgraderUIObserver* observer) override;
void PageOpened() override;
void Backup(const guest_os::GuestId& container_id,
bool show_file_chooser,
base::WeakPtr<content::WebContents> web_contents) override;
void StartPrechecks() override;
void Upgrade(const guest_os::GuestId& container_id) override;
void Restore(const guest_os::GuestId& container_id,
base::WeakPtr<content::WebContents> web_contents) override;
void Cancel() override;
void CancelBeforeStart() override;
// CrostiniManager::UpgradeContainerProgressObserver:
void OnUpgradeContainerProgress(
const guest_os::GuestId& container_id,
UpgradeContainerProgressStatus status,
const std::vector<std::string>& messages) override;
// chromeos::PowerManagerClient::Observer:
void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
// Return true if internal state allows starting upgrade.
bool CanUpgrade();
static void EnsureFactoryBuilt();
private:
void CreateNewLogFile();
// Write a vector of log messages to `current_log_file_` on the
// `log_sequence_`, which allows blocking operations.
void WriteLogMessages(std::vector<std::string> messages);
void OnBackupPathChecked(const guest_os::GuestId& container_id,
base::WeakPtr<content::WebContents> web_contents,
base::FilePath path,
bool path_exists);
// Called when backup completes. If backup was completed successfully (which
// is different from if |result|==SUCCESS) the |backup_path| will contain a
// path to the backup tarball.
void OnBackup(CrostiniResult result,
std::optional<base::FilePath> backup_path);
void OnCancel(CrostiniResult result);
void OnBackupProgress(int progress_percent);
void OnUpgrade(CrostiniResult result);
void DoPrechecks();
void OnRestorePathChecked(const guest_os::GuestId& container_id,
base::WeakPtr<content::WebContents> web_contents,
base::FilePath path,
bool path_exists);
void OnRestore(CrostiniResult result);
void OnRestoreProgress(int progress_percent);
CrostiniExportImport::OnceTrackerFactory MakeFactory();
class StatusTracker : public CrostiniExportImportStatusTracker {
public:
explicit StatusTracker(base::WeakPtr<CrostiniUpgrader> upgrader,
ExportImportType type,
base::FilePath path);
~StatusTracker() override;
// CrostiniExportImportStatusTracker:
void SetStatusRunningUI(int progress_percent) override;
void SetStatusCancellingUI() override {}
void SetStatusDoneUI() override;
void SetStatusCancelledUI() override;
void SetStatusFailedWithMessageUI(Status status,
const std::u16string& message) override;
private:
bool has_notified_start_ = false;
base::WeakPtr<CrostiniUpgrader> upgrader_;
};
friend class StatusTracker;
raw_ptr<Profile> profile_;
guest_os::GuestId container_id_;
base::ObserverList<CrostiniUpgraderUIObserver>::Unchecked upgrader_observers_;
base::OnceClosure prechecks_callback_;
bool power_status_good_ = false;
// A sequence for writing upgrade logs to the file system.
scoped_refptr<base::SequencedTaskRunner> log_sequence_;
// Path to the current log file. Generating the path is a blocking operation,
// so we set it to std::nullopt until we get a response.
std::optional<base::FilePath> current_log_file_;
// Buffer for storing log messages that arrive while the log file is being
// created.
std::vector<std::string> log_buffer_;
base::ScopedObservation<chromeos::PowerManagerClient,
chromeos::PowerManagerClient::Observer>
pmc_observation_{this};
// When restoring after a failed upgrade, if the user successfully completed a
// backup, we will auto-restore from that (if the file still exists),
// otherwise |backup_path_|==nullopt and restore will bring up a file-chooser.
std::optional<base::FilePath> backup_path_;
base::WeakPtrFactory<CrostiniUpgrader> weak_ptr_factory_{this};
};
} // namespace crostini
#endif // CHROME_BROWSER_ASH_CROSTINI_CROSTINI_UPGRADER_H_