| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_SERVICE_H_ |
| #define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_SERVICE_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <queue> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/callback_forward.h" |
| #include "base/memory/weak_ptr.h" |
| #include "chrome/browser/chromeos/crostini/crostini_manager.h" |
| #include "chrome/browser/chromeos/crostini/crostini_package_notification.h" |
| #include "chrome/browser/chromeos/crostini/crostini_package_operation_status.h" |
| #include "chrome/browser/chromeos/crostini/crostini_registry_service.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| |
| namespace crostini { |
| |
| class CrostiniPackageService : public KeyedService, |
| public LinuxPackageOperationProgressObserver { |
| public: |
| using StateChangeCallback = |
| base::RepeatingCallback<void(PackageOperationStatus)>; |
| |
| static CrostiniPackageService* GetForProfile(Profile* profile); |
| |
| explicit CrostiniPackageService(Profile* profile); |
| ~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); |
| |
| // The package installer service caches the most recent retrieved package |
| // info, for use in a package install notification. |
| // TODO(timloh): Actually cache the values. |
| void GetLinuxPackageInfo( |
| const std::string& vm_name, |
| const std::string& container_name, |
| const std::string& package_path, |
| CrostiniManager::GetLinuxPackageInfoCallback callback); |
| |
| // Install a Linux package. If successfully started, a system notification |
| // will be used to display further updates. |
| void InstallLinuxPackage( |
| const std::string& vm_name, |
| const std::string& container_name, |
| const std::string& package_path, |
| CrostiniManager::InstallLinuxPackageCallback callback); |
| |
| // LinuxPackageOperationProgressObserver: |
| void OnInstallLinuxPackageProgress(const std::string& vm_name, |
| const std::string& container_name, |
| InstallLinuxPackageProgressStatus status, |
| int progress_percent) override; |
| |
| void OnUninstallPackageProgress(const std::string& vm_name, |
| const std::string& container_name, |
| UninstallPackageProgressStatus status, |
| int progress_percent) override; |
| |
| // (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); |
| |
| private: |
| // A unique identifier for our containers. This is <vm_name, container_name>. |
| using ContainerIdentifier = std::pair<std::string, std::string>; |
| |
| // The user can request new uninstalls 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 QueuedUninstall; |
| |
| std::string ContainerIdentifierToString( |
| const ContainerIdentifier& container_id) const; |
| |
| bool ContainerHasRunningOperation( |
| const ContainerIdentifier& 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 ContainerIdentifier& 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 ContainerIdentifier& container_id, |
| const std::string& app_id, |
| const std::string& app_name); |
| |
| // 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. |
| void UpdatePackageOperationStatus(const ContainerIdentifier& container_id, |
| PackageOperationStatus status, |
| int progress_percent); |
| |
| // Wraps the callback provided in GetLinuxPackageInfo(). |
| void OnGetLinuxPackageInfo( |
| const std::string& vm_name, |
| const std::string& container_name, |
| CrostiniManager::GetLinuxPackageInfoCallback callback, |
| const LinuxPackageInfo& linux_package_info); |
| |
| // Wraps the callback provided in InstallLinuxPackage(). |
| void OnInstallLinuxPackage( |
| const std::string& vm_name, |
| const std::string& container_name, |
| 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 StartQueuedUninstall. |
| void UninstallApplication( |
| const CrostiniRegistryService::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 ContainerIdentifier& container_id, |
| const std::string& desktop_file_id, |
| CrostiniResult result); |
| |
| // Callback for CrostiniManager::UninstallPackageOwningFile(). |
| void OnUninstallPackageOwningFile(const ContainerIdentifier& container_id, |
| CrostiniResult result); |
| |
| // Kick off the next operation in the queue for the given container. |
| void StartQueuedUninstall(const ContainerIdentifier& container_id); |
| |
| std::string GetUniqueNotificationId(); |
| |
| Profile* profile_; |
| |
| // The notifications in the RUNNING state for each container. |
| std::map<ContainerIdentifier, std::unique_ptr<CrostiniPackageNotification>> |
| running_notifications_; |
| |
| // Containers that have an install waiting for its initial response. We don't |
| // display notifications for these, but they still need to cause uninstalls |
| // to queue. |
| std::set<ContainerIdentifier> containers_with_pending_installs_; |
| |
| // Uninstalls we want to run when the current one is done. |
| std::map<ContainerIdentifier, 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_; |
| |
| // Called each time a notification is set to a new state. |
| StateChangeCallback testing_state_change_callback_; |
| |
| int next_notification_id_ = 0; |
| |
| base::WeakPtrFactory<CrostiniPackageService> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CrostiniPackageService); |
| }; |
| |
| } // namespace crostini |
| |
| #endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_SERVICE_H_ |