910e62b5创建于 1月15日历史提交
// 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 DEVICE_BLUETOOTH_FLOSS_FLOSS_ADAPTER_CLIENT_H_
#define DEVICE_BLUETOOTH_FLOSS_FLOSS_ADAPTER_CLIENT_H_

#include <memory>
#include <string>

#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "dbus/exported_object.h"
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_export.h"
#include "device/bluetooth/floss/floss_dbus_client.h"
#include "device/bluetooth/floss/floss_sdp_types.h"

namespace dbus {
class ErrorResponse;
class ObjectPath;
class Response;
}  // namespace dbus

namespace floss {

// The adapter client represents a specific adapter and exposes some common
// functionality on it (such as discovery and bonding). It is managed by
// FlossClientBundle and will be initialized only when the chosen adapter is
// powered on (presence and power management is done by |FlossManagerClient|).
class DEVICE_BLUETOOTH_EXPORT FlossAdapterClient : public FlossDBusClient {
 public:
  enum class BluetoothDeviceType {
    kUnknown = 0,
    kBredr = 1,
    kBle = 2,
    kDual = 3,
  };

  enum class BluetoothSspVariant {
    kPasskeyConfirmation = 0,
    kPasskeyEntry = 1,
    kConsent = 2,
    kPasskeyNotification = 3,
  };

  enum class BondState {
    kNotBonded = 0,
    kBondingInProgress = 1,
    kBonded = 2,
  };

  enum class ConnectionState {
    kDisconnected = 0,
    kConnectedOnly = 1,
    kPairedBREDROnly = 3,
    kPairedLEOnly = 5,
    kPairedBoth = 7,
  };

  enum class BtPropertyType {
    kBdName = 0x1,
    kBdAddr,
    kUuids,
    kClassOfDevice,
    kTypeOfDevice,
    kServiceRecord,
    kAdapterScanMode,
    kAdapterBondedDevices,
    kAdapterDiscoverableTimeout,
    kRemoteFriendlyName,
    kRemoteRssi,
    kRemoteVersionInfo,
    kLocalLeFeatures,
    kLocalIoCaps,
    kLocalIoCapsBle,
    kDynamicAudioBuffer,
    kRemoteIsCoordinatedSetMember,
    kAppearance,
    kVendorProductInfo,
    // Unimplemented:
    //  BT_PROPERTY_WL_MEDIA_PLAYERS_LIST,
    //  BT_PROPERTY_REMOTE_ASHA_CAPABILITY,
    //  BT_PROPERTY_REMOTE_ASHA_TRUNCATED_HISYNCID,
    //  BT_PROPERTY_REMOTE_MODEL_NUM,
    kRemoteAddrType = 0x18,

    kUnknown = 0xFE,
    kRemoteDeviceTimestamp = 0xFF,
  };

  enum class BtDiscoverableMode : uint32_t {
    kNonDiscoverable = 0,
    kLimitedDiscoverable = 1,
    kGeneralDiscoverable = 2,
  };

  enum class BtAddressType {
    kPublic = 0,
    kRandom,
    kPublicId,
    kRandomId,
    kUnknown = 0xfe,
    kAnonymous = 0xff,
  };

  enum class BtAdapterRole {
    kCentral = 0,
    kPeripheral,
    kCentralPeripheral,
  };

  struct VendorProductInfo {
    uint8_t vendorIdSrc;
    uint16_t vendorId;
    uint16_t productId;
    uint16_t version;
    VendorProductInfo()
        : vendorIdSrc(
              device::BluetoothDevice::VendorIDSource::VENDOR_ID_UNKNOWN),
          vendorId(),
          productId(),
          version() {}
  };

  class Observer : public base::CheckedObserver {
   public:
    Observer(const Observer&) = delete;
    Observer& operator=(const Observer&) = delete;

    Observer() = default;
    ~Observer() override = default;

    // Notification sent when the adapter address has changed.
    virtual void AdapterAddressChanged(const std::string& address) {}

    // Notification sent when the adapter address has changed.
    virtual void DiscoverableChanged(bool discoverable) {}

    // Notification sent when the discovering state has changed.
    virtual void AdapterDiscoveringChanged(bool state) {}

    // Notification sent when discovery has found a device. This notification
    // is not guaranteed to be unique per Chrome discovery session (i.e. you can
    // get the same device twice).
    virtual void AdapterFoundDevice(const FlossDeviceId& device_found) {}

    // Notification sent when a found device is cleared. It will be sent when
    // a device found during discovery is determined to be stale (was last seen
    // some amount of time ago).
    virtual void AdapterClearedDevice(const FlossDeviceId& device_cleared) {}

    // Notification sent when a found device has forgotten its keys or been
    // reset. It will be sent when bond loss is detected.
    virtual void AdapterKeyMissingDevice(const FlossDeviceId& device) {}

