chromium/ash/components/arc/session/arc_dlc_installer.h

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_COMPONENTS_ARC_SESSION_ARC_DLC_INSTALLER_H_
#define ASH_COMPONENTS_ARC_SESSION_ARC_DLC_INSTALLER_H_

#include <string_view>

#include "base/barrier_closure.h"
#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"

namespace arc {

// Name of the Houdini (Android R) DLC.
// Defined in this file so that unit test can also access it.
constexpr char kHoudiniRvcDlc[] = "houdini-rvc-dlc";

// ArcDlcInstaller is responsible for installing and uninstalling ARC DLCs
// by using the ash::DlcserviceClient. The caller can also wait
// for the installation to complete by supplying a callback function.
//
// Semantics:
// 1. ARC DLCs installation/uninstallation can only be initiated by
// external callers using RequestEnable() and RequestDisable().
// RequestEnable(): Will trigger ARC DLCs installation immediately
// if the current state is kUninstalled.
// RequestDisable(): Will trigger ARC DLCs uninstallation immediately
// if the current state is kInstalled.
// 2. When the current state is kInstalling or kUninstalling in (1),
// it will not trigger any additional actions in parallel. Instead, it
// will just flip the is_dlc_enabled_ flag and wait for the end state
// to be reached (kInstalled/kUninstalled) first before determining the
// next action. This handles the edge case when RequestEnable() and
// RequestDisable() are being called repeatedly.
// 3. After reaching the end state (kInstalled/kUninstalled),
// is_dlc_enabled_ will be checked again to determine whether ARC DLCs
// needs to be installed/uninstalled again.
// 4. After reaching the end state (kInstalled/kUninstalled),
// InvokeCallbacks() will be called to unblock any waiters. Waiters are
// always called in the sequence they are added.
class ArcDlcInstaller {
 public:
  ArcDlcInstaller();
  ArcDlcInstaller(const ArcDlcInstaller&) = delete;
  ArcDlcInstaller& operator=(const ArcDlcInstaller&) = delete;
  ~ArcDlcInstaller();

  // Retrieves the global pointer to ArcDlcInstaller instance.
  static ArcDlcInstaller* Get();
  // Enables ARC DLCs. Will trigger ARC DLCs installation if current state is
  // kUninstalled.
  void RequestEnable();
  // Disables ARC DLCs. Will trigger ARC DLCs uninstallation if current state is
  // kInstalled.
  void RequestDisable();
  // Allows the caller to wait for the installation to complete by
  // supplying a callback function.
  void WaitForStableState(base::OnceClosure callback);

  enum class InstallerState {
    // Currently installing ARC DLCs.
    kInstalling,
    // ARC DLC installation has completed.
    kInstalled,
    // Currently uninstalling ARC DLCs.
    kUninstalling,
    // ARC DLC uninstallation has completed.
    kUninstalled,
  };

  // Getters and setters for unit testing.
  InstallerState GetStateForTesting() { return state_; }
  void SetStateForTesting(InstallerState s) { state_ = s; }
  bool GetIsDlcEnabledForTesting() { return is_dlc_enabled_; }

 private:
  // Installs all the ARC DLCs defined in this class. Currently
  // kHoudiniRvcDlc only.
  void Install();

  // Callback function when all the ARC DLC has completed
  // installation.
  void OnDlcInstalled(
      std::string_view dlc,
      const ash::DlcserviceClient::InstallResult& install_result);

  // Uninstalls all the installed ARC DLCs.
  void Uninstall();

  // Callback function when all the ARC DLC has completed
  // uninstallation.
  void OnDlcUninstalled(std::string_view dlc, std::string_view err);

  // Invokes and clears the list of callbacks in callback_list_.
  void InvokeCallbacks();

  // Indicates if ARC DLCs are enabled.
  bool is_dlc_enabled_ = false;

  // Stores the current installation / uninstallation state.
  InstallerState state_ = InstallerState::kUninstalled;

  // Stores the list of callbacks passed to WaitForStableState().
  std::vector<base::OnceClosure> callback_list_;

  base::WeakPtrFactory<ArcDlcInstaller> weak_ptr_factory_{this};
};

}  // namespace arc

#endif  // ASH_COMPONENTS_ARC_SESSION_ARC_DLC_INSTALLER_H_