#ifndef CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_SERVICE_IMPL_H_
#define CONTENT_BROWSER_BLUETOOTH_WEB_BLUETOOTH_SERVICE_IMPL_H_
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "content/browser/bad_message.h"
#include "content/browser/bluetooth/web_bluetooth_pairing_manager_delegate.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/bluetooth_delegate.h"
#include "content/public/browser/bluetooth_scanning_prompt.h"
#include "content/public/browser/document_user_data.h"
#include "content/public/browser/web_contents_observer.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
namespace url {
class Origin;
}
namespace device {
class BluetoothDiscoverySession;
class BluetoothGattConnection;
class BluetoothGattNotifySession;
class BluetoothRemoteGattCharacteristic;
class BluetoothUUID;
}
namespace content {
class BluetoothAllowedDevices;
class BluetoothDeviceChooserController;
class BluetoothDeviceScanningPromptController;
struct CacheQueryResult;
class FrameConnectedBluetoothDevices;
struct GATTNotifySessionAndCharacteristicClient;
class RenderProcessHost;
class WebBluetoothPairingManager;
bool HasValidFilter(
const std::optional<std::vector<blink::mojom::WebBluetoothLeScanFilterPtr>>&
filters);
class CONTENT_EXPORT WebBluetoothServiceImpl
: public blink::mojom::WebBluetoothService,
public DocumentUserData<WebBluetoothServiceImpl>,
public WebContentsObserver,
public device::BluetoothAdapter::Observer,
public BluetoothDelegate::FramePermissionObserver,
public WebBluetoothPairingManagerDelegate {
public:
static blink::mojom::WebBluetoothResult TranslateConnectErrorAndRecord(
device::BluetoothDevice::ConnectErrorCode error_code);
static void BindIfAllowed(
RenderFrameHost* render_frame_host,
mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver);
static WebBluetoothServiceImpl* CreateForTesting(
RenderFrameHost* render_frame_host,
mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver);
static void IgnoreVisibilityRequirementsForTesting();
~WebBluetoothServiceImpl() override;
WebBluetoothServiceImpl(const WebBluetoothServiceImpl&) = delete;
WebBluetoothServiceImpl& operator=(const WebBluetoothServiceImpl&) = delete;
void ReceivedBadMessage(bad_message::BadMessageReason reason);
blink::mojom::WebBluetoothResult GetBluetoothAllowed();
bool IsDevicePaired(const std::string& device_address);
void OnBluetoothScanningPromptEvent(
BluetoothScanningPrompt::Event event,
BluetoothDeviceScanningPromptController* prompt_controller);
void OnPermissionRevoked(const url::Origin& origin) override;
content::RenderFrameHost* GetRenderFrameHost() override;
#if PAIR_BLUETOOTH_ON_DEMAND()
void SetPairingManagerForTesting(
std::unique_ptr<WebBluetoothPairingManager> pairing_manager);
#endif
private:
friend DocumentUserData;
DOCUMENT_USER_DATA_KEY_DECL();
explicit WebBluetoothServiceImpl(RenderFrameHost* render_frame_host);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
DestroyedDuringRequestDevice);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
DestroyedDuringRequestScanningStart);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest, PermissionAllowed);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
PermissionPromptCanceled);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
BluetoothScanningPermissionRevokedWhenTabHidden);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
BluetoothScanningPermissionRevokedWhenTabOccluded);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
BluetoothScanningPermissionRevokedWhenBlocked);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
BluetoothScanningPermissionRevokedWhenFocusIsLost);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
ReadCharacteristicValueErrorWithValueIgnored);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplBrowserTest,
NoShowBluetoothScanningPromptInPrerendering);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
DeferredStartNotifySession);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest, DeviceDisconnected);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
DeviceGattServicesDiscoveryTimeout);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
TwoWatchAdvertisementsReqSuccess);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
TwoWatchAdvertisementsReqFail);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
SecWatchAdvertisementsReqAfterFirstSuccess);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTestWithBaseAdapter,
EmulatedAdapterRemovalRestoresOriginalAdapter);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
ServiceDestroyedDuringAdapterAcquisition);
#if PAIR_BLUETOOTH_ON_DEMAND()
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
ReadCharacteristicValueNotAuthorized);
FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
IncompletePairingOnShutdown);
#endif
friend class FrameConnectedBluetoothDevicesTest;
friend class WebBluetoothServiceImplTest;
friend class WebBluetoothServiceImplTestWithBaseAdapter;
using PrimaryServicesRequestCallback =
base::OnceCallback<void(device::BluetoothDevice*)>;
using ScanFilters = std::vector<blink::mojom::WebBluetoothLeScanFilterPtr>;
class AdvertisementClient;
class WatchAdvertisementsClient;
class ScanningClient;
struct DeferredStartNotificationData;
bool Bind(mojo::PendingReceiver<blink::mojom::WebBluetoothService> receiver);
void OnVisibilityChanged(Visibility visibility) override;
void OnWebContentsLostFocus(RenderWidgetHost* render_widget_host) override;
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) override;
void DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
void DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
void DeviceAdvertisementReceived(
const std::string& device_address,
const std::optional<std::string>& device_name,
const std::optional<std::string>& advertisement_name,
std::optional<int8_t> rssi,
std::optional<int8_t> tx_power,
std::optional<uint16_t> appearance,
const device::BluetoothDevice::UUIDList& advertised_uuids,
const device::BluetoothDevice::ServiceDataMap& service_data_map,
const device::BluetoothDevice::ManufacturerDataMap& manufacturer_data_map)
override;
void GattServicesDiscovered(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
void GattCharacteristicValueChanged(
device::BluetoothAdapter* adapter,
device::BluetoothRemoteGattCharacteristic* characteristic,
const std::vector<uint8_t>& value) override;
void NotifyCharacteristicValueChanged(
const std::string& characteristic_instance_id,
const std::vector<uint8_t>& value);
void GetAvailability(GetAvailabilityCallback callback) override;
void RequestDevice(blink::mojom::WebBluetoothRequestDeviceOptionsPtr options,
RequestDeviceCallback callback) override;
void GetDevices(GetDevicesCallback callback) override;
void ForgetDevice(const blink::WebBluetoothDeviceId& device_id,
ForgetDeviceCallback callback) override;
void RemoteServerConnect(
const blink::WebBluetoothDeviceId& device_id,
mojo::PendingAssociatedRemote<blink::mojom::WebBluetoothServerClient>
client,
RemoteServerConnectCallback callback) override;
void RemoteServerDisconnect(
const blink::WebBluetoothDeviceId& device_id) override;
void RemoteServerGetPrimaryServices(
const blink::WebBluetoothDeviceId& device_id,
blink::mojom::WebBluetoothGATTQueryQuantity quantity,
const std::optional<device::BluetoothUUID>& services_uuid,
RemoteServerGetPrimaryServicesCallback callback) override;
void RemoteServiceGetCharacteristics(
const std::string& service_instance_id,
blink::mojom::WebBluetoothGATTQueryQuantity quantity,
const std::optional<device::BluetoothUUID>& characteristics_uuid,
RemoteServiceGetCharacteristicsCallback callback) override;
void RemoteCharacteristicReadValue(
const std::string& characteristic_instance_id,
RemoteCharacteristicReadValueCallback callback) override;
void RemoteCharacteristicWriteValue(
const std::string& characteristic_instance_id,
base::span<const uint8_t> value,
blink::mojom::WebBluetoothWriteType write_type,
RemoteCharacteristicWriteValueCallback callback) override;
void RemoteCharacteristicStartNotifications(
const std::string& characteristic_instance_id,
mojo::PendingAssociatedRemote<
blink::mojom::WebBluetoothCharacteristicClient> client,
RemoteCharacteristicStartNotificationsCallback callback) override;
void RemoteCharacteristicStartNotificationsInternal(
const std::string& characteristic_instance_id,
mojo::AssociatedRemote<blink::mojom::WebBluetoothCharacteristicClient>
client,
RemoteCharacteristicStartNotificationsCallback callback) override;
void RemoteCharacteristicStopNotifications(
const std::string& characteristic_instance_id,
RemoteCharacteristicStopNotificationsCallback callback) override;
void RemoteCharacteristicGetDescriptors(
const std::string& service_instance_id,
blink::mojom::WebBluetoothGATTQueryQuantity quantity,
const std::optional<device::BluetoothUUID>& characteristics_uuid,
RemoteCharacteristicGetDescriptorsCallback callback) override;
void RemoteDescriptorReadValue(
const std::string& descriptor_instance_id,
RemoteDescriptorReadValueCallback callback) override;
void RemoteDescriptorWriteValue(
const std::string& descriptor_instance_id,
base::span<const uint8_t> value,
RemoteDescriptorWriteValueCallback callback) override;
void RequestScanningStart(
mojo::PendingAssociatedRemote<
blink::mojom::WebBluetoothAdvertisementClient> client_remote,
blink::mojom::WebBluetoothRequestLEScanOptionsPtr options,
RequestScanningStartCallback callback) override;
void WatchAdvertisementsForDevice(
const blink::WebBluetoothDeviceId& device_id,
mojo::PendingAssociatedRemote<
blink::mojom::WebBluetoothAdvertisementClient> client_remote,
WatchAdvertisementsForDeviceCallback callback) override;
void RequestDeviceImpl(
blink::mojom::WebBluetoothRequestDeviceOptionsPtr options,
RequestDeviceCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter);
void GetDevicesImpl(GetDevicesCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter);
void RequestScanningStartImpl(
mojo::PendingAssociatedRemote<
blink::mojom::WebBluetoothAdvertisementClient> client_remote,
blink::mojom::WebBluetoothRequestLEScanOptionsPtr options,
RequestScanningStartCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter);
void OnStartDiscoverySessionForScanning(
mojo::PendingAssociatedRemote<
blink::mojom::WebBluetoothAdvertisementClient> client_remote,
blink::mojom::WebBluetoothRequestLEScanOptionsPtr options,
std::unique_ptr<device::BluetoothDiscoverySession> session);
void OnDiscoverySessionErrorForScanning();
void WatchAdvertisementsForDeviceImpl(
const blink::WebBluetoothDeviceId& device_id,
mojo::PendingAssociatedRemote<
blink::mojom::WebBluetoothAdvertisementClient> client_remote,
WatchAdvertisementsForDeviceCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter);
void OnStartDiscoverySessionForWatchAdvertisements(
std::unique_ptr<device::BluetoothDiscoverySession> session);
void OnDiscoverySessionErrorForWatchAdvertisements();
void RemoveDisconnectedClients();
void MaybeStopDiscovery();
void RemoteServerGetPrimaryServicesImpl(
const blink::WebBluetoothDeviceId& device_id,
blink::mojom::WebBluetoothGATTQueryQuantity quantity,
const std::optional<device::BluetoothUUID>& services_uuid,
RemoteServerGetPrimaryServicesCallback callback,
device::BluetoothDevice* device);
void OnGetDevice(RequestDeviceCallback callback,
blink::mojom::WebBluetoothResult result,
blink::mojom::WebBluetoothRequestDeviceOptionsPtr options,
const std::string& device_id);
void OnCreateGATTConnection(
const blink::WebBluetoothDeviceId& device_id,
mojo::AssociatedRemote<blink::mojom::WebBluetoothServerClient> client,
RemoteServerConnectCallback callback,
std::unique_ptr<device::BluetoothGattConnection> connection,
std::optional<device::BluetoothDevice::ConnectErrorCode> error_code);
void OnCharacteristicReadValue(
const std::string& characteristic_instance_id,
RemoteCharacteristicReadValueCallback callback,
std::optional<device::BluetoothGattService::GattErrorCode> error_code,
const std::vector<uint8_t>& value);
void OnCharacteristicWriteValueSuccess(
RemoteCharacteristicWriteValueCallback callback);
void OnCharacteristicWriteValueFailed(
const std::string& characteristic_instance_id,
const std::vector<uint8_t>& value,
blink::mojom::WebBluetoothWriteType write_type,
RemoteCharacteristicWriteValueCallback callback,
device::BluetoothGattService::GattErrorCode error_code);
void OnStartNotifySessionSuccess(
RemoteCharacteristicStartNotificationsCallback callback,
std::unique_ptr<device::BluetoothGattNotifySession> notify_session);
void OnStartNotifySessionFailed(
RemoteCharacteristicStartNotificationsCallback callback,
const std::string& characteristic_instance_id,
device::BluetoothGattService::GattErrorCode error_code);
void OnStopNotifySessionComplete(
const std::string& characteristic_instance_id,
RemoteCharacteristicStopNotificationsCallback callback);
void OnDescriptorReadValue(
const std::string& descriptor_instance_id,
RemoteDescriptorReadValueCallback callback,
std::optional<device::BluetoothGattService::GattErrorCode> error_code,
const std::vector<uint8_t>& value);
void OnDescriptorWriteValueSuccess(
RemoteDescriptorWriteValueCallback callback);
void OnDescriptorWriteValueFailed(
const std::string& descriptor_instance_id,
const std::vector<uint8_t>& value,
RemoteDescriptorWriteValueCallback callback,
device::BluetoothGattService::GattErrorCode error_code);
CacheQueryResult QueryCacheForDevice(
const blink::WebBluetoothDeviceId& device_id);
device::BluetoothDevice* GetCachedDevice(
const blink::WebBluetoothDeviceId& device_id);
CacheQueryResult QueryCacheForService(const std::string& service_instance_id);
CacheQueryResult QueryCacheForCharacteristic(
const std::string& characteristic_instance_id);
CacheQueryResult QueryCacheForDescriptor(
const std::string& descriptor_instance_id);
void RunPendingPrimaryServicesRequests(device::BluetoothDevice* device);
RenderProcessHost* GetRenderProcessHost();
device::BluetoothAdapter* GetAdapter();
BluetoothAllowedDevices& allowed_devices();
void StoreAllowedScanOptions(
const blink::mojom::WebBluetoothRequestLEScanOptions& options);
bool AreScanFiltersAllowed(const std::optional<ScanFilters>& filters) const;
void ClearAdvertisementClients();
bool IsAllowedToAccessAtLeastOneService(
const blink::WebBluetoothDeviceId& device_id);
bool IsAllowedToAccessService(const blink::WebBluetoothDeviceId& device_id,
const device::BluetoothUUID& service);
bool IsAllowedToAccessManufacturerData(
const blink::WebBluetoothDeviceId& device_id,
uint16_t manufacturer_code);
bool HasActiveDiscoverySession();
void PreventBackForwardCache();
blink::WebBluetoothDeviceId GetCharacteristicDeviceID(
const std::string& characteristic_instance_id) override;
blink::WebBluetoothDeviceId GetDescriptorDeviceId(
const std::string& descriptor_instance_id) override;
blink::WebBluetoothDeviceId GetWebBluetoothDeviceId(
const std::string& device_address) override;
void PairDevice(const blink::WebBluetoothDeviceId& device_id,
device::BluetoothDevice::PairingDelegate* pairing_delegate,
device::BluetoothDevice::ConnectCallback callback) override;
void CancelPairing(const blink::WebBluetoothDeviceId& device_id) override;
void SetPinCode(const blink::WebBluetoothDeviceId& device_id,
const std::string& pincode) override;
void PromptForBluetoothPairing(
const std::u16string& device_identifier,
BluetoothDelegate::PairPromptCallback callback,
BluetoothDelegate::PairingKind pairing_kind,
const std::optional<std::u16string>& pin) override;
void PairConfirmed(const blink::WebBluetoothDeviceId& device_id) override;
mojo::Receiver<blink::mojom::WebBluetoothService> receiver_;
std::unique_ptr<BluetoothDeviceChooserController> device_chooser_controller_;
std::unique_ptr<BluetoothDeviceScanningPromptController>
device_scanning_prompt_controller_;
std::unordered_map<std::string, std::string> service_id_to_device_address_;
std::unordered_map<std::string, std::string> characteristic_id_to_service_id_;
std::unordered_map<std::string, std::string>
descriptor_id_to_characteristic_id_;
std::unique_ptr<FrameConnectedBluetoothDevices> connected_devices_;
std::unordered_map<std::string, std::vector<PrimaryServicesRequestCallback>>
pending_primary_services_requests_;
std::unordered_map<std::string,
std::unique_ptr<GATTNotifySessionAndCharacteristicClient>>
characteristic_id_to_notify_session_;
std::unordered_map<
std::string,
base::queue<std::unique_ptr<DeferredStartNotificationData>>>
characteristic_id_to_deferred_start_;
std::unique_ptr<device::BluetoothDiscoverySession>
ble_scan_discovery_session_;
std::unique_ptr<device::BluetoothDiscoverySession>
watch_advertisements_discovery_session_;
RequestScanningStartCallback request_scanning_start_callback_;
std::vector<std::unique_ptr<WatchAdvertisementsClient>>
watch_advertisements_pending_clients_;
std::vector<std::unique_ptr<ScanningClient>> scanning_clients_;
std::vector<std::unique_ptr<WatchAdvertisementsClient>>
watch_advertisements_clients_;
ScanFilters allowed_scan_filters_;
bool accept_all_advertisements_ = false;
#if PAIR_BLUETOOTH_ON_DEMAND()
std::unique_ptr<WebBluetoothPairingManager> pairing_manager_;
#endif
RenderFrameHostImpl::BackForwardCacheDisablingFeatureHandle
back_forward_cache_feature_handle_;
base::ScopedObservation<BluetoothDelegate,
BluetoothDelegate::FramePermissionObserver>
observer_{this};
std::unordered_set<blink::WebBluetoothDeviceId,
blink::WebBluetoothDeviceIdHash>
pending_connection_device_ids_;
base::WeakPtrFactory<WebBluetoothServiceImpl> weak_ptr_factory_{this};
};
}
#endif