123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "device/bluetooth/bluetooth_device_winrt.h"
- #include <windows.devices.enumeration.h>
- #include <windows.foundation.h>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/logging.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/stringprintf.h"
- #include "base/win/core_winrt_util.h"
- #include "base/win/post_async_results.h"
- #include "base/win/scoped_hstring.h"
- #include "components/device_event_log/device_event_log.h"
- #include "device/bluetooth/bluetooth_adapter_winrt.h"
- #include "device/bluetooth/bluetooth_gatt_discoverer_winrt.h"
- #include "device/bluetooth/bluetooth_pairing_winrt.h"
- #include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
- #include "device/bluetooth/event_utils_winrt.h"
- #include "device/bluetooth/public/cpp/bluetooth_address.h"
- #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
- namespace device {
- 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::
- GattSessionStatus;
- using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- GattSessionStatus_Active;
- using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- GattSessionStatus_Closed;
- using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession;
- using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
- IGattSessionStatics;
- using ABI::Windows::Devices::Enumeration::IDeviceInformation;
- using ABI::Windows::Devices::Enumeration::IDeviceInformation2;
- using ABI::Windows::Devices::Enumeration::IDeviceInformationCustomPairing;
- using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing;
- using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing2;
- using ABI::Windows::Foundation::IAsyncOperation;
- using ABI::Windows::Foundation::IClosable;
- using Microsoft::WRL::ComPtr;
- void PostTask(BluetoothPairingWinrt::ConnectCallback callback,
- absl::optional<BluetoothDevice::ConnectErrorCode> error_code) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), error_code));
- }
- ComPtr<IDeviceInformationPairing> GetDeviceInformationPairing(
- ComPtr<IBluetoothLEDevice> ble_device) {
- if (!ble_device) {
- BLUETOOTH_LOG(DEBUG) << "No BLE device instance present.";
- return nullptr;
- }
- ComPtr<IBluetoothLEDevice2> ble_device_2;
- HRESULT hr = ble_device.As(&ble_device_2);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Obtaining IBluetoothLEDevice2 failed: "
- << logging::SystemErrorCodeToString(hr);
- return nullptr;
- }
- ComPtr<IDeviceInformation> device_information;
- hr = ble_device_2->get_DeviceInformation(&device_information);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Getting Device Information failed: "
- << logging::SystemErrorCodeToString(hr);
- return nullptr;
- }
- ComPtr<IDeviceInformation2> device_information_2;
- hr = device_information.As(&device_information_2);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Obtaining IDeviceInformation2 failed: "
- << logging::SystemErrorCodeToString(hr);
- return nullptr;
- }
- ComPtr<IDeviceInformationPairing> pairing;
- hr = device_information_2->get_Pairing(&pairing);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "DeviceInformation::get_Pairing() failed: "
- << logging::SystemErrorCodeToString(hr);
- return nullptr;
- }
- return pairing;
- }
- void CloseDevice(ComPtr<IBluetoothLEDevice> ble_device) {
- if (!ble_device)
- return;
- ComPtr<IClosable> closable;
- HRESULT hr = ble_device.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);
- }
- }
- 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);
- }
- }
- void RemoveConnectionStatusHandler(IBluetoothLEDevice* ble_device,
- EventRegistrationToken token) {
- HRESULT hr = ble_device->remove_ConnectionStatusChanged(token);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Removing ConnectionStatus Handler failed: "
- << logging::SystemErrorCodeToString(hr);
- }
- }
- 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);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Removing Gatt Services Changed Handler failed: "
- << logging::SystemErrorCodeToString(hr);
- }
- }
- void RemoveNameChangedHandler(IBluetoothLEDevice* ble_device,
- EventRegistrationToken token) {
- HRESULT hr = ble_device->remove_NameChanged(token);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Removing NameChanged Handler failed: "
- << logging::SystemErrorCodeToString(hr);
- }
- }
- } // namespace
- BluetoothDeviceWinrt::BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
- uint64_t raw_address)
- : BluetoothDevice(adapter),
- raw_address_(raw_address),
- address_(CanonicalizeAddress(raw_address)) {
- supports_service_specific_discovery_ = true;
- }
- BluetoothDeviceWinrt::~BluetoothDeviceWinrt() {
- CloseGattSession(gatt_session_);
- CloseDevice(ble_device_);
- ClearEventRegistrations();
- }
- uint32_t BluetoothDeviceWinrt::GetBluetoothClass() const {
- // No logging - called too frequenty.
- return 0;
- }
- std::string BluetoothDeviceWinrt::GetAddress() const {
- return address_;
- }
- BluetoothDevice::AddressType BluetoothDeviceWinrt::GetAddressType() const {
- NOTIMPLEMENTED();
- return ADDR_TYPE_UNKNOWN;
- }
- BluetoothDevice::VendorIDSource BluetoothDeviceWinrt::GetVendorIDSource()
- const {
- NOTIMPLEMENTED();
- return VendorIDSource();
- }
- uint16_t BluetoothDeviceWinrt::GetVendorID() const {
- NOTIMPLEMENTED();
- return 0;
- }
- uint16_t BluetoothDeviceWinrt::GetProductID() const {
- NOTIMPLEMENTED();
- return 0;
- }
- uint16_t BluetoothDeviceWinrt::GetDeviceID() const {
- NOTIMPLEMENTED();
- return 0;
- }
- uint16_t BluetoothDeviceWinrt::GetAppearance() const {
- // No logging - called too frequenty.
- return 0;
- }
- absl::optional<std::string> BluetoothDeviceWinrt::GetName() const {
- if (!ble_device_)
- return local_name_;
- HSTRING name;
- HRESULT hr = ble_device_->get_Name(&name);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Getting Name failed: "
- << logging::SystemErrorCodeToString(hr);
- return local_name_;
- }
- // Prefer returning |local_name_| over an empty string.
- if (!name)
- return local_name_;
- return base::win::ScopedHString(name).GetAsUTF8();
- }
- bool BluetoothDeviceWinrt::IsPaired() const {
- ComPtr<IDeviceInformationPairing> pairing =
- GetDeviceInformationPairing(ble_device_);
- if (!pairing) {
- BLUETOOTH_LOG(DEBUG) << "Failed to get DeviceInformationPairing.";
- return false;
- }
- boolean is_paired;
- HRESULT hr = pairing->get_IsPaired(&is_paired);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "DeviceInformationPairing::get_IsPaired() failed: "
- << logging::SystemErrorCodeToString(hr);
- return false;
- }
- BLUETOOTH_LOG(DEBUG) << "BluetoothDeviceWinrt::IsPaired(): "
- << (is_paired ? "True" : "False");
- return is_paired;
- }
- bool BluetoothDeviceWinrt::IsConnected() const {
- return ble_device_ &&
- connection_status_ == BluetoothConnectionStatus_Connected;
- }
- bool BluetoothDeviceWinrt::IsGattConnected() const {
- if (!observe_gatt_session_status_change_events_)
- return IsConnected();
- return gatt_session_ && gatt_session_status_ == GattSessionStatus_Active;
- }
- bool BluetoothDeviceWinrt::IsConnectable() const {
- NOTIMPLEMENTED();
- return false;
- }
- bool BluetoothDeviceWinrt::IsConnecting() const {
- NOTIMPLEMENTED();
- return false;
- }
- bool BluetoothDeviceWinrt::ExpectingPinCode() const {
- return pairing_ && pairing_->ExpectingPinCode();
- }
- bool BluetoothDeviceWinrt::ExpectingPasskey() const {
- NOTIMPLEMENTED();
- return false;
- }
- bool BluetoothDeviceWinrt::ExpectingConfirmation() const {
- NOTIMPLEMENTED();
- return false;
- }
- void BluetoothDeviceWinrt::GetConnectionInfo(ConnectionInfoCallback callback) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::SetConnectionLatency(
- ConnectionLatency connection_latency,
- base::OnceClosure callback,
- ErrorCallback error_callback) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::Connect(PairingDelegate* pairing_delegate,
- ConnectCallback callback) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::Pair(PairingDelegate* pairing_delegate,
- ConnectCallback callback) {
- BLUETOOTH_LOG(DEBUG) << "BluetoothDeviceWinrt::Pair()";
- if (pairing_) {
- BLUETOOTH_LOG(DEBUG) << "Another Pair Operation is already in progress.";
- PostTask(std::move(callback), ERROR_INPROGRESS);
- return;
- }
- ComPtr<IDeviceInformationPairing> pairing =
- GetDeviceInformationPairing(ble_device_);
- if (!pairing) {
- BLUETOOTH_LOG(DEBUG) << "Failed to get DeviceInformationPairing.";
- PostTask(std::move(callback), ERROR_UNKNOWN);
- return;
- }
- ComPtr<IDeviceInformationPairing2> pairing_2;
- HRESULT hr = pairing.As(&pairing_2);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "Obtaining IDeviceInformationPairing2 failed: "
- << logging::SystemErrorCodeToString(hr);
- PostTask(std::move(callback), ERROR_UNKNOWN);
- return;
- }
- ComPtr<IDeviceInformationCustomPairing> custom;
- hr = pairing_2->get_Custom(&custom);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "DeviceInformationPairing::get_Custom() failed: "
- << logging::SystemErrorCodeToString(hr);
- PostTask(std::move(callback), ERROR_UNKNOWN);
- return;
- }
- // Wrap callback, so that it cleans up the pairing object when run.
- auto wrapped_callback = base::BindOnce(
- [](base::WeakPtr<BluetoothDeviceWinrt> device, ConnectCallback callback,
- absl::optional<ConnectErrorCode> error_code) {
- if (device)
- device->pairing_.reset();
- std::move(callback).Run(error_code);
- },
- weak_ptr_factory_.GetWeakPtr(), std::move(callback));
- pairing_ = std::make_unique<BluetoothPairingWinrt>(
- this, pairing_delegate, std::move(custom), std::move(wrapped_callback));
- pairing_->StartPairing();
- }
- void BluetoothDeviceWinrt::SetPinCode(const std::string& pincode) {
- if (pairing_)
- pairing_->SetPinCode(pincode);
- }
- void BluetoothDeviceWinrt::SetPasskey(uint32_t passkey) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::ConfirmPairing() {
- if (pairing_)
- pairing_->ConfirmPairing();
- }
- void BluetoothDeviceWinrt::RejectPairing() {
- if (pairing_)
- pairing_->RejectPairing();
- }
- void BluetoothDeviceWinrt::CancelPairing() {
- if (pairing_)
- pairing_->CancelPairing();
- }
- void BluetoothDeviceWinrt::Disconnect(base::OnceClosure callback,
- ErrorCallback error_callback) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::Forget(base::OnceClosure callback,
- ErrorCallback error_callback) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::ConnectToService(
- const BluetoothUUID& uuid,
- ConnectToServiceCallback callback,
- ConnectToServiceErrorCallback error_callback) {
- NOTIMPLEMENTED();
- }
- void BluetoothDeviceWinrt::ConnectToServiceInsecurely(
- const device::BluetoothUUID& uuid,
- ConnectToServiceCallback callback,
- ConnectToServiceErrorCallback error_callback) {
- NOTIMPLEMENTED();
- }
- // static
- std::string BluetoothDeviceWinrt::CanonicalizeAddress(uint64_t address) {
- std::string bluetooth_address =
- CanonicalizeBluetoothAddress(base::StringPrintf("%012llX", address));
- DCHECK(!bluetooth_address.empty());
- return bluetooth_address;
- }
- void BluetoothDeviceWinrt::UpdateLocalName(
- absl::optional<std::string> local_name) {
- if (!local_name)
- return;
- local_name_ = std::move(local_name);
- }
- void BluetoothDeviceWinrt::CreateGattConnectionImpl(
- absl::optional<BluetoothUUID> service_uuid) {
- ComPtr<IBluetoothLEDeviceStatics> device_statics;
- HRESULT hr = GetBluetoothLEDeviceStaticsActivationFactory(&device_statics);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG)
- << "GetBluetoothLEDeviceStaticsActivationFactory failed: "
- << logging::SystemErrorCodeToString(hr);
- NotifyGattConnectFailure();
- return;
- }
- // Note: Even though we might have obtained a BluetoothLEDevice instance in
- // the past, we need to request a new instance as the old device might have
- // been closed. See also
- // https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-client#connecting-to-the-device
- ComPtr<IAsyncOperation<BluetoothLEDevice*>> from_bluetooth_address_op;
- hr = device_statics->FromBluetoothAddressAsync(raw_address_,
- &from_bluetooth_address_op);
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG)
- << "BluetoothLEDevice::FromBluetoothAddressAsync failed: "
- << logging::SystemErrorCodeToString(hr);
- NotifyGattConnectFailure();
- return;
- }
- hr = base::win::PostAsyncResults(
- std::move(from_bluetooth_address_op),
- base::BindOnce(
- &BluetoothDeviceWinrt::OnBluetoothLEDeviceFromBluetoothAddress,
- weak_ptr_factory_.GetWeakPtr()));
- if (FAILED(hr)) {
- BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
- << logging::SystemErrorCodeToString(hr);
- NotifyGattConnectFailure();
- return;
- }
- 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::DidConnectGatt,
- 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.
- target_uuid_.reset();
- 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();
- }
- void BluetoothDeviceWinrt::DisconnectGatt() {
- // Closing the device and disposing of all references will trigger a Gatt
- // Disconnection after a short timeout. Since the Gatt Services store a
- // reference to |ble_device_| as well, we need to clear them to drop all
- // 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();
- // Stop any pending Gatt Discovery sessions and report an error. This will
- // destroy |gatt_discoverer_| and release remaining references the discoverer
- // might have hold.
- if (gatt_discoverer_)
- OnGattDiscoveryComplete(false);
- }
- HRESULT BluetoothDeviceWinrt::GetBluetoothLEDeviceStaticsActivationFactory(
- IBluetoothLEDeviceStatics** statics) const {
- return base::win::GetActivationFactory<
- IBluetoothLEDeviceStatics,
- RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice>(statics);
- }
- 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_);
- if (!ble_device) {
- BLUETOOTH_LOG(DEBUG) << "Getting Device From Bluetooth Address failed.";
- NotifyGattConnectFailure();
- return;
- }
- // As we are about to replace |ble_device_| with |ble_device| existing event
- // handlers need to be unregistered. New ones will be added below.
- ClearEventRegistrations();
- ble_device_ = std::move(ble_device);
- ble_device_->get_ConnectionStatus(&connection_status_);
- connection_changed_token_ = AddTypedEventHandler(
- ble_device_.Get(), &IBluetoothLEDevice::add_ConnectionStatusChanged,
- base::BindRepeating(&BluetoothDeviceWinrt::OnConnectionStatusChanged,
- weak_ptr_factory_.GetWeakPtr()));
- 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(/*error_code=*/absl::nullopt);
- }
- 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(/*error_code=*/absl::nullopt);
- 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(/*error_code=*/absl::nullopt);
- StartGattDiscovery();
- } else {
- gatt_discoverer_.reset();
- ClearGattServices();
- DidDisconnectGatt();
- }
- }
- void BluetoothDeviceWinrt::OnConnectionStatusChanged(
- IBluetoothLEDevice* ble_device,
- IInspectable* object) {
- 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;
- }
- if (IsGattConnected()) {
- DidConnectGatt(/*error_code=*/absl::nullopt);
- } else {
- gatt_discoverer_.reset();
- ClearGattServices();
- DidDisconnectGatt();
- }
- }
- void BluetoothDeviceWinrt::OnGattServicesChanged(IBluetoothLEDevice* ble_device,
- IInspectable* object) {
- BLUETOOTH_LOG(DEBUG) << "OnGattServicesChanged()";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // 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();
- }
- }
- void BluetoothDeviceWinrt::OnNameChanged(IBluetoothLEDevice* ble_device,
- IInspectable* object) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- adapter_->NotifyDeviceChanged(this);
- }
- 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(
- base::BindOnce(&BluetoothDeviceWinrt::OnGattDiscoveryComplete,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void BluetoothDeviceWinrt::OnGattDiscoveryComplete(bool success) {
- BLUETOOTH_LOG(DEBUG) << "OnGattDiscoveryComplete() success=" << success;
- if (!success) {
- if (!IsGattConnected()) {
- NotifyGattConnectFailure();
- }
- gatt_discoverer_.reset();
- return;
- }
- // Instead of clearing out |gatt_services_| and creating each service from
- // scratch, we create a new map and move already existing services into it in
- // order to preserve pointer stability.
- GattServiceMap gatt_services;
- for (const auto& gatt_service : gatt_discoverer_->GetGattServices()) {
- auto gatt_service_winrt =
- BluetoothRemoteGattServiceWinrt::Create(this, gatt_service);
- if (!gatt_service_winrt)
- continue;
- std::string identifier = gatt_service_winrt->GetIdentifier();
- auto iter = gatt_services_.find(identifier);
- if (iter != gatt_services_.end()) {
- iter = gatt_services.emplace(std::move(*iter)).first;
- } else {
- iter = gatt_services
- .emplace(std::move(identifier), std::move(gatt_service_winrt))
- .first;
- }
- static_cast<BluetoothRemoteGattServiceWinrt*>(iter->second.get())
- ->UpdateCharacteristics(gatt_discoverer_.get());
- }
- std::swap(gatt_services, gatt_services_);
- device_uuids_.ReplaceServiceUUIDs(gatt_services_);
- SetGattServicesDiscoveryComplete(true);
- adapter_->NotifyGattServicesDiscovered(this);
- adapter_->NotifyDeviceChanged(this);
- gatt_discoverer_.reset();
- }
- void BluetoothDeviceWinrt::ClearGattServices() {
- // Clearing |gatt_services_| can trigger callbacks. Move the existing
- // objects into a local variable to avoid re-entrancy into clear().
- GattServiceMap temp_gatt_services;
- temp_gatt_services.swap(gatt_services_);
- temp_gatt_services.clear();
- device_uuids_.ClearServiceUUIDs();
- SetGattServicesDiscoveryComplete(false);
- }
- void BluetoothDeviceWinrt::ClearEventRegistrations() {
- if (connection_changed_token_) {
- RemoveConnectionStatusHandler(ble_device_.Get(),
- *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_);
- }
- if (name_changed_token_)
- RemoveNameChangedHandler(ble_device_.Get(), *name_changed_token_);
- }
- } // namespace device
|