    // Notification sent when a device property has changed.
    virtual void AdapterDevicePropertyChanged(BtPropertyType prop_type,
                                              const FlossDeviceId& device) {}

    // Notification sent for Simple Secure Pairing.
    virtual void AdapterSspRequest(const FlossDeviceId& remote_device,
                                   uint32_t cod,
                                   BluetoothSspVariant variant,
                                   uint32_t passkey) {}

    // Notification sent for legacy pairing to display auto-gen pin code.
    virtual void AdapterPinDisplay(const FlossDeviceId& remote_device,
                                   std::string pincode) {}

    // Notification sent for legacy pairing to ask user input pin code.
    virtual void AdapterPinRequest(const FlossDeviceId& remote_device,
                                   uint32_t cod,
                                   bool min_16_digit) {}

    // Notification sent when a bonding state changes for a remote device.
    // TODO(b:202334519): Change status type to enum once Floss has the enum.
    virtual void DeviceBondStateChanged(const FlossDeviceId& remote_device,
                                        uint32_t status,
                                        BondState bond_state) {}

    // Notification sent when a remote device becomes connected.
    virtual void AdapterDeviceConnected(const FlossDeviceId& device) {}

    // Notification sent when a remote device becomes disconnected.
    virtual void AdapterDeviceDisconnected(const FlossDeviceId& device) {}

    // Notification sent when a remote device fails to connect.
    virtual void AdapterDeviceConnectionFailed(const FlossDeviceId& device,
                                               uint32_t status) {}

    // Notification sent when requested SDP search has completed.
    virtual void SdpSearchComplete(const FlossDeviceId device,
                                   const device::BluetoothUUID uuid,
                                   const std::vector<BtSdpRecord>& records) {}

    // Notification sent when an SDP record has finished being created and
    // assigned a handle.
    virtual void SdpRecordCreated(const BtSdpRecord record,
                                  const int32_t handle) {}
  };

  // Error: No such adapter.
  static const char kErrorUnknownAdapter[];

  // Creates the instance.
  static std::unique_ptr<FlossAdapterClient> Create();

  // Checks if a connection state indicates that it is paired.
  static bool IsConnectionPaired(uint32_t connection_state);

  FlossAdapterClient(const FlossAdapterClient&) = delete;
  FlossAdapterClient& operator=(const FlossAdapterClient&) = delete;

  FlossAdapterClient();
  ~FlossAdapterClient() override;

  // Manage observers.
  void AddObserver(Observer* observer);
  bool HasObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // Get the address of this adapter.
  const std::string& GetAddress() const { return property_address_.Get(); }

  // Get the name of this adapter.
  const std::string& GetName() const { return property_name_.Get(); }

  // Set the name of this adapter.
  virtual void SetName(ResponseCallback<Void> callback,
                       const std::string& name);

  // Get whether adapter is discoverable.
  bool GetDiscoverable() const { return property_discoverable_.Get(); }

  // Set whether adapter is discoverable.
  virtual void SetDiscoverable(ResponseCallback<Void> callback,
                               bool discoverable);

  // Set adapter discoverability mode.
  virtual void SetDiscoverable(ResponseCallback<Void> callback,
                               BtDiscoverableMode mode,
                               uint32_t duration);

  // Get the discoverable timeout for the adapter. Updates whenever the
  // discoverable state changes.
  uint32_t GetDiscoverableTimeout() const { return discoverable_timeout_; }

  // Indicates if LE extended advertising is supported.
  bool IsExtAdvSupported() const { return property_ext_adv_supported_.Get(); }

  // Start a discovery session.
  virtual void StartDiscovery(ResponseCallback<Void> callback);

  // Cancel the active discovery session.
  virtual void CancelDiscovery(ResponseCallback<Void> callback);

  // Create a bond with the given device and transport.
  virtual void CreateBond(ResponseCallback<bool> callback,
                          FlossDeviceId device,
                          BluetoothTransport transport);

  // Create a bond with the given device and transport. API version >= 0.4.0,
  // add callback status.
  virtual void CreateBond(
      ResponseCallback<FlossDBusClient::BtifStatus> callback,
      FlossDeviceId device,
      BluetoothTransport transport);

  // Cancel a bond process.
  virtual void CancelBondProcess(ResponseCallback<bool> callback,
                                 FlossDeviceId device);

  // Removes bonding.
  virtual void RemoveBond(ResponseCallback<bool> callback,
                          FlossDeviceId device);

  // Gets the transport type of the device.
  virtual void GetRemoteType(ResponseCallback<BluetoothDeviceType> callback,
                             FlossDeviceId device);

