chromium/chrome/browser/ash/crostini/crostini_upgrader.h

// 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_