1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036 |
- // Copyright (c) 2012 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_task_manager_win.h"
- #include <stddef.h>
- #include <winsock2.h>
- #include <memory>
- #include <string>
- #include <utility>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/ref_counted.h"
- #include "base/no_destructor.h"
- #include "base/strings/stringprintf.h"
- #include "base/strings/sys_string_conversions.h"
- #include "base/task/sequenced_task_runner.h"
- #include "base/task/thread_pool.h"
- #include "base/threading/scoped_thread_priority.h"
- #include "device/bluetooth/bluetooth_classic_win.h"
- #include "device/bluetooth/bluetooth_device.h"
- #include "device/bluetooth/bluetooth_init_win.h"
- #include "device/bluetooth/bluetooth_service_record_win.h"
- #include "device/bluetooth/public/cpp/bluetooth_address.h"
- #include "net/base/winsock_init.h"
- namespace {
- const int kMaxNumDeviceAddressChar = 127;
- const int kServiceDiscoveryResultBufferSize = 5000;
- // See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time
- // out for the inquiry, expressed in increments of 1.28 seconds. For example, an
- // inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum
- // value for this member is 48. When a value greater than 48 is used, the
- // calling function immediately fails and returns
- const int kMaxDeviceDiscoveryTimeoutMultiplier = 48;
- typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
- // Note: The string returned here must have the same format as
- // CanonicalizeBluetoothAddress.
- std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) {
- std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
- btha.rgBytes[5],
- btha.rgBytes[4],
- btha.rgBytes[3],
- btha.rgBytes[2],
- btha.rgBytes[1],
- btha.rgBytes[0]);
- DCHECK_EQ(result, device::CanonicalizeBluetoothAddress(result));
- return result;
- }
- bool BluetoothUUIDToWinBLEUUID(const device::BluetoothUUID& uuid,
- BTH_LE_UUID* out_win_uuid) {
- if (!uuid.IsValid())
- return false;
- if (uuid.format() == device::BluetoothUUID::kFormat16Bit) {
- out_win_uuid->IsShortUuid = TRUE;
- unsigned int data = 0;
- int result = sscanf_s(uuid.value().c_str(), "%04x", &data);
- if (result != 1)
- return false;
- out_win_uuid->Value.ShortUuid = data;
- } else {
- out_win_uuid->IsShortUuid = FALSE;
- unsigned int data[11];
- int result =
- sscanf_s(uuid.value().c_str(),
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", &data[0],
- &data[1], &data[2], &data[3], &data[4], &data[5], &data[6],
- &data[7], &data[8], &data[9], &data[10]);
- if (result != 11)
- return false;
- out_win_uuid->Value.LongUuid.Data1 = data[0];
- out_win_uuid->Value.LongUuid.Data2 = data[1];
- out_win_uuid->Value.LongUuid.Data3 = data[2];
- out_win_uuid->Value.LongUuid.Data4[0] = data[3];
- out_win_uuid->Value.LongUuid.Data4[1] = data[4];
- out_win_uuid->Value.LongUuid.Data4[2] = data[5];
- out_win_uuid->Value.LongUuid.Data4[3] = data[6];
- out_win_uuid->Value.LongUuid.Data4[4] = data[7];
- out_win_uuid->Value.LongUuid.Data4[5] = data[8];
- out_win_uuid->Value.LongUuid.Data4[6] = data[9];
- out_win_uuid->Value.LongUuid.Data4[7] = data[10];
- }
- return true;
- }
- // Populates bluetooth adapter state from the currently open adapter.
- void GetAdapterState(device::win::BluetoothClassicWrapper* classic_wrapper,
- device::BluetoothTaskManagerWin::AdapterState* state) {
- std::string name;
- std::string address;
- bool powered = false;
- BLUETOOTH_RADIO_INFO adapter_info = {sizeof(BLUETOOTH_RADIO_INFO)};
- if (classic_wrapper->HasHandle() &&
- ERROR_SUCCESS == classic_wrapper->GetRadioInfo(&adapter_info)) {
- name = base::SysWideToUTF8(adapter_info.szName);
- address = BluetoothAddressToCanonicalString(adapter_info.address);
- powered = !!classic_wrapper->IsConnectable();
- }
- state->name = name;
- state->address = address;
- state->powered = powered;
- }
- void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
- device::BluetoothTaskManagerWin::DeviceState* state) {
- state->name = base::SysWideToUTF8(device_info.szName);
- state->address = BluetoothAddressToCanonicalString(device_info.Address);
- state->bluetooth_class = device_info.ulClassofDevice;
- state->visible = true;
- state->connected = !!device_info.fConnected;
- state->authenticated = !!device_info.fAuthenticated;
- }
- struct CharacteristicValueChangedRegistration {
- CharacteristicValueChangedRegistration();
- ~CharacteristicValueChangedRegistration();
- BLUETOOTH_GATT_EVENT_HANDLE win_event_handle;
- device::BluetoothTaskManagerWin::GattCharacteristicValueChangedCallback
- callback;
- // The task runner the callback should run on.
- scoped_refptr<base::SequencedTaskRunner> callback_task_runner;
- };
- CharacteristicValueChangedRegistration::
- CharacteristicValueChangedRegistration() {}
- CharacteristicValueChangedRegistration::
- ~CharacteristicValueChangedRegistration() {}
- // The key of CharacteristicValueChangedRegistrationMap is a
- // GattCharacteristicValueChangedCallback pointer (cast to PVOID) to make it
- // unique for different callbacks. It is also the context value passed into OS
- // when registering event.
- typedef std::unordered_map<
- PVOID,
- std::unique_ptr<CharacteristicValueChangedRegistration>>
- CharacteristicValueChangedRegistrationMap;
- CharacteristicValueChangedRegistrationMap&
- GetCharacteristicValueChangedRegistrations() {
- static base::NoDestructor<CharacteristicValueChangedRegistrationMap>
- registrations;
- return *registrations;
- }
- base::Lock& GetCharacteristicValueChangedRegistrationsLock() {
- static base::NoDestructor<base::Lock> lock;
- return *lock;
- }
- // Function to be registered to OS to monitor Bluetooth LE GATT event. It is
- // invoked in BluetoothApis.dll thread.
- void CALLBACK OnGetGattEventWin(BTH_LE_GATT_EVENT_TYPE type,
- PVOID event_parameter,
- PVOID context) {
- if (type != CharacteristicValueChangedEvent) {
- // Right now, only characteristic value changed event is supported.
- NOTREACHED();
- return;
- }
- BLUETOOTH_GATT_VALUE_CHANGED_EVENT* event =
- (BLUETOOTH_GATT_VALUE_CHANGED_EVENT*)event_parameter;
- PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value_win = event->CharacteristicValue;
- std::unique_ptr<std::vector<uint8_t>> new_value(
- new std::vector<uint8_t>(new_value_win->DataSize));
- for (ULONG i = 0; i < new_value_win->DataSize; i++)
- (*new_value)[i] = new_value_win->Data[i];
- base::AutoLock auto_lock(GetCharacteristicValueChangedRegistrationsLock());
- CharacteristicValueChangedRegistrationMap::const_iterator it =
- GetCharacteristicValueChangedRegistrations().find(context);
- if (it == GetCharacteristicValueChangedRegistrations().end())
- return;
- it->second->callback_task_runner->PostTask(
- FROM_HERE, base::BindOnce(it->second->callback, std::move(new_value)));
- }
- } // namespace
- namespace device {
- // static
- const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
- BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) {
- }
- BluetoothTaskManagerWin::AdapterState::~AdapterState() {
- }
- BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() {
- }
- BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() {
- }
- BluetoothTaskManagerWin::DeviceState::DeviceState()
- : visible(false),
- connected(false),
- authenticated(false),
- bluetooth_class(0) {
- }
- BluetoothTaskManagerWin::DeviceState::~DeviceState() {
- }
- BluetoothTaskManagerWin::BluetoothTaskManagerWin(
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
- : ui_task_runner_(std::move(ui_task_runner)),
- classic_wrapper_(std::make_unique<win::BluetoothClassicWrapper>()),
- le_wrapper_(std::make_unique<win::BluetoothLowEnergyWrapper>()) {}
- BluetoothTaskManagerWin::BluetoothTaskManagerWin(
- std::unique_ptr<win::BluetoothClassicWrapper> classic_wrapper,
- std::unique_ptr<win::BluetoothLowEnergyWrapper> le_wrapper,
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
- : ui_task_runner_(std::move(ui_task_runner)),
- classic_wrapper_(std::move(classic_wrapper)),
- le_wrapper_(std::move(le_wrapper)) {}
- BluetoothTaskManagerWin::~BluetoothTaskManagerWin() = default;
- // static
- scoped_refptr<BluetoothTaskManagerWin>
- BluetoothTaskManagerWin::CreateForTesting(
- std::unique_ptr<win::BluetoothClassicWrapper> classic_wrapper,
- std::unique_ptr<win::BluetoothLowEnergyWrapper> le_wrapper,
- scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
- return new BluetoothTaskManagerWin(std::move(classic_wrapper),
- std::move(le_wrapper),
- std::move(ui_task_runner));
- }
- // static
- BluetoothUUID BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(
- const BTH_LE_UUID& bth_le_uuid) {
- if (bth_le_uuid.IsShortUuid) {
- std::string uuid_hex =
- base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid);
- return BluetoothUUID(uuid_hex);
- } else {
- return BluetoothUUID(base::StringPrintf(
- "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- bth_le_uuid.Value.LongUuid.Data1, bth_le_uuid.Value.LongUuid.Data2,
- bth_le_uuid.Value.LongUuid.Data3, bth_le_uuid.Value.LongUuid.Data4[0],
- bth_le_uuid.Value.LongUuid.Data4[1],
- bth_le_uuid.Value.LongUuid.Data4[2],
- bth_le_uuid.Value.LongUuid.Data4[3],
- bth_le_uuid.Value.LongUuid.Data4[4],
- bth_le_uuid.Value.LongUuid.Data4[5],
- bth_le_uuid.Value.LongUuid.Data4[6],
- bth_le_uuid.Value.LongUuid.Data4[7]));
- }
- }
- void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
- DCHECK(observer);
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- observers_.AddObserver(observer);
- }
- void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
- DCHECK(observer);
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- observers_.RemoveObserver(observer);
- }
- void BluetoothTaskManagerWin::Initialize() {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- InitializeWithBluetoothTaskRunner(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
- }
- void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
- scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_ = bluetooth_task_runner;
- bluetooth_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::StartPolling, this));
- }
- void BluetoothTaskManagerWin::StartPolling() {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- if (device::bluetooth_init_win::HasBluetoothStack()) {
- PollAdapter();
- } else {
- // IF the bluetooth stack is not available, we still send an empty state
- // to BluetoothAdapter so that it is marked initialized, but the adapter
- // will not be present.
- AdapterState* state = new AdapterState();
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::OnAdapterStateChanged, this,
- base::Owned(state)));
- }
- }
- void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
- bool powered,
- base::OnceClosure callback,
- BluetoothAdapter::ErrorCallback error_callback) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::SetPowered, this, powered,
- std::move(callback), std::move(error_callback)));
- }
- void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::StartDiscovery, this));
- }
- void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::StopDiscovery, this));
- }
- void BluetoothTaskManagerWin::LogPollingError(const char* message,
- int win32_error) {
- const int kLogPeriodInMilliseconds = 60 * 1000;
- const int kMaxMessagesPerLogPeriod = 10;
- // Check if we need to discard this message
- if (!current_logging_batch_ticks_.is_null()) {
- if (base::TimeTicks::Now() - current_logging_batch_ticks_ <=
- base::Milliseconds(kLogPeriodInMilliseconds)) {
- if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod)
- return;
- } else {
- // The batch expired, reset it to "null".
- current_logging_batch_ticks_ = base::TimeTicks();
- }
- }
- // Keep track of this batch of messages
- if (current_logging_batch_ticks_.is_null()) {
- current_logging_batch_ticks_ = base::TimeTicks::Now();
- current_logging_batch_count_ = 0;
- }
- ++current_logging_batch_count_;
- // Log the message
- if (win32_error == 0)
- LOG(WARNING) << message;
- else
- LOG(WARNING) << message << ": "
- << logging::SystemErrorCodeToString(win32_error);
- }
- void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- for (auto& observer : observers_)
- observer.AdapterStateChanged(*state);
- }
- void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- for (auto& observer : observers_)
- observer.DiscoveryStarted(success);
- }
- void BluetoothTaskManagerWin::OnDiscoveryStopped() {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- for (auto& observer : observers_)
- observer.DiscoveryStopped();
- }
- void BluetoothTaskManagerWin::OnDevicesPolled(
- std::vector<std::unique_ptr<DeviceState>> devices) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- for (auto& observer : observers_)
- observer.DevicesPolled(devices);
- }
- void BluetoothTaskManagerWin::PollAdapter() {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- // Skips updating the adapter info if the adapter is in discovery mode.
- if (!discovering_) {
- const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
- { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
- HBLUETOOTH_RADIO_FIND handle =
- classic_wrapper_->FindFirstRadio(&adapter_param);
- if (handle) {
- GetKnownDevices();
- classic_wrapper_->FindRadioClose(handle);
- }
- PostAdapterStateToUi();
- }
- // Re-poll.
- bluetooth_task_runner_->PostDelayedTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::PollAdapter, this),
- base::Milliseconds(kPollIntervalMs));
- }
- void BluetoothTaskManagerWin::PostAdapterStateToUi() {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- AdapterState* state = new AdapterState();
- GetAdapterState(classic_wrapper_.get(), state);
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnAdapterStateChanged,
- this, base::Owned(state)));
- }
- void BluetoothTaskManagerWin::SetPowered(
- bool powered,
- base::OnceClosure callback,
- BluetoothAdapter::ErrorCallback error_callback) {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- bool success = false;
- if (classic_wrapper_->HasHandle()) {
- if (!powered)
- classic_wrapper_->EnableDiscovery(false);
- success = !!classic_wrapper_->EnableIncomingConnections(powered);
- }
- if (success) {
- PostAdapterStateToUi();
- ui_task_runner_->PostTask(FROM_HERE, std::move(callback));
- } else {
- ui_task_runner_->PostTask(FROM_HERE, std::move(error_callback));
- }
- }
- void BluetoothTaskManagerWin::StartDiscovery() {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- bool adapter_opened = classic_wrapper_->HasHandle();
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnDiscoveryStarted,
- this, adapter_opened));
- if (!adapter_opened)
- return;
- discovering_ = true;
- DiscoverDevices(1);
- }
- void BluetoothTaskManagerWin::StopDiscovery() {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- discovering_ = false;
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
- }
- void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- if (!discovering_ || !classic_wrapper_->HasHandle())
- return;
- std::vector<std::unique_ptr<DeviceState>> device_list;
- if (SearchDevices(timeout_multiplier, false, &device_list)) {
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnDevicesPolled,
- this, std::move(device_list)));
- }
- if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
- ++timeout_multiplier;
- bluetooth_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::DiscoverDevices, this,
- timeout_multiplier));
- }
- void BluetoothTaskManagerWin::GetKnownDevices() {
- std::vector<std::unique_ptr<DeviceState>> device_list;
- if (SearchDevices(1, true, &device_list)) {
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnDevicesPolled,
- this, std::move(device_list)));
- }
- }
- bool BluetoothTaskManagerWin::SearchDevices(
- int timeout_multiplier,
- bool search_cached_devices_only,
- std::vector<std::unique_ptr<DeviceState>>* device_list) {
- return SearchClassicDevices(
- timeout_multiplier, search_cached_devices_only, device_list) &&
- SearchLowEnergyDevices(device_list) &&
- DiscoverServices(device_list, search_cached_devices_only);
- }
- bool BluetoothTaskManagerWin::SearchClassicDevices(
- int timeout_multiplier,
- bool search_cached_devices_only,
- std::vector<std::unique_ptr<DeviceState>>* device_list) {
- // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds.
- BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params;
- ZeroMemory(&device_search_params, sizeof(device_search_params));
- device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
- device_search_params.fReturnAuthenticated = 1;
- device_search_params.fReturnRemembered = 1;
- device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1);
- device_search_params.fReturnConnected = 1;
- device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1);
- device_search_params.cTimeoutMultiplier = timeout_multiplier;
- BLUETOOTH_DEVICE_INFO device_info;
- ZeroMemory(&device_info, sizeof(device_info));
- device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
- HBLUETOOTH_DEVICE_FIND handle =
- classic_wrapper_->FindFirstDevice(&device_search_params, &device_info);
- if (!handle) {
- int last_error = classic_wrapper_->LastError();
- if (last_error == ERROR_NO_MORE_ITEMS) {
- return true; // No devices is not an error.
- }
- LogPollingError("Error calling BluetoothFindFirstDevice", last_error);
- return false;
- }
- while (true) {
- auto device_state = std::make_unique<DeviceState>();
- GetDeviceState(device_info, device_state.get());
- device_list->push_back(std::move(device_state));
- // Reset device info before next call (as a safety precaution).
- ZeroMemory(&device_info, sizeof(device_info));
- device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
- if (!classic_wrapper_->FindNextDevice(handle, &device_info)) {
- int last_error = classic_wrapper_->LastError();
- if (last_error == ERROR_NO_MORE_ITEMS) {
- break; // No more items is expected error when done enumerating.
- }
- LogPollingError("Error calling BluetoothFindNextDevice", last_error);
- classic_wrapper_->FindDeviceClose(handle);
- return false;
- }
- }
- if (!classic_wrapper_->FindDeviceClose(handle)) {
- LogPollingError("Error calling BluetoothFindDeviceClose",
- classic_wrapper_->LastError());
- return false;
- }
- return true;
- }
- bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
- std::vector<std::unique_ptr<DeviceState>>* device_list) {
- if (!le_wrapper_->IsBluetoothLowEnergySupported()) {
- return true; // Bluetooth LE not supported is not an error.
- }
- std::vector<std::unique_ptr<win::BluetoothLowEnergyDeviceInfo>> btle_devices;
- std::string error;
- bool success = le_wrapper_->EnumerateKnownBluetoothLowEnergyDevices(
- &btle_devices, &error);
- if (!success) {
- error.insert(0, "Error calling EnumerateKnownBluetoothLowEnergyDevices: ");
- LogPollingError(error.c_str(), 0);
- return false;
- }
- for (const auto& device_info : btle_devices) {
- auto device_state = std::make_unique<DeviceState>();
- device_state->name = device_info->friendly_name;
- device_state->address =
- BluetoothAddressToCanonicalString(device_info->address);
- device_state->visible = device_info->visible;
- device_state->authenticated = device_info->authenticated;
- device_state->connected = device_info->connected;
- device_state->path = device_info->path;
- device_list->push_back(std::move(device_state));
- }
- return true;
- }
- bool BluetoothTaskManagerWin::DiscoverServices(
- std::vector<std::unique_ptr<DeviceState>>* device_list,
- bool search_cached_services_only) {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- net::EnsureWinsockInit();
- for (const auto& device : *device_list) {
- std::vector<std::unique_ptr<ServiceRecordState>>* service_record_states =
- &device->service_record_states;
- if (device->is_bluetooth_classic()) {
- if (!DiscoverClassicDeviceServices(device->address,
- L2CAP_PROTOCOL_UUID,
- search_cached_services_only,
- service_record_states)) {
- return false;
- }
- } else {
- if (!DiscoverLowEnergyDeviceServices(device->path,
- service_record_states)) {
- return false;
- }
- if (!SearchForGattServiceDevicePaths(device->address,
- service_record_states)) {
- return false;
- }
- }
- }
- return true;
- }
- bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
- const std::string& device_address,
- const GUID& protocol_uuid,
- bool search_cached_services_only,
- std::vector<std::unique_ptr<ServiceRecordState>>* service_record_states) {
- int error_code =
- DiscoverClassicDeviceServicesWorker(device_address,
- protocol_uuid,
- search_cached_services_only,
- service_record_states);
- // If the device is "offline", no services are returned when specifying
- // "LUP_FLUSHCACHE". Try again without flushing the cache so that the list
- // of previously known services is returned.
- if (!search_cached_services_only &&
- (error_code == WSASERVICE_NOT_FOUND || error_code == WSANO_DATA)) {
- error_code = DiscoverClassicDeviceServicesWorker(
- device_address, protocol_uuid, true, service_record_states);
- }
- return (error_code == ERROR_SUCCESS);
- }
- int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker(
- const std::string& device_address,
- const GUID& protocol_uuid,
- bool search_cached_services_only,
- std::vector<std::unique_ptr<ServiceRecordState>>* service_record_states) {
- // Mitigate the issues caused by loading DLLs on a background thread
- // (http://crbug/973868).
- SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
- // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
- WSAQUERYSET sdp_query;
- ZeroMemory(&sdp_query, sizeof(sdp_query));
- sdp_query.dwSize = sizeof(sdp_query);
- GUID protocol = protocol_uuid;
- sdp_query.lpServiceClassId = &protocol;
- sdp_query.dwNameSpace = NS_BTH;
- wchar_t device_address_context[kMaxNumDeviceAddressChar];
- std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
- device_address_context, kMaxNumDeviceAddressChar);
- device_address_context[length] = NULL;
- sdp_query.lpszContext = device_address_context;
- DWORD control_flags = LUP_RETURN_ALL;
- // See http://goo.gl/t1Hulo: "Applications should generally specify
- // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached
- // information and establish an over-the-air SDP connection to the specified
- // device to perform the SDP search. This non-cached operation may take
- // several seconds (whereas a cached search returns quickly)."
- // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list
- // of services for devices which have not been discovered before.
- if (!search_cached_services_only)
- control_flags |= LUP_FLUSHCACHE;
- HANDLE sdp_handle;
- if (ERROR_SUCCESS !=
- WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) {
- int last_error = WSAGetLastError();
- // If the device is "offline", no services are returned when specifying
- // "LUP_FLUSHCACHE". Don't log error in that case.
- if (!search_cached_services_only &&
- (last_error == WSASERVICE_NOT_FOUND || last_error == WSANO_DATA)) {
- return last_error;
- }
- LogPollingError("Error calling WSALookupServiceBegin", last_error);
- return last_error;
- }
- char sdp_buffer[kServiceDiscoveryResultBufferSize];
- LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
- while (true) {
- DWORD sdp_buffer_size = sizeof(sdp_buffer);
- if (ERROR_SUCCESS !=
- WSALookupServiceNext(
- sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) {
- int last_error = WSAGetLastError();
- if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) {
- break;
- }
- LogPollingError("Error calling WSALookupServiceNext", last_error);
- WSALookupServiceEnd(sdp_handle);
- return last_error;
- }
- auto service_record_state = std::make_unique<ServiceRecordState>();
- service_record_state->name =
- base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
- for (uint64_t i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
- service_record_state->sdp_bytes.push_back(
- sdp_result_data->lpBlob->pBlobData[i]);
- }
- service_record_states->push_back(std::move(service_record_state));
- }
- if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
- int last_error = WSAGetLastError();
- LogPollingError("Error calling WSALookupServiceEnd", last_error);
- return last_error;
- }
- return ERROR_SUCCESS;
- }
- bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
- const base::FilePath& device_path,
- std::vector<std::unique_ptr<ServiceRecordState>>* service_record_states) {
- if (!le_wrapper_->IsBluetoothLowEnergySupported()) {
- return true; // Bluetooth LE not supported is not an error.
- }
- std::string error;
- std::vector<std::unique_ptr<win::BluetoothLowEnergyServiceInfo>> services;
- bool success = le_wrapper_->EnumerateKnownBluetoothLowEnergyServices(
- device_path, &services, &error);
- if (!success) {
- error.insert(0, "Error calling EnumerateKnownBluetoothLowEnergyServices: ");
- LogPollingError(error.c_str(), 0);
- return false;
- }
- for (const auto& service : services) {
- auto service_state = std::make_unique<ServiceRecordState>();
- service_state->gatt_uuid =
- BluetoothLowEnergyUuidToBluetoothUuid(service->uuid);
- service_state->attribute_handle = service->attribute_handle;
- service_record_states->push_back(std::move(service_state));
- }
- return true;
- }
- // Each GATT service of a BLE device will be listed on the machine as a BLE
- // device interface with a matching service attribute handle. This interface
- // lists all GATT service devices and matches them back to correspond GATT
- // service of the BLE device according to their address and included service
- // attribute handles, as we did not find a more neat way to bond them.
- bool BluetoothTaskManagerWin::SearchForGattServiceDevicePaths(
- const std::string device_address,
- std::vector<std::unique_ptr<ServiceRecordState>>* service_record_states) {
- std::string error;
- // List all known GATT service devices on the machine.
- std::vector<std::unique_ptr<win::BluetoothLowEnergyDeviceInfo>>
- gatt_service_devices;
- bool success =
- le_wrapper_->EnumerateKnownBluetoothLowEnergyGattServiceDevices(
- &gatt_service_devices, &error);
- if (!success) {
- error.insert(
- 0,
- "Error calling EnumerateKnownBluetoothLowEnergyGattServiceDevices: ");
- LogPollingError(error.c_str(), 0);
- return false;
- }
- for (const auto& gatt_service_device : gatt_service_devices) {
- // Only care about the service devices with |device_address|.
- if (BluetoothAddressToCanonicalString(gatt_service_device->address) !=
- device_address) {
- continue;
- }
- // Discover this service device's contained services.
- std::vector<std::unique_ptr<win::BluetoothLowEnergyServiceInfo>>
- gatt_services;
- if (!le_wrapper_->EnumerateKnownBluetoothLowEnergyServices(
- gatt_service_device->path, &gatt_services, &error)) {
- error.insert(0,
- "Error calling EnumerateKnownBluetoothLowEnergyServices: ");
- LogPollingError(error.c_str(), 0);
- continue;
- }
- // Usually each service device correspond to one Gatt service.
- if (gatt_services.size() > 1) {
- LOG(WARNING) << "This GATT service device contains more than one ("
- << gatt_services.size() << ") services";
- }
- // Associate service device to corresponding service record. Attribute
- // handle is unique on one device.
- for (const auto& gatt_service : gatt_services) {
- for (const auto& service_record_state : *service_record_states) {
- if (service_record_state->attribute_handle ==
- gatt_service->attribute_handle) {
- service_record_state->path = gatt_service_device->path;
- break;
- }
- }
- }
- }
- // Service devices are known and available for enumeration shortly after a
- // a service is known. If we are searching for service device paths in that
- // short window, we won't have a service device path for every service.
- for (const auto& service_record_state : *service_record_states) {
- if (service_record_state->path.empty())
- return false;
- }
- return true;
- }
- void BluetoothTaskManagerWin::GetGattIncludedCharacteristics(
- base::FilePath service_path,
- BluetoothUUID uuid,
- uint16_t attribute_handle,
- GetGattIncludedCharacteristicsCallback callback) {
- HRESULT hr = S_OK;
- std::unique_ptr<BTH_LE_GATT_CHARACTERISTIC> win_characteristics_info;
- uint16_t number_of_charateristics = 0;
- BTH_LE_GATT_SERVICE win_service;
- if (BluetoothUUIDToWinBLEUUID(uuid, &(win_service.ServiceUuid))) {
- win_service.AttributeHandle = attribute_handle;
- hr = le_wrapper_->ReadCharacteristicsOfAService(service_path, &win_service,
- &win_characteristics_info,
- &number_of_charateristics);
- } else {
- hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
- }
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), std::move(win_characteristics_info),
- number_of_charateristics, hr));
- }
- void BluetoothTaskManagerWin::GetGattIncludedDescriptors(
- base::FilePath service_path,
- BTH_LE_GATT_CHARACTERISTIC characteristic,
- GetGattIncludedDescriptorsCallback callback) {
- std::unique_ptr<BTH_LE_GATT_DESCRIPTOR> win_descriptors_info;
- uint16_t number_of_descriptors = 0;
- HRESULT hr = le_wrapper_->ReadDescriptorsOfACharacteristic(
- service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic),
- &win_descriptors_info, &number_of_descriptors);
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), std::move(win_descriptors_info),
- number_of_descriptors, hr));
- }
- void BluetoothTaskManagerWin::ReadGattCharacteristicValue(
- base::FilePath service_path,
- BTH_LE_GATT_CHARACTERISTIC characteristic,
- ReadGattCharacteristicValueCallback callback) {
- std::unique_ptr<BTH_LE_GATT_CHARACTERISTIC_VALUE> win_characteristic_value;
- HRESULT hr = le_wrapper_->ReadCharacteristicValue(
- service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic),
- &win_characteristic_value);
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback),
- std::move(win_characteristic_value), hr));
- }
- void BluetoothTaskManagerWin::WriteGattCharacteristicValue(
- base::FilePath service_path,
- BTH_LE_GATT_CHARACTERISTIC characteristic,
- std::vector<uint8_t> new_value,
- ULONG flags,
- HResultCallback callback) {
- ULONG length = (ULONG)(sizeof(ULONG) + new_value.size());
- std::vector<UCHAR> data(length);
- auto* win_new_value =
- reinterpret_cast<PBTH_LE_GATT_CHARACTERISTIC_VALUE>(&data[0]);
- win_new_value->DataSize = (ULONG)new_value.size();
- for (ULONG i = 0; i < new_value.size(); i++)
- win_new_value->Data[i] = new_value[i];
- HRESULT hr = le_wrapper_->WriteCharacteristicValue(
- service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic),
- win_new_value, flags);
- ui_task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(callback), hr));
- }
- void BluetoothTaskManagerWin::RegisterGattCharacteristicValueChangedEvent(
- base::FilePath service_path,
- BTH_LE_GATT_CHARACTERISTIC characteristic,
- BTH_LE_GATT_DESCRIPTOR ccc_descriptor,
- GattEventRegistrationCallback callback,
- const GattCharacteristicValueChangedCallback& registered_callback) {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- BLUETOOTH_GATT_EVENT_HANDLE win_event_handle = NULL;
- BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION win_event_parameter;
- memcpy(&(win_event_parameter.Characteristics[0]), &characteristic,
- sizeof(BTH_LE_GATT_CHARACTERISTIC));
- win_event_parameter.NumCharacteristics = 1;
- PVOID user_event_handle = (PVOID)®istered_callback;
- HRESULT hr = le_wrapper_->RegisterGattEvents(
- service_path, CharacteristicValueChangedEvent, &win_event_parameter,
- &OnGetGattEventWin, user_event_handle, &win_event_handle);
- // Sets the Client Characteristic Configuration descriptor.
- if (SUCCEEDED(hr)) {
- BTH_LE_GATT_DESCRIPTOR_VALUE new_cccd_value;
- RtlZeroMemory(&new_cccd_value, sizeof(new_cccd_value));
- new_cccd_value.DescriptorType = ClientCharacteristicConfiguration;
- if (characteristic.IsNotifiable) {
- new_cccd_value.ClientCharacteristicConfiguration
- .IsSubscribeToNotification = TRUE;
- } else {
- new_cccd_value.ClientCharacteristicConfiguration.IsSubscribeToIndication =
- TRUE;
- }
- hr = le_wrapper_->WriteDescriptorValue(
- service_path, (PBTH_LE_GATT_DESCRIPTOR)(&ccc_descriptor),
- &new_cccd_value);
- }
- if (SUCCEEDED(hr)) {
- std::unique_ptr<CharacteristicValueChangedRegistration> registration(
- new CharacteristicValueChangedRegistration());
- registration->win_event_handle = win_event_handle;
- registration->callback = registered_callback;
- registration->callback_task_runner = ui_task_runner_;
- base::AutoLock auto_lock(GetCharacteristicValueChangedRegistrationsLock());
- GetCharacteristicValueChangedRegistrations()[user_event_handle] =
- std::move(registration);
- }
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), user_event_handle, hr));
- }
- void BluetoothTaskManagerWin::UnregisterGattCharacteristicValueChangedEvent(
- PVOID event_handle) {
- DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- base::AutoLock auto_lock(GetCharacteristicValueChangedRegistrationsLock());
- CharacteristicValueChangedRegistrationMap::const_iterator it =
- GetCharacteristicValueChangedRegistrations().find(event_handle);
- if (it != GetCharacteristicValueChangedRegistrations().end()) {
- le_wrapper_->UnregisterGattEvent(it->second->win_event_handle);
- GetCharacteristicValueChangedRegistrations().erase(event_handle);
- }
- }
- void BluetoothTaskManagerWin::PostGetGattIncludedCharacteristics(
- const base::FilePath& service_path,
- const BluetoothUUID& uuid,
- uint16_t attribute_handle,
- GetGattIncludedCharacteristicsCallback callback) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::GetGattIncludedCharacteristics,
- this, service_path, uuid, attribute_handle,
- std::move(callback)));
- }
- void BluetoothTaskManagerWin::PostGetGattIncludedDescriptors(
- const base::FilePath& service_path,
- const PBTH_LE_GATT_CHARACTERISTIC characteristic,
- GetGattIncludedDescriptorsCallback callback) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::GetGattIncludedDescriptors, this,
- service_path, *characteristic, std::move(callback)));
- }
- void BluetoothTaskManagerWin::PostReadGattCharacteristicValue(
- const base::FilePath& service_path,
- const PBTH_LE_GATT_CHARACTERISTIC characteristic,
- ReadGattCharacteristicValueCallback callback) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::ReadGattCharacteristicValue,
- this, service_path, *characteristic, std::move(callback)));
- }
- void BluetoothTaskManagerWin::PostWriteGattCharacteristicValue(
- const base::FilePath& service_path,
- const PBTH_LE_GATT_CHARACTERISTIC characteristic,
- const std::vector<uint8_t>& new_value,
- ULONG flags,
- HResultCallback callback) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::WriteGattCharacteristicValue,
- this, service_path, *characteristic, new_value, flags,
- std::move(callback)));
- }
- void BluetoothTaskManagerWin::PostRegisterGattCharacteristicValueChangedEvent(
- const base::FilePath& service_path,
- const PBTH_LE_GATT_CHARACTERISTIC characteristic,
- const PBTH_LE_GATT_DESCRIPTOR ccc_descriptor,
- GattEventRegistrationCallback callback,
- const GattCharacteristicValueChangedCallback& registered_callback) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- &BluetoothTaskManagerWin::RegisterGattCharacteristicValueChangedEvent,
- this, service_path, *characteristic, *ccc_descriptor,
- std::move(callback), registered_callback));
- }
- void BluetoothTaskManagerWin::PostUnregisterGattCharacteristicValueChangedEvent(
- PVOID event_handle) {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- bluetooth_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::
- UnregisterGattCharacteristicValueChangedEvent,
- this, event_handle));
- }
- } // namespace device
|