blob: d187dd384d5678234ef20d0c8a87506c0c9c252c [file] [log] [blame]
// 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_