chromium/chromeos/ash/components/peripheral_notification/peripheral_notification_manager.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 CHROMEOS_ASH_COMPONENTS_PERIPHERAL_NOTIFICATION_PERIPHERAL_NOTIFICATION_MANAGER_H_
#define CHROMEOS_ASH_COMPONENTS_PERIPHERAL_NOTIFICATION_PERIPHERAL_NOTIFICATION_MANAGER_H_

#include <memory>

#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "chromeos/ash/components/dbus/pciguard/pciguard_client.h"
#include "chromeos/ash/components/dbus/typecd/typecd_client.h"
#include "third_party/cros_system_api/dbus/typecd/dbus-constants.h"

namespace device {
namespace mojom {
class UsbDeviceInfo;
}  // namespace mojom
}  // namespace device

namespace ash {

// This class is responsible for listening to TypeCd and Pciguard D-Bus calls
// and translating those signals to notification observer events. It handles
// additional logic such determining if notifications are required or whether a
// guest-session notification is needed.
class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_PERIPHERAL_NOTIFICATION)
    PeripheralNotificationManager : public TypecdClient::Observer,
                                    public PciguardClient::Observer {
 public:
  class Observer : public base::CheckedObserver {
   public:
    ~Observer() override = default;

    // Called to notify observers, primarily notification controllers, that a
    // recently plugged in Thunderbolt/USB4 device is running at limited
    // performance. This can be called multiple times.
    virtual void OnLimitedPerformancePeripheralReceived() = 0;

    // Called to notify observers, primarily notification controllers, that a
    // Thunderbolt/USB4 device has been plugged in during a guest session. Can
    // be called multiple times.
    virtual void OnGuestModeNotificationReceived(bool is_thunderbolt_only) = 0;

    // Called to notify observers, primarily notification controllers, that the
    // recently plugged in Thunderbolt/USB4 device is in the block list. The
    // block list is specified by the Pciguard Daemon.
    virtual void OnPeripheralBlockedReceived() = 0;

    // Called to notify observers, primarily notification controllers, that the
    // recently plugged in Thunderbolt/USB4 device is a billboard device that is
    // not supported by the board.
    virtual void OnBillboardDeviceConnected() = 0;

    // Called to notify user of possibly invalid dp cable. This signal will be
    // sent by typecd when the partner meets the conditions for DP alternate
    // mode, but the cable does not.
    virtual void OnInvalidDpCableWarning() = 0;

    // Called to notify the user that their USB4 device is unable to establish a
    // USB4 connection because of the cable. In this case, the connection will
    // fall back to Thunderbolt.
    virtual void OnInvalidUSB4ValidTBTCableWarning() = 0;

    // Called to notify the user that their USB4 device is unable to establish a
    // USB4 connection because of the cable. It is similar to
    // OnUSB4ToThundeboltCableWarning, but in this case the connection will
    // fall back to DisplayPort, USB 3.2 or USB 2.0.
    virtual void OnInvalidUSB4CableWarning() = 0;

    // Called to notify the user that their Thubderbolt device is unable to
    // establish a Thunderbolt connection, and will instead use DisplayPort,
    // USB 3.2 or USB 2.0.
    virtual void OnInvalidTBTCableWarning() = 0;

    // Called to notify the user when their 40 Gbps USB4 device is unable to use
    // 40 Gbps data transmission because of the cable. Transmissions speeds will
    // decrease to 20 Gbps, 10 Gbps or 5 Gbps.
    virtual void OnSpeedLimitingCableWarning() = 0;
  };

  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused.
  enum class PeripheralConnectivityResults {
    kTBTSupportedAndAllowed = 0,
    kTBTOnlyAndBlockedByPciguard = 1,
    kTBTOnlyAndBlockedInGuestSession = 2,
    kAltModeFallbackDueToPciguard = 3,
    kAltModeFallbackInGuestSession = 4,
    kPeripheralBlocked = 5,
    kBillboardDevice = 6,
    kInvalidDpCable = 7,
    kInvalidUSB4ValidTBTCable = 8,
    kInvalidUSB4Cable = 9,
    kInvalidTBTCable = 10,
    kSpeedLimitingCable = 11,
    kMaxValue = kSpeedLimitingCable,
  };

  // Sets the global instance. Must be called before any calls to Get().
  static void Initialize(bool is_guest_profile, bool is_pcie_tunneling_allowed);

  // Destroys the global instance.
  static void Shutdown();

  // Gets the global instance pointer.
  static PeripheralNotificationManager* Get();

  // Returns true if the global instance is initialized.
  static bool IsInitialized();

  void SetPcieTunnelingAllowedState(bool is_pcie_tunneling_allowed);

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  void OnDeviceConnected(device::mojom::UsbDeviceInfo* device);

 private:
  friend class PeripheralNotificationManagerTest;

  PeripheralNotificationManager(bool is_guest_profile,
                                bool is_pcie_tunneling_allowed);
  PeripheralNotificationManager(const PeripheralNotificationManager&) = delete;
  PeripheralNotificationManager& operator=(
      const PeripheralNotificationManager&) = delete;
  ~PeripheralNotificationManager() override;

  // TypecdClient::Observer:
  void OnThunderboltDeviceConnected(bool is_thunderbolt_only) override;
  void OnCableWarning(typecd::CableWarningType cable_warning_type) override;

  // PciguardClient::Observer:
  void OnBlockedThunderboltDeviceConnected(
      const std::string& device_name) override;

  // Call to notify observers that a new notification is needed.
  void NotifyLimitedPerformancePeripheralReceived();
  void NotifyGuestModeNotificationReceived(bool is_thunderbolt_only);
  void NotifyPeripheralBlockedReceived();
  void OnBillboardDeviceConnected(bool billboard_is_supported);
  void NotifyInvalidDpCable();
  void NotifyInvalidUSB4ValidTBTCableWarning();
  void NotifyInvalidUSB4CableWarning();
  void NotifyInvalidTBTCableWarning();
  void NotifySpeedLimitingCableWarning();

  // Called by unit tests to set up root_prefix_ for simulating the existence
  // of a system folder.
  void SetRootPrefixForTesting(const std::string& prefix);

  const bool is_guest_profile_;
  // Pcie tunneling refers to allowing Thunderbolt/USB4 peripherals to run at
  // full capacity by utilizing the PciExpress protocol. If this is set to
  // false, we anticipate that the plugged in Thunderbolt/USB4 periphal is
  // operating at either Alt-mode (i.e. fallback to an older protocol) or
  // in a restricted state (e.g. certain devices are Thunderbolt only).
  bool is_pcie_tunneling_allowed_;
  base::ObserverList<Observer> observer_list_;

  std::string root_prefix_ = "";

  // Used for callbacks.
  base::WeakPtrFactory<PeripheralNotificationManager> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // CHROMEOS_ASH_COMPONENTS_PERIPHERAL_NOTIFICATION_PERIPHERAL_NOTIFICATION_MANAGER_H_