chromium/chrome/browser/ash/bruschetta/bruschetta_service.h

// Copyright 2022 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_BRUSCHETTA_BRUSCHETTA_SERVICE_H_
#define CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_SERVICE_H_

#include <string_view>

#include "base/callback_list.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/bruschetta/bruschetta_util.h"
#include "chrome/browser/ash/guest_os/guest_id.h"
#include "chrome/browser/ash/guest_os/guest_os_remover.h"
#include "chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h"
#include "chrome/browser/ash/guest_os/public/guest_os_terminal_provider_registry.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"

class Profile;

namespace bruschetta {

class BruschettaLauncher;

// A service to hold the separate modules that provide Bruschetta
// (third-party/generic VM) support within Chrome (files app integration, app
// service integration, etc).
class BruschettaService : public KeyedService,
                          public ash::ConciergeClient::VmObserver {
 public:
  explicit BruschettaService(Profile* profile);
  ~BruschettaService() override;

  // Helper method to get the service instance for the given profile.
  static BruschettaService* GetForProfile(Profile* profile);

  // Register an existing bruschetta instance with the terminal app.
  void RegisterWithTerminal(const guest_os::GuestId& guest_id);

  // Register a new bruschetta instance in prefs. `config_id` controls which
  // enterprise policy manages this instance.
  void RegisterInPrefs(const guest_os::GuestId& guest_id,
                       const std::string& config_id);

  // Register `vm_name` as running with the specified enterprise policy. This is
  // a no-op if called for a VM we already believe to be running. In particular,
  // in that case the VM is considered to keep its old policy, not the new one
  // passed in.
  void RegisterVmLaunch(std::string vm_name, RunningVmPolicy policy);

  // Returns a handle to the launcher for the vm specified by `vm_name`. Will
  // return a null pointer if the name isn't recognised.
  base::WeakPtr<BruschettaLauncher> GetLauncher(std::string vm_name);

  // ConciergeClient::VmObserver:
  void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override;
  void OnVmStopped(const vm_tools::concierge::VmStoppedSignal& signal) override;

  void SetLauncherForTesting(std::string vm_name,
                             std::unique_ptr<BruschettaLauncher> launcher);

  const base::flat_map<std::string, RunningVmPolicy>& GetRunningVmsForTesting();

  // Uninstalls the Bruschetta vm identified by `guest_id`. No-op if already
  // completely uninstalled, can run after a failed uninstall to finish cleaning
  // up.
  void RemoveVm(const guest_os::GuestId& guest_id,
                base::OnceCallback<void(bool)> callback);

  // Checks if the vm identified by `vm_name` is in the running list.
  bool IsVmRunning(std::string_view vm_name);

  // Stops all running VMs.
  void StopRunningVms();

 private:
  struct VmRegistration {
    std::unique_ptr<BruschettaLauncher> launcher;
    guest_os::GuestOsMountProviderRegistry::Id mount_id;
    // We don't track the terminal registration because that should remain in
    // place even if the VM is blocked from launching.

    VmRegistration(std::unique_ptr<BruschettaLauncher> launcher,
                   guest_os::GuestOsMountProviderRegistry::Id mount_id);
    VmRegistration(VmRegistration&&);
    VmRegistration& operator=(VmRegistration&&);
    VmRegistration(const VmRegistration&) = delete;
    VmRegistration& operator=(const VmRegistration&) = delete;
    ~VmRegistration();
  };

  void OnPolicyChanged();
  void AllowLaunch(guest_os::GuestId guest_id);
  void BlockLaunch(guest_os::GuestId guest_id);
  void StopVm(std::string vm_name);

  void StopVmIfRequiredByPolicy(std::string vm_name,
                                std::string config_id,
                                const base::Value::Dict* config);

  void OnRemoveVm(base::OnceCallback<void(bool)> callback,
                  guest_os::GuestId guest_id,
                  guest_os::GuestOsRemover::Result result);
  void OnUninstallToolsDlc(base::OnceCallback<void(bool)> callback,
                           guest_os::GuestId guest_id,
                           std::string_view result);
  void OnUninstallAllDlcs(base::OnceCallback<void(bool)> callback,
                          guest_os::GuestId guest_id,
                          std::string_view tools_result,
                          std::string_view firmware_result);

  base::flat_map<std::string, VmRegistration> runnable_vms_;
  base::flat_map<std::string, RunningVmPolicy> running_vms_;

  // Terminal providers are special, since even non-runnable VMs should still
  // show up in the terminal, so we track them separately instead of as part of
  // runnable_vms_.
  base::flat_map<std::string, guest_os::GuestOsTerminalProviderRegistry::Id>
      terminal_providers_;

  PrefChangeRegistrar pref_observer_;
  base::CallbackListSubscription cros_settings_observer_;

  const raw_ptr<Profile> profile_;

  // Must be last
  base::WeakPtrFactory<BruschettaService> weak_ptr_factory_{this};
};

}  // namespace bruschetta

#endif  // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_SERVICE_H_