  // Gets class of a device.
  virtual void GetRemoteClass(ResponseCallback<uint32_t> callback,
                              FlossDeviceId device);

  // Gets appearance of a device.
  virtual void GetRemoteAppearance(ResponseCallback<uint16_t> callback,
                                   FlossDeviceId device);

  // Get connection state of a device.
  // TODO(b/202334519): Change return type to enum instead of u32
  virtual void GetConnectionState(ResponseCallback<uint32_t> callback,
                                  const FlossDeviceId& device);

  // Gets UUIDs of a device.
  virtual void GetRemoteUuids(
      ResponseCallback<device::BluetoothDevice::UUIDList> callback,
      FlossDeviceId device);

  // Triggers SDP to fetch UUIDs of a device.
  virtual void FetchRemoteUuids(ResponseCallback<bool> callback,
                                FlossDeviceId device);

  // Gets the Vendor and Product Id of a device
  virtual void GetRemoteVendorProductInfo(
      ResponseCallback<VendorProductInfo> callback,
      FlossDeviceId device);

  // Gets the address type of a device
  virtual void GetRemoteAddressType(ResponseCallback<BtAddressType> callback,
                                    FlossDeviceId device);

  // Get bonding state of a device.
  virtual void GetBondState(ResponseCallback<uint32_t> callback,
                            const FlossDeviceId& device);

  // Connect to all enabled profiles.
  virtual void ConnectAllEnabledProfiles(ResponseCallback<Void> callback,
                                         const FlossDeviceId& device);

  // Connect to all enabled profiles. API version >= 0.4.0, add callback status.
  virtual void ConnectAllEnabledProfiles(
      ResponseCallback<FlossDBusClient::BtifStatus> callback,
      const FlossDeviceId& device);

  // Disconnect all enabled profiles.
  virtual void DisconnectAllEnabledProfiles(ResponseCallback<Void> callback,
                                            const FlossDeviceId& device);

  // Indicates whether the user approves the pairing, if accepted then a pairing
  // should be completed on the remote device.
  virtual void SetPairingConfirmation(ResponseCallback<Void> callback,
                                      const FlossDeviceId& device,
                                      bool accept);

  // Indicates whether the user approves the pairing with the given pin.
  virtual void SetPin(ResponseCallback<Void> callback,
                      const FlossDeviceId& device,
                      bool accept,
                      const std::vector<uint8_t>& pin);

  // Indicates whether the user approves the pairing with the given passkey.
  virtual void SetPasskey(ResponseCallback<Void> callback,
                          const FlossDeviceId& device,
                          bool accept,
                          const std::vector<uint8_t>& passkey);

  // Returns bonded devices.
  virtual void GetBondedDevices();

  // Returns connected devices.
  virtual void GetConnectedDevices();

  // Initiate an SDP search on device for uuid. Search results provided through
  // |OnSdpSearchComplete|.
  virtual void SdpSearch(ResponseCallback<bool> callback,
                         const FlossDeviceId& device,
                         device::BluetoothUUID uuid);

  // Create a new SDP record in this device's SDP server. Record handle is
  // returned via |SdpRecordCreated|.
  virtual void CreateSdpRecord(ResponseCallback<bool> callback,
                               const BtSdpRecord& record);

  // Remove an SDP record by its record handle.
  virtual void RemoveSdpRecord(ResponseCallback<bool> callback,
                               const int32_t& handle);

  std::vector<BtAdapterRole> GetSupportedRoles() {
    return property_roles_.Get();
  }

  // Get the object path for this adapter.
  const dbus::ObjectPath* GetObjectPath() const { return &adapter_path_; }

  // Initialize the adapter client.
  void Init(dbus::Bus* bus,
            const std::string& service_name,
            const int adapter_index,
            base::Version version,
            base::OnceClosure on_ready) override;

 protected:
  friend class FlossAdapterClientTest;

  // Handle callback |OnAdapterPropertyChanged| on exported object path.
  void OnAdapterPropertyChanged(
      dbus::MethodCall* method_call,
      dbus::ExportedObject::ResponseSender response_sender);

  // When address property is updated.
  void OnAddressChanged(const std::string& address);

  // When name property is updated.
  void OnNameChanged(const std::string& name);

  // When discoverable property is updated.
  void OnDiscoverableChanged(const bool& discoverable);

