1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
// Copyright 2018 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_PACKAGE_SERVICE_H_
#define CHROME_BROWSER_ASH_CROSTINI_CROSTINI_PACKAGE_SERVICE_H_
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/crostini/crostini_package_notification.h"
#include "chrome/browser/ash/crostini/crostini_package_operation_status.h"
#include "chrome/browser/ash/crostini/crostini_util.h"
#include "chrome/browser/ash/guest_os/guest_os_registry_service.h"
#include "components/keyed_service/core/keyed_service.h"
#include "storage/browser/file_system/file_system_url.h"
namespace crostini {
class CrostiniPackageService : public KeyedService,
public LinuxPackageOperationProgressObserver,
public PendingAppListUpdatesObserver,
public ash::VmShutdownObserver {
public:
using StateChangeCallback =
base::RepeatingCallback<void(PackageOperationStatus)>;
explicit CrostiniPackageService(Profile* profile);
CrostiniPackageService(const CrostiniPackageService&) = delete;
CrostiniPackageService& operator=(const CrostiniPackageService&) = delete;
~CrostiniPackageService() override;
// For testing: Set a callback that will be called each time a notification
// is set to a new state.
void SetNotificationStateChangeCallbackForTesting(
StateChangeCallback state_change_callback);
// KeyedService:
void Shutdown() override;
void NotificationCompleted(CrostiniPackageNotification* notification);
void GetLinuxPackageInfo(
const guest_os::GuestId& container_id,
const storage::FileSystemURL& package_url,
CrostiniManager::GetLinuxPackageInfoCallback callback);
// LinuxPackageOperationProgressObserver:
void OnInstallLinuxPackageProgress(const guest_os::GuestId& container_id,
InstallLinuxPackageProgressStatus status,
int progress_percent,
const std::string& error_message) override;
void OnUninstallPackageProgress(const guest_os::GuestId& container_id,
UninstallPackageProgressStatus status,
int progress_percent) override;
// PendingAppListUpdatesObserver:
void OnPendingAppListUpdates(const guest_os::GuestId& container_id,
int count) override;
// ash::VmShutdownObserver
void OnVmShutdown(const std::string& vm_name) override;
// (Eventually) install a Linux package. If successfully started, a system
// notification will be used to display further updates.
void QueueInstallLinuxPackage(
const guest_os::GuestId& container_id,
const storage::FileSystemURL& package_url,
CrostiniManager::InstallLinuxPackageCallback callback);
// (Eventually) uninstall the package identified by |app_id|. If successfully
// started, a system notification will be used to display further updates.
void QueueUninstallApplication(const std::string& app_id);
CrostiniManager::RestartId GetRestartIdForTesting();
private:
// The user can request new operations while a different operation is in
// progress. Rather than sending a request which will fail, just queue the
// request until the previous one is done.
struct QueuedInstall;
struct QueuedUninstall;
bool ContainerHasRunningOperation(
const guest_os::GuestId& container_id) const;
bool ContainerHasQueuedOperation(const guest_os::GuestId& container_id) const;
// Creates a new notification and adds it to running_notifications_.
// |app_name| is the name of the application being modified, if any -- for
// installs, it will be blank, but for uninstalls, it will have the localized
// name of the application in UTF8.
// If there is a running notification, it will be set to error state. Caller
// should check before calling this if a different behavior is desired.
void CreateRunningNotification(
const guest_os::GuestId& container_id,
CrostiniPackageNotification::NotificationType notification_type,
const std::string& app_name);
// Creates a new uninstall notification and adds it to queued_uninstalls_.
void CreateQueuedUninstall(const guest_os::GuestId& container_id,
const std::string& app_id,
const std::string& app_name);
// Creates a new install notification and adds it to queued_installs_.
void CreateQueuedInstall(
const guest_os::GuestId& container_id,
const std::string& package,
CrostiniManager::InstallLinuxPackageCallback callback);
// Sets the operation status of the current operation. Sets the notification
// window's current state and updates containers_with_running_operations_.
// Note that if status is |SUCCEEDED| or |FAILED|, this may kick off another
// operation from the queued_uninstalls_ list. When status is |FAILED|, the
// |error_message| will contain an error reported by the installation process.
void UpdatePackageOperationStatus(const guest_os::GuestId& container_id,
PackageOperationStatus status,
int progress_percent,
const std::string& error_message = {});
// Callback between sharing and invoking GetLinuxPackageInfo().
void OnSharePathForGetLinuxPackageInfo(
const guest_os::GuestId& container_id,
const storage::FileSystemURL& package_url,
const base::FilePath& package_path,
CrostiniManager::GetLinuxPackageInfoCallback callback,
CrostiniResult result);
// Wraps the callback provided in GetLinuxPackageInfo().
void OnGetLinuxPackageInfo(
const guest_os::GuestId& container_id,
CrostiniManager::GetLinuxPackageInfoCallback callback,
const LinuxPackageInfo& linux_package_info);
// Wraps the callback provided in InstallLinuxPackage().
void OnInstallLinuxPackage(
const guest_os::GuestId& container_id,
CrostiniManager::InstallLinuxPackageCallback callback,
CrostiniResult result);
// Kicks off an uninstall of the given app. Never queues the operation. Helper
// for QueueUninstallApplication (if the operation can be performed
// immediately) and StartQueuedOperation.
void UninstallApplication(
const guest_os::GuestOsRegistryService::Registration& registration,
const std::string& app_id);
// Callback when the Crostini container is up and ready to accept messages.
// Used by the uninstall flow only.
void OnCrostiniRunningForUninstall(const guest_os::GuestId& container_id,
const std::string& desktop_file_id,
CrostiniResult result);
// Callback for CrostiniManager::UninstallPackageOwningFile().
void OnUninstallPackageOwningFile(const guest_os::GuestId& container_id,
CrostiniResult result);
// Kick off the next operation in the queue for the given container.
void StartQueuedOperation(const guest_os::GuestId& container_id);
std::string GetUniqueNotificationId();
raw_ptr<Profile> profile_;
// The notifications in the RUNNING state for each container.
std::map<guest_os::GuestId, std::unique_ptr<CrostiniPackageNotification>>
running_notifications_;
// Installs we want to run when the current operation is done.
std::map<guest_os::GuestId, std::queue<QueuedInstall>> queued_installs_;
// Uninstalls we want to run when the current operation is done.
std::map<guest_os::GuestId, std::queue<QueuedUninstall>> queued_uninstalls_;
// Notifications in a finished state (either SUCCEEDED or FAILED). We need
// to keep notifications around until they are dismissed even if we don't
// update them any more.
std::vector<std::unique_ptr<CrostiniPackageNotification>>
finished_notifications_;
// A map storing which containers have currently pending app list update
// operations. If a container is not present in the map, we assume no pending
// updates.
std::set<guest_os::GuestId> has_pending_app_list_updates_;
// Called each time a notification is set to a new state.
StateChangeCallback testing_state_change_callback_;
int next_notification_id_ = 0;
CrostiniManager::RestartId restart_id_for_testing_;
base::WeakPtrFactory<CrostiniPackageService> weak_ptr_factory_{this};
};
} // namespace crostini
#endif // CHROME_BROWSER_ASH_CROSTINI_CROSTINI_PACKAGE_SERVICE_H_
|