summaryrefslogtreecommitdiff
path: root/chromium/device/bluetooth/bluetooth_device_winrt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/device/bluetooth/bluetooth_device_winrt.cc')
-rw-r--r--chromium/device/bluetooth/bluetooth_device_winrt.cc330
1 files changed, 264 insertions, 66 deletions
diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.cc b/chromium/device/bluetooth/bluetooth_device_winrt.cc
index b1785fa92e6..bdb2afdc94c 100644
--- a/chromium/device/bluetooth/bluetooth_device_winrt.cc
+++ b/chromium/device/bluetooth/bluetooth_device_winrt.cc
@@ -32,26 +32,30 @@ namespace {
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus_Connected;
+using ABI::Windows::Devices::Bluetooth::BluetoothError;
+using ABI::Windows::Devices::Bluetooth::BluetoothError_Success;
using ABI::Windows::Devices::Bluetooth::BluetoothLEDevice;
+using ABI::Windows::Devices::Bluetooth::IBluetoothDeviceId;
+using ABI::Windows::Devices::Bluetooth::IBluetoothDeviceIdStatics;
+using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
+using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice2;
+using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice4;
+using ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics;
+using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattSession;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- GattCommunicationStatus;
+ GattSessionStatus;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- GattCommunicationStatus_Success;
+ GattSessionStatus_Active;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- GattDeviceServicesResult;
+ GattSessionStatus_Closed;
+using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession;
using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- IGattDeviceServicesResult;
-using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice2;
-using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3;
-using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
-using ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics;
-using ABI::Windows::Devices::Enumeration::DevicePairingResultStatus;
-using ABI::Windows::Devices::Enumeration::IDeviceInformation2;
+ IGattSessionStatics;
using ABI::Windows::Devices::Enumeration::IDeviceInformation;
+using ABI::Windows::Devices::Enumeration::IDeviceInformation2;
using ABI::Windows::Devices::Enumeration::IDeviceInformationCustomPairing;
-using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing2;
using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing;
-using ABI::Windows::Devices::Enumeration::IDevicePairingRequestedEventArgs;
+using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing2;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::IClosable;
using Microsoft::WRL::ComPtr;
@@ -118,7 +122,26 @@ void CloseDevice(ComPtr<IBluetoothLEDevice> ble_device) {
hr = closable->Close();
if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "IClosable::close() failed: "
+ BLUETOOTH_LOG(DEBUG) << "IClosable::Close() failed: "
+ << logging::SystemErrorCodeToString(hr);
+ }
+}
+
+void CloseGattSession(ComPtr<IGattSession> gatt_session) {
+ if (!gatt_session)
+ return;
+
+ ComPtr<IClosable> closable;
+ HRESULT hr = gatt_session.As(&closable);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "As IClosable failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ hr = closable->Close();
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "IClosable::Close() failed: "
<< logging::SystemErrorCodeToString(hr);
}
}
@@ -132,6 +155,15 @@ void RemoveConnectionStatusHandler(IBluetoothLEDevice* ble_device,
}
}
+void RemoveGattSessionStatusHandler(IGattSession* gatt_session,
+ EventRegistrationToken token) {
+ HRESULT hr = gatt_session->remove_SessionStatusChanged(token);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "Removing ConnectionStatus Handler failed: "
+ << logging::SystemErrorCodeToString(hr);
+ }
+}
+
void RemoveGattServicesChangedHandler(IBluetoothLEDevice* ble_device,
EventRegistrationToken token) {
HRESULT hr = ble_device->remove_GattServicesChanged(token);
@@ -161,6 +193,7 @@ BluetoothDeviceWinrt::BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
}
BluetoothDeviceWinrt::~BluetoothDeviceWinrt() {
+ CloseGattSession(gatt_session_);
CloseDevice(ble_device_);
ClearEventRegistrations();
}
@@ -241,14 +274,15 @@ bool BluetoothDeviceWinrt::IsPaired() const {
}
bool BluetoothDeviceWinrt::IsConnected() const {
- return IsGattConnected();
+ return ble_device_ &&
+ connection_status_ == BluetoothConnectionStatus_Connected;
}
bool BluetoothDeviceWinrt::IsGattConnected() const {
- if (!ble_device_)
- return false;
+ if (!observe_gatt_session_status_change_events_)
+ return IsConnected();
- return connection_status_;
+ return gatt_session_ && gatt_session_status_ == GattSessionStatus_Active;
}
bool BluetoothDeviceWinrt::IsConnectable() const {
@@ -426,10 +460,7 @@ void BluetoothDeviceWinrt::CreateGattConnectionImpl(
BLUETOOTH_LOG(DEBUG)
<< "GetBluetoothLEDeviceStaticsActivationFactory failed: "
<< logging::SystemErrorCodeToString(hr);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
- weak_ptr_factory_.GetWeakPtr(),
- ConnectErrorCode::ERROR_FAILED));
+ NotifyGattConnectFailure();
return;
}
@@ -444,45 +475,53 @@ void BluetoothDeviceWinrt::CreateGattConnectionImpl(
BLUETOOTH_LOG(DEBUG)
<< "BluetoothLEDevice::FromBluetoothAddressAsync failed: "
<< logging::SystemErrorCodeToString(hr);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
- weak_ptr_factory_.GetWeakPtr(),
- ConnectErrorCode::ERROR_FAILED));
+ NotifyGattConnectFailure();
return;
}
- target_uuid_ = std::move(service_uuid);
hr = base::win::PostAsyncResults(
std::move(from_bluetooth_address_op),
- base::BindOnce(&BluetoothDeviceWinrt::OnFromBluetoothAddress,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(
+ &BluetoothDeviceWinrt::OnBluetoothLEDeviceFromBluetoothAddress,
+ weak_ptr_factory_.GetWeakPtr()));
if (FAILED(hr)) {
BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
<< logging::SystemErrorCodeToString(hr);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
- weak_ptr_factory_.GetWeakPtr(),
- ConnectErrorCode::ERROR_FAILED));
+ NotifyGattConnectFailure();
return;
}
- pending_on_from_bluetooth_address_ = true;
+ target_uuid_ = std::move(service_uuid);
+ pending_gatt_service_discovery_start_ = true;
+}
+
+void BluetoothDeviceWinrt::NotifyGattConnectFailure() {
+ // Reset |pending_gatt_service_discovery_start_| so that
+ // UpgradeToFullDiscovery() doesn't mistakenly believe GATT discovery is
+ // imminent and therefore avoids starting one itself.
+ pending_gatt_service_discovery_start_ = false;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt,
+ weak_ptr_factory_.GetWeakPtr(),
+ ConnectErrorCode::ERROR_FAILED));
}
void BluetoothDeviceWinrt::UpgradeToFullDiscovery() {
// |CreateGattConnectionImpl| has been called previously but having a specific
// |target_uuid_| was too optimistic and now a complete enumeration of
// services is needed.
- DCHECK(pending_on_from_bluetooth_address_ || connection_status_);
target_uuid_.reset();
- if (pending_on_from_bluetooth_address_) {
- // |OnFromBluetoothAddress| hasn't been called yet. Updating |target_uuid_|
- // will be sufficient to change the discovery that will be started.
+ if (pending_gatt_service_discovery_start_) {
+ // There is an imminent call to StartDiscovery(). Resetting |target_uuid_|
+ // now will be sufficient to change the discovery that will be started.
return;
}
+ DCHECK(ble_device_);
+ DCHECK(!observe_gatt_session_status_change_events_ || IsGattConnected());
+
// Restart discovery.
StartGattDiscovery();
}
@@ -494,6 +533,7 @@ void BluetoothDeviceWinrt::DisconnectGatt() {
// remaining references, so that the OS disconnects.
// Reference:
// - https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-client
+ CloseGattSession(gatt_session_);
CloseDevice(ble_device_);
ClearGattServices();
@@ -511,13 +551,20 @@ HRESULT BluetoothDeviceWinrt::GetBluetoothLEDeviceStaticsActivationFactory(
RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice>(statics);
}
-void BluetoothDeviceWinrt::OnFromBluetoothAddress(
+HRESULT BluetoothDeviceWinrt::GetGattSessionStaticsActivationFactory(
+ IGattSessionStatics** statics) const {
+ return base::win::GetActivationFactory<
+ IGattSessionStatics,
+ RuntimeClass_Windows_Devices_Bluetooth_GenericAttributeProfile_GattSession>(
+ statics);
+}
+
+void BluetoothDeviceWinrt::OnBluetoothLEDeviceFromBluetoothAddress(
ComPtr<IBluetoothLEDevice> ble_device) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- pending_on_from_bluetooth_address_ = false;
if (!ble_device) {
BLUETOOTH_LOG(DEBUG) << "Getting Device From Bluetooth Address failed.";
- DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
+ NotifyGattConnectFailure();
return;
}
@@ -532,40 +579,168 @@ void BluetoothDeviceWinrt::OnFromBluetoothAddress(
base::BindRepeating(&BluetoothDeviceWinrt::OnConnectionStatusChanged,
weak_ptr_factory_.GetWeakPtr()));
- // For paired devices the OS immediately establishes a GATT connection after
- // the first advertisement. In this case our handler is registered too late to
- // catch the initial connection changed event, and we need to perform an
- // explicit check ourselves.
- if (IsGattConnected())
- DidConnectGatt();
-
- gatt_services_changed_token_ = AddTypedEventHandler(
- ble_device_.Get(), &IBluetoothLEDevice::add_GattServicesChanged,
- base::BindRepeating(&BluetoothDeviceWinrt::OnGattServicesChanged,
- weak_ptr_factory_.GetWeakPtr()));
-
- // Initiating the GATT discovery will result in a GATT connection attempt as
- // well and triggers OnConnectionStatusChanged on success.
- StartGattDiscovery();
-
name_changed_token_ = AddTypedEventHandler(
ble_device_.Get(), &IBluetoothLEDevice::add_NameChanged,
base::BindRepeating(&BluetoothDeviceWinrt::OnNameChanged,
weak_ptr_factory_.GetWeakPtr()));
+
+ if (!observe_gatt_session_status_change_events_) {
+ // GattSession SessionStatusChanged events can not be observed on
+ // 1703 (RS2) because BluetoothLEDevice::GetDeviceId() is not
+ // available. Instead, initiate GATT discovery which should result
+ // in a GATT connection attempt as well and trigger
+ // OnConnectionStatusChanged on success.
+ if (IsGattConnected()) {
+ DidConnectGatt();
+ }
+ StartGattDiscovery();
+ return;
+ }
+
+ // Next, obtain a GattSession so we can tell the OS to maintain a GATT
+ // connection with |ble_device_|.
+
+ // BluetoothLEDevice::GetDeviceId()
+ ComPtr<IBluetoothLEDevice4> ble_device_4;
+ HRESULT hr = ble_device_.As(&ble_device_4);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "Obtaining IBluetoothLEDevice4 failed: "
+ << logging::SystemErrorCodeToString(hr);
+ NotifyGattConnectFailure();
+ return;
+ }
+ ComPtr<IBluetoothDeviceId> bluetooth_device_id;
+ hr = ble_device_4->get_BluetoothDeviceId(&bluetooth_device_id);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "BluetoothDeviceId::FromId failed: "
+ << logging::SystemErrorCodeToString(hr);
+ NotifyGattConnectFailure();
+ return;
+ }
+
+ // GattSession::FromDeviceIdAsync()
+ IGattSessionStatics* gatt_session_statics = nullptr;
+ hr = GetGattSessionStaticsActivationFactory(&gatt_session_statics);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "GetGattSessionStaticsActivationFactory() failed: "
+ << logging::SystemErrorCodeToString(hr);
+ NotifyGattConnectFailure();
+ return;
+ }
+ ComPtr<IAsyncOperation<GattSession*>> gatt_session_from_device_id_async_op;
+ hr = gatt_session_statics->FromDeviceIdAsync(
+ bluetooth_device_id.Get(), &gatt_session_from_device_id_async_op);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "GattSession::FromDeviceId failed: "
+ << logging::SystemErrorCodeToString(hr);
+ NotifyGattConnectFailure();
+ return;
+ }
+ hr = base::win::PostAsyncResults(
+ std::move(gatt_session_from_device_id_async_op),
+ base::BindOnce(&BluetoothDeviceWinrt::OnGattSessionFromDeviceId,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
+ << logging::SystemErrorCodeToString(hr);
+ NotifyGattConnectFailure();
+ return;
+ }
+}
+
+void BluetoothDeviceWinrt::OnGattSessionFromDeviceId(
+ ComPtr<IGattSession> gatt_session) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(observe_gatt_session_status_change_events_);
+
+ if (!gatt_session) {
+ BLUETOOTH_LOG(DEBUG) << "Getting GattSession failed";
+ NotifyGattConnectFailure();
+ return;
+ }
+
+ gatt_session_ = std::move(gatt_session);
+
+ // Tell the OS to automatically establish and maintain a GATT connection.
+ HRESULT hr = gatt_session_->put_MaintainConnection(true);
+ if (FAILED(hr)) {
+ BLUETOOTH_LOG(DEBUG) << "Setting GattSession.MaintainConnection failed: "
+ << logging::SystemErrorCodeToString(hr);
+ NotifyGattConnectFailure();
+ return;
+ }
+
+ // Observe GattSessionStatus changes.
+ gatt_session_->get_SessionStatus(&gatt_session_status_);
+ gatt_session_status_changed_token_ = AddTypedEventHandler(
+ gatt_session_.Get(), &IGattSession::add_SessionStatusChanged,
+ base::BindRepeating(&BluetoothDeviceWinrt::OnGattSessionStatusChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Check whether we missed the initial GattSessionStatus change notification
+ // because the OS had already established a connection.
+ if (IsGattConnected()) {
+ DidConnectGatt();
+ StartGattDiscovery();
+ }
+}
+
+void BluetoothDeviceWinrt::OnGattSessionStatusChanged(
+ IGattSession* gatt_session,
+ ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
+ IGattSessionStatusChangedEventArgs* event_args) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(observe_gatt_session_status_change_events_);
+ DCHECK_EQ(gatt_session_.Get(), gatt_session);
+
+ GattSessionStatus old_status = gatt_session_status_;
+ event_args->get_Status(&gatt_session_status_);
+
+ BluetoothError error;
+ event_args->get_Error(&error);
+ BLUETOOTH_LOG(DEBUG) << "OnGattSessionStatusChanged() status="
+ << gatt_session_status_ << ", error=" << error;
+
+ if (pending_gatt_service_discovery_start_ &&
+ error != BluetoothError_Success) {
+ NotifyGattConnectFailure();
+ return;
+ }
+
+ // Spurious status change notifications may occur.
+ if (old_status == gatt_session_status_) {
+ return;
+ }
+
+ if (IsGattConnected()) {
+ DidConnectGatt();
+ StartGattDiscovery();
+ } else {
+ gatt_discoverer_.reset();
+ ClearGattServices();
+ DidDisconnectGatt();
+ }
}
void BluetoothDeviceWinrt::OnConnectionStatusChanged(
IBluetoothLEDevice* ble_device,
IInspectable* object) {
- BluetoothConnectionStatus new_status;
- ble_device->get_ConnectionStatus(&new_status);
- // Windows sometimes returns a status changed event with a status that has
- // not changed.
- if (new_status == connection_status_)
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ BluetoothConnectionStatus old_status = connection_status_;
+ ble_device->get_ConnectionStatus(&connection_status_);
+ BLUETOOTH_LOG(DEBUG) << "OnConnectionStatusChanged() status="
+ << connection_status_;
+
+ // Spurious status change notifications may occur.
+ if (old_status == connection_status_) {
return;
+ }
+
+ if (observe_gatt_session_status_change_events_) {
+ return;
+ }
- connection_status_ = new_status;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (IsGattConnected()) {
DidConnectGatt();
} else {
@@ -577,15 +752,23 @@ void BluetoothDeviceWinrt::OnConnectionStatusChanged(
void BluetoothDeviceWinrt::OnGattServicesChanged(IBluetoothLEDevice* ble_device,
IInspectable* object) {
+ BLUETOOTH_LOG(DEBUG) << "OnGattServicesChanged()";
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Note: We don't clear out |gatt_services_| here, as we don't want to break
+ // TODO(crbug/1085596): This event fires once for every newly discovered GATT
+ // service. Hence, the initial GATT service discovery aborts and restarts
+ // itself here once for every service discovered, which is unnecessary and
+ // slow.
+
+ // We don't clear out |gatt_services_| here, as we don't want to break
// existing references to Gatt Services that did not change.
device_uuids_.ClearServiceUUIDs();
+
SetGattServicesDiscoveryComplete(false);
adapter_->NotifyDeviceChanged(this);
if (IsGattConnected()) {
// In order to stop a potential ongoing GATT discovery, the GattDiscoverer
// is reset and a new discovery is initiated.
+ BLUETOOTH_LOG(DEBUG) << "Discovering GATT services anew";
StartGattDiscovery();
}
}
@@ -597,6 +780,14 @@ void BluetoothDeviceWinrt::OnNameChanged(IBluetoothLEDevice* ble_device,
}
void BluetoothDeviceWinrt::StartGattDiscovery() {
+ BLUETOOTH_LOG(DEBUG) << "StartGattDiscovery()";
+ pending_gatt_service_discovery_start_ = false;
+ if (!gatt_services_changed_token_) {
+ gatt_services_changed_token_ = AddTypedEventHandler(
+ ble_device_.Get(), &IBluetoothLEDevice::add_GattServicesChanged,
+ base::BindRepeating(&BluetoothDeviceWinrt::OnGattServicesChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
gatt_discoverer_ =
std::make_unique<BluetoothGattDiscovererWinrt>(ble_device_, target_uuid_);
gatt_discoverer_->StartGattDiscovery(
@@ -605,9 +796,11 @@ void BluetoothDeviceWinrt::StartGattDiscovery() {
}
void BluetoothDeviceWinrt::OnGattDiscoveryComplete(bool success) {
+ BLUETOOTH_LOG(DEBUG) << "OnGattDiscoveryComplete() success=" << success;
if (!success) {
- if (!IsGattConnected())
- DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED);
+ if (!IsGattConnected()) {
+ NotifyGattConnectFailure();
+ }
gatt_discoverer_.reset();
return;
}
@@ -661,6 +854,11 @@ void BluetoothDeviceWinrt::ClearEventRegistrations() {
*connection_changed_token_);
}
+ if (gatt_session_status_changed_token_) {
+ RemoveGattSessionStatusHandler(gatt_session_.Get(),
+ *gatt_session_status_changed_token_);
+ }
+
if (gatt_services_changed_token_) {
RemoveGattServicesChangedHandler(ble_device_.Get(),
*gatt_services_changed_token_);