  // Handle callback |OnDiscoveringChanged| on exported object path.
  void OnDiscoveringChanged(
      dbus::MethodCall* method_call,
      dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDeviceFound| on exported object path.
  void OnDeviceFound(dbus::MethodCall* method_call,
                     dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDeviceCleared| on exported object path.
  void OnDeviceCleared(dbus::MethodCall* method_call,
                       dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDeviceKeyMissing| on exported object path.
  void OnDeviceKeyMissing(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDevicePropertiesChanged| on exported object path.
  void OnDevicePropertiesChanged(
      dbus::MethodCall* method_call,
      dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnSspRequest| on exported object path.
  void OnSspRequest(dbus::MethodCall* method_call,
                    dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnPinDisplay| on exported object path.
  void OnPinDisplay(dbus::MethodCall* method_call,
                    dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnPinRequest| on exported object path.
  void OnPinRequest(dbus::MethodCall* method_call,
                    dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnBondStateChanged| on exported object path.
  void OnBondStateChanged(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnSdpSearchComplete| on exported object path.
  void OnSdpSearchComplete(
      dbus::MethodCall* method_call,
      dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnSdpRecordCreated| on exported object path.
  void OnSdpRecordCreated(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDeviceConnected| on exported object path.
  void OnDeviceConnected(dbus::MethodCall* method_call,
                         dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDeviceDisconnected| on exported object path.
  void OnDeviceDisconnected(
      dbus::MethodCall* method_call,
      dbus::ExportedObject::ResponseSender response_sender);

  // Handle callback |OnDeviceConnectionFailed| on exported object path.
  void OnDeviceConnectionFailed(
      dbus::MethodCall* method_call,
      dbus::ExportedObject::ResponseSender response_sender);

  // Handle GetBondedDevices.
  void OnGetBondedDevices(DBusResult<std::vector<FlossDeviceId>> ret);

  // Handle GetConnectedDevices.
  void OnGetConnectedDevices(DBusResult<std::vector<FlossDeviceId>> ret);

  // Calls GetDiscoverableTimeout.
  void UpdateDiscoverableTimeout();

  // Handle GetDiscoverableTimeout and cache the returned value.
  void OnDiscoverableTimeout(DBusResult<uint32_t> ret);

  // Handle |RegisterCallback| result and store callback ID.
  void OnRegisterCallback(DBusResult<uint32_t> ret);

  // Handle |RegisterConnectionCallback| result and store callback ID.
  void OnRegisterConnectionCallback(DBusResult<uint32_t> ret);

  // Handle both |UnregisterCallback| and |UnregisterConnectionCallback|.
  void OnUnregisterCallbacks(DBusResult<bool> ret);

  // List of observers interested in event notifications from this client.
  base::ObserverList<Observer> observers_;

  // Managed by FlossDBusManager - we keep local pointer to access object proxy.
  raw_ptr<dbus::Bus> bus_ = nullptr;

  // Adapter managed by this client.
  dbus::ObjectPath adapter_path_;

  // Service which implements the adapter interface.
  std::string service_name_;

  // Object path for exported callbacks registered to this client.
  std::string exported_callback_path_;

  // Cached discoverable timeout value (updates on init and on discoverable
  // state changes).
  uint32_t discoverable_timeout_ = 0;

 private:
  FRIEND_TEST_ALL_PREFIXES(FlossAdapterClientTest, CallAdapterMethods);

  template <typename R, typename... Args>
  void CallAdapterMethod(ResponseCallback<R> callback,
                         const char* member,
                         Args... args) {
    CallMethod(std::move(callback), bus_, service_name_, kAdapterInterface,
               adapter_path_, member, args...);
  }

  FlossProperty<std::string> property_address_{
      kAdapterInterface, adapter::kCallbackInterface, adapter::kGetAddress,
      adapter::kOnAddressChanged};

  FlossProperty<std::string> property_name_{
      kAdapterInterface, adapter::kCallbackInterface, adapter::kGetName,
      adapter::kOnNameChanged};

  FlossProperty<bool> property_discoverable_{
      kAdapterInterface, adapter::kCallbackInterface, adapter::kGetDiscoverable,
      adapter::kOnDiscoverableChanged};

  FlossProperty<bool> property_ext_adv_supported_{
      kAdapterInterface, adapter::kCallbackInterface,
      adapter::kIsLeExtendedAdvertisingSupported, nullptr};

  FlossProperty<std::vector<BtAdapterRole>> property_roles_{
      kAdapterInterface, adapter::kCallbackInterface,
      adapter::kGetSupportedRoles, nullptr};

  // Object path for exported callbacks registered against adapter interface.
  static const char kExportedCallbacksPath[];

  // Signal when client is ready to be used.
  base::OnceClosure on_ready_;

  // Number of callbacks pending registration before client is ready to use.
  int pending_register_calls_ = 0;

  // Callback ID used for callbacks registered to this client.
  std::optional<uint32_t> callback_id_;

  // Callback ID used for connection callbacks registered to this client.
  std::optional<uint32_t> connection_callback_id_;

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

}  // namespace floss

#endif  // DEVICE_BLUETOOTH_FLOSS_FLOSS_ADAPTER_CLIENT_H_