| // 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_MANAGER_H_ |
| #define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_ |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/files/file_path.h" |
| #include "base/memory/singleton.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/optional.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/extensions/app_launch_params.h" |
| #include "chromeos/dbus/cicerone/cicerone_service.pb.h" |
| #include "chromeos/dbus/cicerone_client.h" |
| #include "chromeos/dbus/concierge/service.pb.h" |
| #include "chromeos/dbus/concierge_client.h" |
| |
| class Profile; |
| |
| namespace crostini { |
| |
| // Result types for CrostiniManager::StartTerminaVmCallback etc. |
| enum class ConciergeClientResult { |
| SUCCESS, |
| DBUS_ERROR, |
| UNPARSEABLE_RESPONSE, |
| CREATE_DISK_IMAGE_FAILED, |
| VM_START_FAILED, |
| VM_STOP_FAILED, |
| DESTROY_DISK_IMAGE_FAILED, |
| LIST_VM_DISKS_FAILED, |
| CLIENT_ERROR, |
| DISK_TYPE_ERROR, |
| CONTAINER_START_FAILED, |
| LAUNCH_CONTAINER_APPLICATION_FAILED, |
| INSTALL_LINUX_PACKAGE_FAILED, |
| INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE, |
| UNKNOWN_ERROR, |
| }; |
| |
| enum class InstallLinuxPackageProgressStatus { |
| SUCCEEDED, |
| FAILED, |
| DOWNLOADING, |
| INSTALLING, |
| }; |
| |
| // Return type when getting app icons from within a container. |
| struct Icon { |
| std::string desktop_file_id; |
| |
| // Icon file content in PNG format. |
| std::string content; |
| }; |
| |
| class InstallLinuxPackageProgressObserver { |
| public: |
| // A successfully started package install will continually fire progress |
| // events until it returns a status of SUCCEEDED or FAILED. The |
| // |progress_percent| field is given as a percentage of the given step, |
| // DOWNLOADING or INSTALLING. |failure_reason| is returned from the container |
| // for a FAILED case, and not necessarily localized. |
| virtual void OnInstallLinuxPackageProgress( |
| const std::string& vm_name, |
| const std::string& container_name, |
| InstallLinuxPackageProgressStatus status, |
| int progress_percent, |
| const std::string& failure_reason) = 0; |
| }; |
| |
| // CrostiniManager is a singleton which is used to check arguments for |
| // ConciergeClient and CiceroneClient. ConciergeClient is dedicated to |
| // communication with the Concierge service, CiceroneClient is dedicated to |
| // communication with the Cicerone service and both should remain as thin as |
| // possible. The existence of Cicerone is abstracted behind this class and |
| // only the Concierge name is exposed outside of here. |
| class CrostiniManager : public chromeos::ConciergeClient::Observer, |
| public chromeos::CiceroneClient::Observer { |
| public: |
| using ConciergeClientCallback = |
| base::OnceCallback<void(ConciergeClientResult result)>; |
| |
| // The type of the callback for CrostiniManager::StartConcierge. |
| using StartConciergeCallback = |
| base::OnceCallback<void(bool is_service_available)>; |
| // The type of the callback for CrostiniManager::StopConcierge. |
| using StopConciergeCallback = StartConciergeCallback; |
| |
| // The type of the callback for CrostiniManager::StartTerminaVm. |
| using StartTerminaVmCallback = ConciergeClientCallback; |
| // The type of the callback for CrostiniManager::CreateDiskImage. |
| using CreateDiskImageCallback = |
| base::OnceCallback<void(ConciergeClientResult result, |
| const base::FilePath& disk_path)>; |
| // The type of the callback for CrostiniManager::DestroyDiskImage. |
| using DestroyDiskImageCallback = ConciergeClientCallback; |
| // The type of the callback for CrostiniManager::ListVmDisks. |
| using ListVmDisksCallback = |
| base::OnceCallback<void(ConciergeClientResult result, |
| int64_t total_size)>; |
| // The type of the callback for CrostiniManager::StopVm. |
| using StopVmCallback = ConciergeClientCallback; |
| // The type of the callback for CrostiniManager::StartContainer. |
| using StartContainerCallback = ConciergeClientCallback; |
| // The type of the callback for CrostiniManager::ShutdownContainer. |
| using ShutdownContainerCallback = base::OnceClosure; |
| // The type of the callback for CrostiniManager::LaunchContainerApplication. |
| using LaunchContainerApplicationCallback = ConciergeClientCallback; |
| // The type of the callback for CrostiniManager::GetContainerAppIcons. |
| using GetContainerAppIconsCallback = |
| base::OnceCallback<void(ConciergeClientResult result, |
| std::vector<Icon>& icons)>; |
| // The type of the callback for CrostiniManager::InstallLinuxPackage. |
| // |failure_reason| is returned from the container upon failure |
| // (INSTALL_LINUX_PACKAGE_FAILED), and not necessarily localized. |
| using InstallLinuxPackageCallback = |
| base::OnceCallback<void(ConciergeClientResult result, |
| const std::string& failure_reason)>; |
| // The type of the callback for CrostiniManager::GetContainerSshKeys. |
| using GetContainerSshKeysCallback = |
| base::OnceCallback<void(ConciergeClientResult result, |
| const std::string& container_public_key, |
| const std::string& host_private_key, |
| const std::string& hostname)>; |
| // The type of the callback for CrostiniManager::RestartCrostini. |
| using RestartCrostiniCallback = ConciergeClientCallback; |
| // The type of the callback for CrostiniManager::RemoveCrostini. |
| using RemoveCrostiniCallback = ConciergeClientCallback; |
| |
| // Observer class for the Crostini restart flow. |
| class RestartObserver { |
| public: |
| virtual ~RestartObserver() {} |
| virtual void OnComponentLoaded(ConciergeClientResult result) = 0; |
| virtual void OnConciergeStarted(ConciergeClientResult result) = 0; |
| virtual void OnDiskImageCreated(ConciergeClientResult result) = 0; |
| virtual void OnVmStarted(ConciergeClientResult result) = 0; |
| }; |
| |
| // Checks if the cros-termina component is installed. |
| static bool IsCrosTerminaInstalled(); |
| |
| // Generate the URL for Crostini terminal application. |
| static GURL GenerateVshInCroshUrl(Profile* profile, |
| const std::string& vm_name, |
| const std::string& container_name); |
| |
| // Generate AppLaunchParams for the Crostini terminal application. |
| static AppLaunchParams GenerateTerminalAppLaunchParams(Profile* profile); |
| |
| // Starts the Concierge service. |callback| is called after the method call |
| // finishes. |
| void StartConcierge(StartConciergeCallback callback); |
| |
| // Stops the Concierge service. |callback| is called after the method call |
| // finishes. |
| void StopConcierge(StopConciergeCallback callback); |
| |
| // Checks the arguments for creating a new Termina VM disk image. Creates a |
| // disk image for a Termina VM via ConciergeClient::CreateDiskImage. |
| // |callback| is called if the arguments are bad, or after the method call |
| // finishes. |
| void CreateDiskImage( |
| // The cryptohome id for the user's encrypted storage. |
| const std::string& cryptohome_id, |
| // The path to the disk image, including the name of |
| // the image itself. The image name should match the |
| // name of the VM that it will be used for. |
| const base::FilePath& disk_path, |
| // The storage location for the disk image |
| vm_tools::concierge::StorageLocation storage_location, |
| CreateDiskImageCallback callback); |
| |
| // Checks the arguments for destroying a named Termina VM disk image. |
| // Removes the named Termina VM via ConciergeClient::DestroyDiskImage. |
| // |callback| is called if the arguments are bad, or after the method call |
| // finishes. |
| void DestroyDiskImage( |
| // The cryptohome id for the user's encrypted storage. |
| const std::string& cryptohome_id, |
| // The path to the disk image, including the name of |
| // the image itself. |
| const base::FilePath& disk_path, |
| // The storage location of the disk image |
| vm_tools::concierge::StorageLocation storage_location, |
| DestroyDiskImageCallback callback); |
| |
| void ListVmDisks( |
| // The cryptohome id for the user's encrypted storage. |
| const std::string& cryptohome_id, |
| ListVmDisksCallback callback); |
| |
| // Checks the arguments for starting a Termina VM. Starts a Termina VM via |
| // ConciergeClient::StartTerminaVm. |callback| is called if the arguments |
| // are bad, or after the method call finishes. |
| void StartTerminaVm(std::string owner_id, |
| // The human-readable name to be assigned to this VM. |
| std::string name, |
| // Path to the disk image on the host. |
| const base::FilePath& disk_path, |
| StartTerminaVmCallback callback); |
| |
| // Checks the arguments for stopping a Termina VM. Stops the Termina VM via |
| // ConciergeClient::StopVm. |callback| is called if the arguments are bad, |
| // or after the method call finishes. |
| void StopVm(Profile* profile, std::string name, StopVmCallback callback); |
| |
| // Checks the arguments for starting a Container inside an existing Termina |
| // VM. Starts the container via ConciergeClient::StartContainer. |callback| |
| // is called if the arguments are bad, or after the method call finishes. |
| void StartContainer(std::string vm_name, |
| std::string container_name, |
| std::string container_username, |
| std::string cryptohome_id, |
| StartContainerCallback callback); |
| |
| // Asynchronously launches an app as specified by its desktop file id. |
| // |callback| is called with SUCCESS when the relevant process is started |
| // or LAUNCH_CONTAINER_APPLICATION_FAILED if there was an error somewhere. |
| void LaunchContainerApplication(Profile* profile, |
| std::string vm_name, |
| std::string container_name, |
| std::string desktop_file_id, |
| const std::vector<std::string>& files, |
| LaunchContainerApplicationCallback callback); |
| |
| // Asynchronously gets app icons as specified by their desktop file ids. |
| // |callback| is called after the method call finishes. |
| void GetContainerAppIcons(Profile* profile, |
| std::string vm_name, |
| std::string container_name, |
| std::vector<std::string> desktop_file_ids, |
| int icon_size, |
| int scale, |
| GetContainerAppIconsCallback callback); |
| |
| // Begin installation of a Linux Package inside the container. If the |
| // installation is successfully started, further updates will be sent to |
| // added InstallLinuxPackageProgressObservers. |
| void InstallLinuxPackage(Profile* profile, |
| std::string vm_name, |
| std::string container_name, |
| std::string package_path, |
| InstallLinuxPackageCallback callback); |
| |
| // Asynchronously gets SSH server public key of container and trusted SSH |
| // client private key which can be used to connect to the container. |
| // |callback| is called after the method call finishes. |
| void GetContainerSshKeys(std::string vm_name, |
| std::string container_name, |
| std::string cryptohome_id, |
| GetContainerSshKeysCallback callback); |
| |
| // Create the crosh-in-a-window that displays a shell in an container on a VM. |
| Browser* CreateContainerTerminal(const AppLaunchParams& launch_params, |
| const GURL& vsh_in_crosh_url); |
| |
| // Shows the already created crosh-in-a-window that displays a shell in an |
| // already running container on a VM. |
| void ShowContainerTerminal(const AppLaunchParams& launch_params, |
| const GURL& vsh_in_crosh_url, |
| Browser* browser); |
| |
| // Launches the crosh-in-a-window that displays a shell in an already running |
| // container on a VM. |
| void LaunchContainerTerminal(Profile* profile, |
| const std::string& vm_name, |
| const std::string& container_name); |
| |
| using RestartId = int; |
| static const RestartId kUninitializedRestartId = -1; |
| // Runs all the steps required to restart the given crostini vm and container. |
| // The optional |observer| tracks progress. |
| RestartId RestartCrostini(Profile* profile, |
| std::string vm_name, |
| std::string container_name, |
| RestartCrostiniCallback callback, |
| RestartObserver* observer = nullptr); |
| |
| void AbortRestartCrostini(Profile* profile, RestartId id); |
| |
| // Can be called for testing to skip restart. |
| void set_skip_restart_for_testing() { skip_restart_for_testing_ = true; } |
| bool skip_restart_for_testing() { return skip_restart_for_testing_; } |
| |
| // Adds a callback to receive notification of container shutdown. |
| void AddShutdownContainerCallback( |
| Profile* profile, |
| std::string vm_name, |
| std::string container_name, |
| ShutdownContainerCallback shutdown_callback); |
| |
| // Add/remove observers for package install progress. |
| void AddInstallLinuxPackageProgressObserver( |
| Profile* profile, |
| InstallLinuxPackageProgressObserver* observer); |
| void RemoveInstallLinuxPackageProgressObserver( |
| Profile* profile, |
| InstallLinuxPackageProgressObserver* observer); |
| |
| // ConciergeClient::Observer: |
| void OnContainerStartupFailed( |
| const vm_tools::concierge::ContainerStartedSignal& signal) override; |
| |
| // CiceroneClient::Observer: |
| void OnContainerStarted( |
| const vm_tools::cicerone::ContainerStartedSignal& signal) override; |
| void OnContainerShutdown( |
| const vm_tools::cicerone::ContainerShutdownSignal& signal) override; |
| void OnInstallLinuxPackageProgress( |
| const vm_tools::cicerone::InstallLinuxPackageProgressSignal& signal) |
| override; |
| |
| void RemoveCrostini(Profile* profile, |
| std::string vm_name, |
| std::string container_name, |
| RemoveCrostiniCallback callback); |
| |
| // Returns the singleton instance of CrostiniManager. |
| static CrostiniManager* GetInstance(); |
| |
| bool IsVmRunning(Profile* profile, std::string vm_name); |
| bool IsContainerRunning(Profile* profile, |
| std::string vm_name, |
| std::string container_name); |
| |
| private: |
| friend struct base::DefaultSingletonTraits<CrostiniManager>; |
| |
| CrostiniManager(); |
| ~CrostiniManager() override; |
| |
| // Callback for ConciergeClient::CreateDiskImage. Called after the Concierge |
| // service method finishes. |
| void OnCreateDiskImage( |
| CreateDiskImageCallback callback, |
| base::Optional<vm_tools::concierge::CreateDiskImageResponse> reply); |
| |
| // Callback for ConciergeClient::DestroyDiskImage. Called after the Concierge |
| // service method finishes. |
| void OnDestroyDiskImage( |
| DestroyDiskImageCallback callback, |
| base::Optional<vm_tools::concierge::DestroyDiskImageResponse> reply); |
| |
| // Callback for ConciergeClient::ListVmDisks. Called after the Concierge |
| // service method finishes. |
| void OnListVmDisks( |
| ListVmDisksCallback callback, |
| base::Optional<vm_tools::concierge::ListVmDisksResponse> reply); |
| |
| // Callback for ConciergeClient::StartTerminaVm. Called after the Concierge |
| // service method finishes. |
| void OnStartTerminaVm( |
| std::string owner_id, |
| std::string vm_name, |
| StartTerminaVmCallback callback, |
| base::Optional<vm_tools::concierge::StartVmResponse> reply); |
| |
| // Callback for ConciergeClient::StopVm. Called after the Concierge |
| // service method finishes. |
| void OnStopVm(std::string owner_id, |
| std::string vm_name, |
| StopVmCallback callback, |
| base::Optional<vm_tools::concierge::StopVmResponse> reply); |
| |
| // Callback for CrostiniClient::StartConcierge. Called after the |
| // DebugDaemon service method finishes. |
| void OnStartConcierge(StartConciergeCallback callback, bool success); |
| |
| // Callback for CrostiniClient::StopConcierge. Called after the |
| // DebugDaemon service method finishes. |
| void OnStopConcierge(StopConciergeCallback callback, bool success); |
| |
| // Callback for CrostiniManager::StartContainer. Called after the Concierge |
| // service finishes. |
| void OnStartContainer( |
| std::string owner_id, |
| std::string vm_name, |
| std::string container_name, |
| StartContainerCallback callback, |
| base::Optional<vm_tools::concierge::StartContainerResponse> reply); |
| |
| // Callback for CrostiniManager::LaunchContainerApplication. |
| void OnLaunchContainerApplication( |
| LaunchContainerApplicationCallback callback, |
| base::Optional<vm_tools::cicerone::LaunchContainerApplicationResponse> |
| reply); |
| |
| // Callback for CrostiniManager::GetContainerAppIcons. Called after the |
| // Concierge service finishes. |
| void OnGetContainerAppIcons( |
| GetContainerAppIconsCallback callback, |
| base::Optional<vm_tools::cicerone::ContainerAppIconResponse> reply); |
| |
| // Callback for CrostiniManager::InstallLinuxPackage. |
| void OnInstallLinuxPackage( |
| InstallLinuxPackageCallback callback, |
| base::Optional<vm_tools::cicerone::InstallLinuxPackageResponse> reply); |
| |
| // Callback for CrostiniManager::GetContainerSshKeys. Called after the |
| // Concierge service finishes. |
| void OnGetContainerSshKeys( |
| GetContainerSshKeysCallback callback, |
| base::Optional<vm_tools::concierge::ContainerSshKeysResponse> reply); |
| |
| // Helper for CrostiniManager::CreateDiskImage. Separated so it can be run |
| // off the main thread. |
| void CreateDiskImageAfterSizeCheck( |
| vm_tools::concierge::CreateDiskImageRequest request, |
| CreateDiskImageCallback callback, |
| int64_t free_disk_size); |
| |
| // Pending StartContainer callbacks are keyed by <owner_id, vm_name, |
| // container_name> string tuples. |
| std::multimap<std::tuple<std::string, std::string, std::string>, |
| StartContainerCallback> |
| start_container_callbacks_; |
| |
| bool skip_restart_for_testing_ = false; |
| |
| // Pending ShutdownContainer callbacks are keyed by <owner_id, vm_name, |
| // container_name> string tuples. |
| std::multimap<std::tuple<std::string, std::string, std::string>, |
| ShutdownContainerCallback> |
| shutdown_container_callbacks_; |
| |
| // Running vms as <owner_id, vm_name> pairs. |
| std::set<std::pair<std::string, std::string>> running_vms_; |
| |
| // Running containers as keyed by <owner_id, vm_name> string pairs. |
| std::multimap<std::pair<std::string, std::string>, std::string> |
| running_containers_; |
| |
| // Keyed by owner_id. |
| std::multimap<std::string, InstallLinuxPackageProgressObserver*> |
| install_linux_package_progress_observers_; |
| |
| // Note: This should remain the last member so it'll be destroyed and |
| // invalidate its weak pointers before any other members are destroyed. |
| base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CrostiniManager); |
| }; |
| |
| } // namespace crostini |
| |
| #endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_ |