1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_
6 #define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_
7 
8 #include <map>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/files/file_path.h"
14 #include "base/memory/singleton.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/observer_list.h"
17 #include "base/optional.h"
18 #include "base/unguessable_token.h"
19 #include "chrome/browser/chromeos/crostini/crostini_simple_types.h"
20 #include "chrome/browser/chromeos/crostini/crostini_types.mojom-forward.h"
21 #include "chrome/browser/chromeos/crostini/crostini_util.h"
22 #include "chrome/browser/chromeos/crostini/termina_installer.h"
23 #include "chrome/browser/chromeos/vm_starting_observer.h"
24 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chromeos/dbus/anomaly_detector/anomaly_detector.pb.h"
27 #include "chromeos/dbus/anomaly_detector_client.h"
28 #include "chromeos/dbus/cicerone/cicerone_service.pb.h"
29 #include "chromeos/dbus/cicerone_client.h"
30 #include "chromeos/dbus/concierge/concierge_service.pb.h"
31 #include "chromeos/dbus/concierge_client.h"
32 #include "chromeos/dbus/power/power_manager_client.h"
33 #include "chromeos/network/network_state.h"
34 #include "chromeos/network/network_state_handler.h"
35 #include "chromeos/network/network_state_handler_observer.h"
36 #include "components/keyed_service/core/keyed_service.h"
37 #include "services/device/public/mojom/usb_manager.mojom.h"
38 
39 class Profile;
40 
41 namespace crostini {
42 
43 class CrostiniStabilityMonitor;
44 class CrostiniUpgradeAvailableNotification;
45 
46 class LinuxPackageOperationProgressObserver {
47  public:
48   // A successfully started package install will continually fire progress
49   // events until it returns a status of SUCCEEDED or FAILED. The
50   // |progress_percent| field is given as a percentage of the given step,
51   // DOWNLOADING or INSTALLING. If |status| is FAILED, the |error_message|
52   // will contain output of the failing installation command.
53   virtual void OnInstallLinuxPackageProgress(
54       const ContainerId& container_id,
55       InstallLinuxPackageProgressStatus status,
56       int progress_percent,
57       const std::string& error_message) = 0;
58 
59   // A successfully started package uninstall will continually fire progress
60   // events until it returns a status of SUCCEEDED or FAILED.
61   virtual void OnUninstallPackageProgress(const ContainerId& container_id,
62                                           UninstallPackageProgressStatus status,
63                                           int progress_percent) = 0;
64 };
65 
66 class PendingAppListUpdatesObserver : public base::CheckedObserver {
67  public:
68   // Called whenever the kPendingAppListUpdatesMethod signal is sent.
69   virtual void OnPendingAppListUpdates(const ContainerId& container_id,
70                                        int count) = 0;
71 };
72 
73 class ExportContainerProgressObserver {
74  public:
75   // DEPCRECATED. A successfully started container export will continually fire
76   // progress events until the original callback from ExportLxdContainer is
77   // invoked with a status of SUCCESS or CONTAINER_EXPORT_FAILED.
78   virtual void OnExportContainerProgress(const ContainerId& container_id,
79                                          ExportContainerProgressStatus status,
80                                          int progress_percent,
81                                          uint64_t progress_speed) = 0;
82 
83   // A successfully started container export will continually fire progress
84   // events until the original callback from ExportLxdContainer is invoked with
85   // a status of SUCCESS or CONTAINER_EXPORT_FAILED.
86   virtual void OnExportContainerProgress(const ContainerId& container_id,
87                                          const StreamingExportStatus&) = 0;
88 };
89 
90 class ImportContainerProgressObserver {
91  public:
92   // A successfully started container import will continually fire progress
93   // events until the original callback from ImportLxdContainer is invoked with
94   // a status of SUCCESS or CONTAINER_IMPORT_FAILED[_*].
95   virtual void OnImportContainerProgress(
96       const ContainerId& container_id,
97       ImportContainerProgressStatus status,
98       int progress_percent,
99       uint64_t progress_speed,
100       const std::string& architecture_device,
101       const std::string& architecture_container,
102       uint64_t available_space,
103       uint64_t minimum_required_space) = 0;
104 };
105 
106 class UpgradeContainerProgressObserver {
107  public:
108   virtual void OnUpgradeContainerProgress(
109       const ContainerId& container_id,
110       UpgradeContainerProgressStatus status,
111       const std::vector<std::string>& messages) = 0;
112 };
113 
114 class CrostiniDialogStatusObserver : public base::CheckedObserver {
115  public:
116   // Called when a Crostini dialog (installer, upgrader, etc.) opens or
117   // closes.
118   virtual void OnCrostiniDialogStatusChanged(DialogType dialog_type,
119                                              bool open) = 0;
120 };
121 
122 class CrostiniContainerPropertiesObserver : public base::CheckedObserver {
123  public:
124   // Called when a container's OS release version changes.
125   virtual void OnContainerOsReleaseChanged(const ContainerId& container_id,
126                                            bool can_upgrade) = 0;
127 };
128 
129 class VmShutdownObserver : public base::CheckedObserver {
130  public:
131   // Called when the given VM has shutdown.
132   virtual void OnVmShutdown(const std::string& vm_name) = 0;
133 };
134 
135 class ContainerStartedObserver : public base::CheckedObserver {
136  public:
137   // Called when the container has started.
138   virtual void OnContainerStarted(const ContainerId& container_id) = 0;
139 };
140 
141 class ContainerShutdownObserver : public base::CheckedObserver {
142  public:
143   // Called when the container has shutdown.
144   virtual void OnContainerShutdown(const ContainerId& container_id) = 0;
145 };
146 
147 class CrostiniMicSharingEnabledObserver : public base::CheckedObserver {
148  public:
149   // Called when changes are made to the Crostini mic settings.
150   virtual void OnCrostiniMicSharingEnabledChanged(bool enabled) = 0;
151 };
152 
153 class CrostiniFileChangeObserver : public base::CheckedObserver {
154  public:
155   // Called when a path registered via AddFileWatch() is changed.
156   virtual void OnCrostiniFileChanged(const ContainerId& container_id,
157                                      const base::FilePath& path) = 0;
158 };
159 
160 // CrostiniManager is a singleton which is used to check arguments for
161 // ConciergeClient and CiceroneClient. ConciergeClient is dedicated to
162 // communication with the Concierge service, CiceroneClient is dedicated to
163 // communication with the Cicerone service and both should remain as thin as
164 // possible. The existence of Cicerone is abstracted behind this class and
165 // only the Concierge name is exposed outside of here.
166 class CrostiniManager : public KeyedService,
167                         public chromeos::AnomalyDetectorClient::Observer,
168                         public chromeos::ConciergeClient::VmObserver,
169                         public chromeos::ConciergeClient::ContainerObserver,
170                         public chromeos::CiceroneClient::Observer,
171                         public chromeos::NetworkStateHandlerObserver,
172                         public chromeos::PowerManagerClient::Observer {
173  public:
174   using CrostiniResultCallback =
175       base::OnceCallback<void(CrostiniResult result)>;
176   using ExportLxdContainerResultCallback =
177       base::OnceCallback<void(CrostiniResult result,
178                               uint64_t container_size,
179                               uint64_t compressed_size)>;
180   // Callback indicating success or failure
181   using BoolCallback = base::OnceCallback<void(bool success)>;
182 
183   using RestartId = int;
184   static const RestartId kUninitializedRestartId = -1;
185 
186   // Observer class for the Crostini restart flow.
187   class RestartObserver {
188    public:
~RestartObserver()189     virtual ~RestartObserver() {}
OnStageStarted(mojom::InstallerState stage)190     virtual void OnStageStarted(mojom::InstallerState stage) {}
OnComponentLoaded(CrostiniResult result)191     virtual void OnComponentLoaded(CrostiniResult result) {}
OnDiskImageCreated(bool success,vm_tools::concierge::DiskImageStatus status,int64_t disk_size_bytes)192     virtual void OnDiskImageCreated(bool success,
193                                     vm_tools::concierge::DiskImageStatus status,
194                                     int64_t disk_size_bytes) {}
OnVmStarted(bool success)195     virtual void OnVmStarted(bool success) {}
OnContainerDownloading(int32_t download_percent)196     virtual void OnContainerDownloading(int32_t download_percent) {}
OnContainerCreated(CrostiniResult result)197     virtual void OnContainerCreated(CrostiniResult result) {}
OnContainerSetup(bool success)198     virtual void OnContainerSetup(bool success) {}
OnContainerStarted(CrostiniResult result)199     virtual void OnContainerStarted(CrostiniResult result) {}
OnSshKeysFetched(bool success)200     virtual void OnSshKeysFetched(bool success) {}
OnContainerMounted(bool success)201     virtual void OnContainerMounted(bool success) {}
202 
restart_id()203     RestartId restart_id() const { return restart_id_; }
204 
205    protected:
206     friend class CrostiniManager;
set_restart_id(RestartId restart_id)207     void set_restart_id(RestartId restart_id) { restart_id_ = restart_id; }
208     RestartId restart_id_ = kUninitializedRestartId;
209   };
210 
211   struct RestartOptions {
212     // These two options only affect new containers.
213     base::Optional<std::string> container_username;
214     base::Optional<int64_t> disk_size_bytes;
215 
216     RestartOptions();
217     ~RestartOptions();
218     // Add copy version if necessary.
219     RestartOptions(RestartOptions&&);
220     RestartOptions& operator=(RestartOptions&&);
221   };
222 
223   static CrostiniManager* GetForProfile(Profile* profile);
224 
225   explicit CrostiniManager(Profile* profile);
226   ~CrostiniManager() override;
227 
228   base::WeakPtr<CrostiniManager> GetWeakPtr();
229 
230   // Returns true if the /dev/kvm directory is present.
231   static bool IsDevKvmPresent();
232 
233   // Upgrades cros-termina component if the current version is not
234   // compatible. This is a no-op if chromeos::features::kCrostiniUseDlc is
235   // enabled.
236   void MaybeUpdateCrostini();
237 
238   // Installs termina using either component updater or the DLC service
239   // depending on the value of chromeos::features::kCrostiniUseDlc
240   void InstallTermina(CrostiniResultCallback callback);
241 
242   // Unloads and removes termina.
243   void UninstallTermina(BoolCallback callback);
244 
245   // Checks the arguments for creating a new Termina VM disk image. Creates a
246   // disk image for a Termina VM via ConciergeClient::CreateDiskImage.
247   // |callback| is called if the arguments are bad, or after the method call
248   // finishes.
249   using CreateDiskImageCallback =
250       base::OnceCallback<void(bool success,
251                               vm_tools::concierge::DiskImageStatus,
252                               const base::FilePath& disk_path)>;
253   void CreateDiskImage(
254       // The path to the disk image, including the name of
255       // the image itself. The image name should match the
256       // name of the VM that it will be used for.
257       const base::FilePath& disk_path,
258       // The storage location for the disk image
259       vm_tools::concierge::StorageLocation storage_location,
260       // The logical size of the disk image, in bytes
261       int64_t disk_size_bytes,
262       CreateDiskImageCallback callback);
263 
264   // Checks the arguments for destroying a named Termina VM disk image.
265   // Removes the named Termina VM via ConciergeClient::DestroyDiskImage.
266   // |callback| is called if the arguments are bad, or after the method call
267   // finishes.
268   void DestroyDiskImage(
269       // The path to the disk image, including the name of the image itself.
270       const base::FilePath& disk_path,
271       BoolCallback callback);
272 
273   using ListVmDisksCallback =
274       base::OnceCallback<void(CrostiniResult result, int64_t total_size)>;
275   void ListVmDisks(ListVmDisksCallback callback);
276 
277   // Checks the arguments for starting a Termina VM. Starts a Termina VM via
278   // ConciergeClient::StartTerminaVm. |callback| is called if the arguments
279   // are bad, or after the method call finishes.
280   void StartTerminaVm(
281       // The human-readable name to be assigned to this VM.
282       std::string name,
283       // Path to the disk image on the host.
284       const base::FilePath& disk_path,
285       // The number of logical CPU cores that are currently disabled.
286       size_t num_cores_disabled,
287       BoolCallback callback);
288 
289   // Checks the arguments for stopping a Termina VM. Stops the Termina VM via
290   // ConciergeClient::StopVm. |callback| is called if the arguments are bad,
291   // or after the method call finishes.
292   void StopVm(std::string name, CrostiniResultCallback callback);
293 
294   // Asynchronously retrieve the Termina VM kernel version using
295   // concierge's GetVmEnterpriseReportingInfo method.
296   using GetTerminaVmKernelVersionCallback = base::OnceCallback<void(
297       const base::Optional<std::string>& maybe_kernel_version)>;
298   void GetTerminaVmKernelVersion(GetTerminaVmKernelVersionCallback callback);
299 
300   // Wrapper for CiceroneClient::StartLxd with some extra parameter validation.
301   // |callback| is called immediately if the arguments are bad, or after LXD has
302   // been started.
303   void StartLxd(std::string vm_name, CrostiniResultCallback callback);
304 
305   // Checks the arguments for creating an Lxd container via
306   // CiceroneClient::CreateLxdContainer. |callback| is called immediately if the
307   // arguments are bad, or once the container has been created.
308   void CreateLxdContainer(ContainerId container_id,
309                           CrostiniResultCallback callback);
310 
311   // Checks the arguments for deleting an Lxd container via
312   // CiceroneClient::DeleteLxdContainer. |callback| is called immediately if the
313   // arguments are bad, or once the container has been deleted.
314   void DeleteLxdContainer(ContainerId container_id, BoolCallback callback);
315 
316   // Checks the arguments for starting an Lxd container via
317   // CiceroneClient::StartLxdContainer. |callback| is called immediately if the
318   // arguments are bad, or once the container has been created.
319   void StartLxdContainer(ContainerId container_id,
320                          CrostiniResultCallback callback);
321 
322   // Checks the arguments for setting up an Lxd container user via
323   // CiceroneClient::SetUpLxdContainerUser. |callback| is called immediately if
324   // the arguments are bad, or once garcon has been started.
325   void SetUpLxdContainerUser(ContainerId container_id,
326                              std::string container_username,
327                              BoolCallback callback);
328 
329   // Checks the arguments for exporting an Lxd container via
330   // CiceroneClient::ExportLxdContainer. |callback| is called immediately if the
331   // arguments are bad, or after the method call finishes.
332   void ExportLxdContainer(ContainerId container_id,
333                           base::FilePath export_path,
334                           ExportLxdContainerResultCallback callback);
335 
336   // Checks the arguments for importing an Lxd container via
337   // CiceroneClient::ImportLxdContainer. |callback| is called immediately if the
338   // arguments are bad, or after the method call finishes.
339   void ImportLxdContainer(ContainerId container_id,
340                           base::FilePath import_path,
341                           CrostiniResultCallback callback);
342 
343   // Checks the arguments for cancelling a Lxd container export via
344   // CiceroneClient::CancelExportLxdContainer .
345   void CancelExportLxdContainer(ContainerId key);
346 
347   // Checks the arguments for cancelling a Lxd container import via
348   // CiceroneClient::CancelImportLxdContainer.
349   void CancelImportLxdContainer(ContainerId key);
350 
351   // Checks the arguments for upgrading an existing container via
352   // CiceroneClient::UpgradeContainer. An UpgradeProgressObserver should be used
353   // to monitor further results.
354   void UpgradeContainer(const ContainerId& key,
355                         ContainerVersion source_version,
356                         ContainerVersion target_version,
357                         CrostiniResultCallback callback);
358 
359   // Checks the arguments for canceling the upgrade of an existing container via
360   // CiceroneClient::CancelUpgradeContainer.
361   void CancelUpgradeContainer(const ContainerId& key,
362                               CrostiniResultCallback callback);
363 
364   // Asynchronously launches an app as specified by its desktop file id.
365   void LaunchContainerApplication(const ContainerId& container_id,
366                                   std::string desktop_file_id,
367                                   const std::vector<std::string>& files,
368                                   bool display_scaled,
369                                   CrostiniSuccessCallback callback);
370 
371   // Asynchronously gets app icons as specified by their desktop file ids.
372   // |callback| is called after the method call finishes.
373   using GetContainerAppIconsCallback =
374       base::OnceCallback<void(bool success, const std::vector<Icon>& icons)>;
375   void GetContainerAppIcons(const ContainerId& container_id,
376                             std::vector<std::string> desktop_file_ids,
377                             int icon_size,
378                             int scale,
379                             GetContainerAppIconsCallback callback);
380 
381   // Asynchronously retrieve information about a Linux Package (.deb) inside the
382   // container.
383   using GetLinuxPackageInfoCallback =
384       base::OnceCallback<void(const LinuxPackageInfo&)>;
385   void GetLinuxPackageInfo(const ContainerId& container_id,
386                            std::string package_path,
387                            GetLinuxPackageInfoCallback callback);
388 
389   // Begin installation of a Linux Package inside the container. If the
390   // installation is successfully started, further updates will be sent to
391   // added LinuxPackageOperationProgressObservers.
392   using InstallLinuxPackageCallback = CrostiniResultCallback;
393   void InstallLinuxPackage(const ContainerId& container_id,
394                            std::string package_path,
395                            InstallLinuxPackageCallback callback);
396 
397   // Begin installation of a Linux Package inside the container. If the
398   // installation is successfully started, further updates will be sent to
399   // added LinuxPackageOperationProgressObservers. Uses a package_id, given
400   // by "package_name;version;arch;data", to identify the package to install
401   // from the APT repository.
402   void InstallLinuxPackageFromApt(const ContainerId& container_id,
403                                   std::string package_id,
404                                   InstallLinuxPackageCallback callback);
405 
406   // Begin uninstallation of a Linux Package inside the container. The package
407   // is identified by its associated .desktop file's ID; we don't use package_id
408   // to avoid problems with stale package_ids (such as after upgrades). If the
409   // uninstallation is successfully started, further updates will be sent to
410   // added LinuxPackageOperationProgressObservers.
411   void UninstallPackageOwningFile(const ContainerId& container_id,
412                                   std::string desktop_file_id,
413                                   CrostiniResultCallback callback);
414 
415   // Asynchronously gets SSH server public key of container and trusted SSH
416   // client private key which can be used to connect to the container.
417   // |callback| is called after the method call finishes.
418   using GetContainerSshKeysCallback =
419       base::OnceCallback<void(bool success,
420                               const std::string& container_public_key,
421                               const std::string& host_private_key,
422                               const std::string& hostname)>;
423   void GetContainerSshKeys(const ContainerId& container_id,
424                            GetContainerSshKeysCallback callback);
425 
426   // Add a relative path to watch within the container homedir. Register as a
427   // CrostiniFileChangeObserver to be notified when changes occur. Used by
428   // FilesApp.
429   void AddFileWatch(const ContainerId& container_id,
430                     const base::FilePath& path,
431                     BoolCallback callback);
432   void RemoveFileWatch(const ContainerId& container_id,
433                        const base::FilePath& path);
434   void AddFileChangeObserver(CrostiniFileChangeObserver* observer);
435   void RemoveFileChangeObserver(CrostiniFileChangeObserver* observer);
436 
437   // Lookup vsh session from pid. Used by terminal to open new tabs in cwd.
438   using VshSessionCallback =
439       base::OnceCallback<void(bool success,
440                               const std::string& failure_reason,
441                               int32_t container_shell_pid)>;
442   void GetVshSession(const ContainerId& container_id,
443                      int32_t host_vsh_pid,
444                      VshSessionCallback callback);
445 
446   // Runs all the steps required to restart the given crostini vm and container.
447   // The optional |observer| tracks progress. If provided, it must be alive
448   // until the restart completes (i.e. when |callback| is called) or the restart
449   // is aborted via |AbortRestartCrostini|.
450   RestartId RestartCrostini(ContainerId container_id,
451                             CrostiniResultCallback callback,
452                             RestartObserver* observer = nullptr);
453 
454   RestartId RestartCrostiniWithOptions(ContainerId container_id,
455                                        RestartOptions options,
456                                        CrostiniResultCallback callback,
457                                        RestartObserver* observer = nullptr);
458 
459   // Aborts a restart. A "next" restarter with the same ContainerId will run, if
460   // there is one. |callback| will be called once the restart has finished
461   // aborting
462   void AbortRestartCrostini(RestartId restart_id, base::OnceClosure callback);
463 
464   // Returns true if the Restart corresponding to |restart_id| is not yet
465   // complete.
466   bool IsRestartPending(RestartId restart_id);
467 
468   // Adds a callback to receive notification of container shutdown.
469   void AddShutdownContainerCallback(ContainerId container_id,
470                                     base::OnceClosure shutdown_callback);
471 
472   // Adds a callback to receive uninstall notification.
473   using RemoveCrostiniCallback = CrostiniResultCallback;
474   void AddRemoveCrostiniCallback(RemoveCrostiniCallback remove_callback);
475 
476   // Add/remove observers for package install and uninstall progress.
477   void AddLinuxPackageOperationProgressObserver(
478       LinuxPackageOperationProgressObserver* observer);
479   void RemoveLinuxPackageOperationProgressObserver(
480       LinuxPackageOperationProgressObserver* observer);
481 
482   // Add/remove observers for pending app list updates.
483   void AddPendingAppListUpdatesObserver(
484       PendingAppListUpdatesObserver* observer);
485   void RemovePendingAppListUpdatesObserver(
486       PendingAppListUpdatesObserver* observer);
487 
488   // Add/remove observers for container export/import.
489   void AddExportContainerProgressObserver(
490       ExportContainerProgressObserver* observer);
491   void RemoveExportContainerProgressObserver(
492       ExportContainerProgressObserver* observer);
493   void AddImportContainerProgressObserver(
494       ImportContainerProgressObserver* observer);
495   void RemoveImportContainerProgressObserver(
496       ImportContainerProgressObserver* observer);
497 
498   // Add/remove observers for container upgrade
499   void AddUpgradeContainerProgressObserver(
500       UpgradeContainerProgressObserver* observer);
501   void RemoveUpgradeContainerProgressObserver(
502       UpgradeContainerProgressObserver* observer);
503 
504   // Add/remove vm shutdown observers.
505   void AddVmShutdownObserver(VmShutdownObserver* observer);
506   void RemoveVmShutdownObserver(VmShutdownObserver* observer);
507 
508   // Add/remove vm starting observers.
509   void AddVmStartingObserver(chromeos::VmStartingObserver* observer);
510   void RemoveVmStartingObserver(chromeos::VmStartingObserver* observer);
511 
512   // AnomalyDetectorClient::Observer:
513   void OnGuestFileCorruption(
514       const anomaly_detector::GuestFileCorruptionSignal& signal) override;
515 
516   // ConciergeClient::VmObserver:
517   void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override;
518   void OnVmStopped(const vm_tools::concierge::VmStoppedSignal& signal) override;
519 
520   // ConciergeClient::ContainerObserver:
521   void OnContainerStartupFailed(
522       const vm_tools::concierge::ContainerStartedSignal& signal) override;
523 
524   // CiceroneClient::Observer:
525   void OnContainerStarted(
526       const vm_tools::cicerone::ContainerStartedSignal& signal) override;
527   void OnContainerShutdown(
528       const vm_tools::cicerone::ContainerShutdownSignal& signal) override;
529   void OnInstallLinuxPackageProgress(
530       const vm_tools::cicerone::InstallLinuxPackageProgressSignal& signal)
531       override;
532   void OnUninstallPackageProgress(
533       const vm_tools::cicerone::UninstallPackageProgressSignal& signal)
534       override;
535   void OnLxdContainerCreated(
536       const vm_tools::cicerone::LxdContainerCreatedSignal& signal) override;
537   void OnLxdContainerDeleted(
538       const vm_tools::cicerone::LxdContainerDeletedSignal& signal) override;
539   void OnLxdContainerDownloading(
540       const vm_tools::cicerone::LxdContainerDownloadingSignal& signal) override;
541   void OnTremplinStarted(
542       const vm_tools::cicerone::TremplinStartedSignal& signal) override;
543   void OnLxdContainerStarting(
544       const vm_tools::cicerone::LxdContainerStartingSignal& signal) override;
545   void OnExportLxdContainerProgress(
546       const vm_tools::cicerone::ExportLxdContainerProgressSignal& signal)
547       override;
548   void OnImportLxdContainerProgress(
549       const vm_tools::cicerone::ImportLxdContainerProgressSignal& signal)
550       override;
551   void OnPendingAppListUpdates(
552       const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) override;
553   void OnApplyAnsiblePlaybookProgress(
554       const vm_tools::cicerone::ApplyAnsiblePlaybookProgressSignal& signal)
555       override;
556   void OnUpgradeContainerProgress(
557       const vm_tools::cicerone::UpgradeContainerProgressSignal& signal)
558       override;
559   void OnStartLxdProgress(
560       const vm_tools::cicerone::StartLxdProgressSignal& signal) override;
561   void OnFileWatchTriggered(
562       const vm_tools::cicerone::FileWatchTriggeredSignal& signal) override;
563 
564   // chromeos::NetworkStateHandlerObserver overrides:
565   void ActiveNetworksChanged(const std::vector<const chromeos::NetworkState*>&
566                                  active_networks) override;
567 
568   // chromeos::PowerManagerClient::Observer overrides:
569   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
570   void SuspendDone(const base::TimeDelta& sleep_duration) override;
571 
572   // Callback for |RemoveSshfsCrostiniVolume| called from |SuspendImminent| when
573   // the device is allowed to suspend. Removes metadata associated with the
574   // crostini sshfs mount and unblocks a pending suspend.
575   void OnRemoveSshfsCrostiniVolume(
576       base::UnguessableToken power_manager_suspend_token,
577       bool result);
578 
579   void RemoveCrostini(std::string vm_name, RemoveCrostiniCallback callback);
580 
581   void UpdateVmState(std::string vm_name, VmState vm_state);
582   bool IsVmRunning(std::string vm_name);
583   // Returns null if VM is not running.
584   base::Optional<VmInfo> GetVmInfo(std::string vm_name);
585   void AddRunningVmForTesting(std::string vm_name);
586   void AddStoppingVmForTesting(std::string vm_name);
587 
588   void SetContainerSshfsMounted(const ContainerId& container_id,
589                                 bool is_mounted);
590   void SetContainerOsRelease(const ContainerId& container_id,
591                              const vm_tools::cicerone::OsRelease& os_release);
592   const vm_tools::cicerone::OsRelease* GetContainerOsRelease(
593       const ContainerId& container_id) const;
594   // Returns null if VM or container is not running.
595   base::Optional<ContainerInfo> GetContainerInfo(
596       const ContainerId& container_id);
597   void AddRunningContainerForTesting(std::string vm_name, ContainerInfo info);
598 
599   // If the Crostini reporting policy is set, save the last app launch
600   // time window and the Termina version in prefs for asynchronous reporting.
601   void UpdateLaunchMetricsForEnterpriseReporting();
602 
603   // Clear the lists of running VMs and containers.
604   // Can be called for testing to skip restart.
set_skip_restart_for_testing()605   void set_skip_restart_for_testing() { skip_restart_for_testing_ = true; }
skip_restart_for_testing()606   bool skip_restart_for_testing() { return skip_restart_for_testing_; }
set_component_manager_load_error_for_testing(component_updater::CrOSComponentManager::Error error)607   void set_component_manager_load_error_for_testing(
608       component_updater::CrOSComponentManager::Error error) {
609     component_manager_load_error_for_testing_ = error;
610   }
611 
612   void SetCrostiniDialogStatus(DialogType dialog_type, bool open);
613   // Returns true if the dialog is open.
614   bool GetCrostiniDialogStatus(DialogType dialog_type) const;
615   void AddCrostiniDialogStatusObserver(CrostiniDialogStatusObserver* observer);
616   void RemoveCrostiniDialogStatusObserver(
617       CrostiniDialogStatusObserver* observer);
618 
619   void AddCrostiniContainerPropertiesObserver(
620       CrostiniContainerPropertiesObserver* observer);
621   void RemoveCrostiniContainerPropertiesObserver(
622       CrostiniContainerPropertiesObserver* observer);
623 
624   void AddContainerStartedObserver(ContainerStartedObserver* observer);
625   void RemoveContainerStartedObserver(ContainerStartedObserver* observer);
626   void AddContainerShutdownObserver(ContainerShutdownObserver* observer);
627   void RemoveContainerShutdownObserver(ContainerShutdownObserver* observer);
628 
629   void OnDBusShuttingDownForTesting();
630 
631   bool IsContainerUpgradeable(const ContainerId& container_id) const;
632   bool ShouldPromptContainerUpgrade(const ContainerId& container_id) const;
633   void UpgradePromptShown(const ContainerId& container_id);
634   void EnsureVmRunning(const ContainerId& key, CrostiniResultCallback callback);
635   bool IsUncleanStartup() const;
636   void SetUncleanStartupForTesting(bool is_unclean_startup);
637   void RemoveUncleanSshfsMounts();
638   void DeallocateForwardedPortsCallback(Profile* profile,
639                                         const ContainerId& container_id);
640 
641   void SetCrostiniMicSharingEnabled(bool enabled);
crostini_mic_sharing_enabled()642   bool crostini_mic_sharing_enabled() const {
643     return crostini_mic_sharing_enabled_;
644   }
645   void AddCrostiniMicSharingEnabledObserver(
646       CrostiniMicSharingEnabledObserver* observer);
647   void RemoveCrostiniMicSharingEnabledObserver(
648       CrostiniMicSharingEnabledObserver* observer);
649 
650  private:
651   class CrostiniRestarter;
652 
653   void RemoveDBusObservers();
654 
655   // Callback for ConciergeClient::CreateDiskImage. Called after the Concierge
656   // service method finishes.
657   void OnCreateDiskImage(
658       CreateDiskImageCallback callback,
659       base::Optional<vm_tools::concierge::CreateDiskImageResponse> response);
660 
661   // Callback for ConciergeClient::DestroyDiskImage. Called after the Concierge
662   // service method finishes.
663   void OnDestroyDiskImage(
664       BoolCallback callback,
665       base::Optional<vm_tools::concierge::DestroyDiskImageResponse> response);
666 
667   // Callback for ConciergeClient::ListVmDisks. Called after the Concierge
668   // service method finishes.
669   void OnListVmDisks(
670       ListVmDisksCallback callback,
671       base::Optional<vm_tools::concierge::ListVmDisksResponse> response);
672 
673   // Callback for ConciergeClient::StartTerminaVm. Called after the Concierge
674   // service method finishes.  Updates running containers list then calls the
675   // |callback| if the container has already been started, otherwise passes the
676   // callback to OnStartTremplin.
677   void OnStartTerminaVm(
678       std::string vm_name,
679       BoolCallback callback,
680       base::Optional<vm_tools::concierge::StartVmResponse> response);
681 
682   // Callback for ConciergeClient::TremplinStartedSignal. Called after the
683   // Tremplin service starts. Updates running containers list and then calls the
684   // |callback| with true, indicating success.
685   void OnStartTremplin(std::string vm_name, BoolCallback callback);
686 
687   // Callback for ConciergeClient::StopVm. Called after the Concierge
688   // service method finishes.
689   void OnStopVm(std::string vm_name,
690                 CrostiniResultCallback callback,
691                 base::Optional<vm_tools::concierge::StopVmResponse> response);
692 
693   // Callback for ConciergeClient::GetVmEnterpriseReportingInfo.
694   // Currently used to report the Termina kernel version for enterprise
695   // reporting.
696   void OnGetTerminaVmKernelVersion(
697       GetTerminaVmKernelVersionCallback callback,
698       base::Optional<vm_tools::concierge::GetVmEnterpriseReportingInfoResponse>
699           response);
700 
701   // Callback for CiceroneClient::StartLxd. May indicate that LXD is still being
702   // started in which case we will wait for OnStartLxdProgress events.
703   void OnStartLxd(
704       std::string vm_name,
705       CrostiniResultCallback callback,
706       base::Optional<vm_tools::cicerone::StartLxdResponse> response);
707 
708   // Callback for CiceroneClient::CreateLxdContainer. May indicate the container
709   // is still being created, in which case we will wait for an
710   // OnLxdContainerCreated event.
711   void OnCreateLxdContainer(
712       const ContainerId& container_id,
713       CrostiniResultCallback callback,
714       base::Optional<vm_tools::cicerone::CreateLxdContainerResponse> response);
715 
716   // Callback for CiceroneClient::DeleteLxdContainer.
717   void OnDeleteLxdContainer(
718       const ContainerId& container_id,
719       BoolCallback callback,
720       base::Optional<vm_tools::cicerone::DeleteLxdContainerResponse> response);
721 
722   // Callback for CiceroneClient::StartLxdContainer.
723   void OnStartLxdContainer(
724       const ContainerId& container_id,
725       CrostiniResultCallback callback,
726       base::Optional<vm_tools::cicerone::StartLxdContainerResponse> response);
727 
728   // Callback for CiceroneClient::SetUpLxdContainerUser.
729   void OnSetUpLxdContainerUser(
730       const ContainerId& container_id,
731       BoolCallback callback,
732       base::Optional<vm_tools::cicerone::SetUpLxdContainerUserResponse>
733           response);
734 
735   // Callback for CiceroneClient::ExportLxdContainer.
736   void OnExportLxdContainer(
737       const ContainerId& container_id,
738       base::Optional<vm_tools::cicerone::ExportLxdContainerResponse> response);
739 
740   // Callback for CiceroneClient::ImportLxdContainer.
741   void OnImportLxdContainer(
742       const ContainerId& container_id,
743       base::Optional<vm_tools::cicerone::ImportLxdContainerResponse> response);
744 
745   // Callback for CiceroneClient::CancelExportLxdContainer.
746   void OnCancelExportLxdContainer(
747       const ContainerId& key,
748       base::Optional<vm_tools::cicerone::CancelExportLxdContainerResponse>
749           response);
750 
751   // Callback for CiceroneClient::CancelImportLxdContainer.
752   void OnCancelImportLxdContainer(
753       const ContainerId& key,
754       base::Optional<vm_tools::cicerone::CancelImportLxdContainerResponse>
755           response);
756 
757   // Callback for CiceroneClient::UpgradeContainer.
758   void OnUpgradeContainer(
759       CrostiniResultCallback callback,
760       base::Optional<vm_tools::cicerone::UpgradeContainerResponse> response);
761 
762   // Callback for CiceroneClient::CancelUpgradeContainer.
763   void OnCancelUpgradeContainer(
764       CrostiniResultCallback callback,
765       base::Optional<vm_tools::cicerone::CancelUpgradeContainerResponse>
766           response);
767 
768   // Callback for CrostiniManager::LaunchContainerApplication.
769   void OnLaunchContainerApplication(
770       CrostiniSuccessCallback callback,
771       base::Optional<vm_tools::cicerone::LaunchContainerApplicationResponse>
772           response);
773 
774   // Callback for CrostiniManager::GetContainerAppIcons. Called after the
775   // Concierge service finishes.
776   void OnGetContainerAppIcons(
777       GetContainerAppIconsCallback callback,
778       base::Optional<vm_tools::cicerone::ContainerAppIconResponse> response);
779 
780   // Callback for CrostiniManager::GetLinuxPackageInfo.
781   void OnGetLinuxPackageInfo(
782       GetLinuxPackageInfoCallback callback,
783       base::Optional<vm_tools::cicerone::LinuxPackageInfoResponse> response);
784 
785   // Callback for CrostiniManager::InstallLinuxPackage.
786   void OnInstallLinuxPackage(
787       InstallLinuxPackageCallback callback,
788       base::Optional<vm_tools::cicerone::InstallLinuxPackageResponse> response);
789 
790   // Callback for CrostiniManager::UninstallPackageOwningFile.
791   void OnUninstallPackageOwningFile(
792       CrostiniResultCallback callback,
793       base::Optional<vm_tools::cicerone::UninstallPackageOwningFileResponse>
794           response);
795 
796   // Callback for CrostiniManager::GetContainerSshKeys. Called after the
797   // Concierge service finishes.
798   void OnGetContainerSshKeys(
799       GetContainerSshKeysCallback callback,
800       base::Optional<vm_tools::concierge::ContainerSshKeysResponse> response);
801 
802   // Callback for AnsibleManagementService::ConfigureDefaultContainer
803   void OnDefaultContainerConfigured(bool success);
804 
805   // Helper for CrostiniManager::MaybeUpdateCrostini. Makes blocking calls to
806   // check for /dev/kvm.
807   static void CheckPaths();
808 
809   // Helper for CrostiniManager::MaybeUpdateCrostini. Separated because the
810   // checking component registration code may block.
811   void MaybeUpdateCrostiniAfterChecks();
812 
813   void FinishRestart(CrostiniRestarter* restarter, CrostiniResult result);
814 
815   // Callback for CrostiniManager::AbortRestartCrostini
816   void OnAbortRestartCrostini(RestartId restart_id, base::OnceClosure callback);
817 
818   // Callback for CrostiniManager::RemoveCrostini.
819   void OnRemoveCrostini(CrostiniResult result);
820 
821   void OnVmStoppedCleanup(const std::string& vm_name);
822 
823   // Configure the container so that it can sideload apps into Arc++.
824   void ConfigureForArcSideload();
825 
826   // Tries to query Concierge for the type of disk the named VM has then emits a
827   // metric logging the type. Mostly happens async and best-effort.
828   void EmitVmDiskTypeMetric(const std::string vm_name);
829 
830   Profile* profile_;
831   std::string owner_id_;
832 
833   bool skip_restart_for_testing_ = false;
834   component_updater::CrOSComponentManager::Error
835       component_manager_load_error_for_testing_ =
836           component_updater::CrOSComponentManager::Error::NONE;
837 
838   static bool is_dev_kvm_present_;
839 
840   // |is_unclean_startup_| is true when we detect Concierge still running at
841   // session startup time, and the last session ended in a crash.
842   bool is_unclean_startup_ = false;
843 
844   // Callbacks that are waiting on a signal
845   std::multimap<ContainerId, CrostiniResultCallback> start_container_callbacks_;
846   std::multimap<ContainerId, base::OnceClosure> shutdown_container_callbacks_;
847   std::multimap<ContainerId, CrostiniResultCallback>
848       create_lxd_container_callbacks_;
849   std::multimap<ContainerId, BoolCallback> delete_lxd_container_callbacks_;
850   std::map<ContainerId, ExportLxdContainerResultCallback>
851       export_lxd_container_callbacks_;
852   std::map<ContainerId, CrostiniResultCallback> import_lxd_container_callbacks_;
853 
854   // Callbacks to run after Tremplin is started, keyed by vm_name. These are
855   // used if StartTerminaVm completes but we need to wait from Tremplin to
856   // start.
857   std::multimap<std::string, base::OnceClosure> tremplin_started_callbacks_;
858 
859   // Callbacks to run after LXD is started, keyed by vm_name. Used if StartLxd
860   // completes but we need to wait for LXD to start.
861   std::map<std::string, CrostiniResultCallback> start_lxd_callbacks_;
862 
863   std::map<std::string, VmInfo> running_vms_;
864 
865   // Running containers as keyed by vm name.
866   std::multimap<std::string, ContainerInfo> running_containers_;
867 
868   // OsRelease protos keyed by ContainerId. We populate this map even if a
869   // container fails to start normally.
870   std::map<ContainerId, vm_tools::cicerone::OsRelease> container_os_releases_;
871   std::set<ContainerId> container_upgrade_prompt_shown_;
872 
873   std::vector<RemoveCrostiniCallback> remove_crostini_callbacks_;
874 
875   base::ObserverList<LinuxPackageOperationProgressObserver>::Unchecked
876       linux_package_operation_progress_observers_;
877 
878   base::ObserverList<PendingAppListUpdatesObserver>
879       pending_app_list_updates_observers_;
880 
881   base::ObserverList<ExportContainerProgressObserver>::Unchecked
882       export_container_progress_observers_;
883   base::ObserverList<ImportContainerProgressObserver>::Unchecked
884       import_container_progress_observers_;
885 
886   base::ObserverList<UpgradeContainerProgressObserver>::Unchecked
887       upgrade_container_progress_observers_;
888 
889   base::ObserverList<VmShutdownObserver> vm_shutdown_observers_;
890   base::ObserverList<chromeos::VmStartingObserver> vm_starting_observers_;
891 
892   // Only one restarter flow is actually running for a given container, other
893   // restarters will just have their callback called when the running restarter
894   // completes.
895   std::multimap<ContainerId, CrostiniManager::RestartId>
896       restarters_by_container_;
897 
898   std::map<CrostiniManager::RestartId, std::unique_ptr<CrostiniRestarter>>
899       restarters_by_id_;
900 
901   base::ObserverList<CrostiniDialogStatusObserver>
902       crostini_dialog_status_observers_;
903   base::ObserverList<CrostiniContainerPropertiesObserver>
904       crostini_container_properties_observers_;
905 
906   base::ObserverList<ContainerStartedObserver> container_started_observers_;
907   base::ObserverList<ContainerShutdownObserver> container_shutdown_observers_;
908 
909   base::ObserverList<CrostiniMicSharingEnabledObserver>
910       crostini_mic_sharing_enabled_observers_;
911 
912   base::ObserverList<CrostiniFileChangeObserver> file_change_observers_;
913 
914   // Contains the types of crostini dialogs currently open. It is generally
915   // invalid to show more than one. e.g. uninstalling and installing are
916   // mutually exclusive.
917   base::flat_set<DialogType> open_crostini_dialogs_;
918 
919   // Tracks if Crostini has access to the microphone.
920   bool crostini_mic_sharing_enabled_ = false;
921 
922   bool dbus_observers_removed_ = false;
923 
924   base::Time time_of_last_disk_type_metric_;
925 
926   std::unique_ptr<CrostiniStabilityMonitor> crostini_stability_monitor_;
927 
928   std::unique_ptr<CrostiniUpgradeAvailableNotification>
929       upgrade_available_notification_;
930 
931   TerminaInstaller termina_installer_{};
932 
933   // Note: This should remain the last member so it'll be destroyed and
934   // invalidate its weak pointers before any other members are destroyed.
935   base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_{this};
936 
937   DISALLOW_COPY_AND_ASSIGN(CrostiniManager);
938 };
939 
940 }  // namespace crostini
941 
942 #endif  // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_
943