| Index: device/bluetooth/bluetooth_task_manager_win.cc
|
| diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
|
| index 7bfc32b658eda1c961ce5e37e9f423031f114565..db2540b12e77ddf41d8132c8b1ab5a904e590c6a 100644
|
| --- a/device/bluetooth/bluetooth_task_manager_win.cc
|
| +++ b/device/bluetooth/bluetooth_task_manager_win.cc
|
| @@ -17,6 +17,7 @@
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "base/threading/sequenced_worker_pool.h"
|
| #include "base/win/scoped_handle.h"
|
| +#include "device/bluetooth/bluetooth_device.h"
|
| #include "device/bluetooth/bluetooth_init_win.h"
|
| #include "device/bluetooth/bluetooth_low_energy_win.h"
|
| #include "device/bluetooth/bluetooth_service_record_win.h"
|
| @@ -28,21 +29,31 @@ const int kNumThreadsInWorkerPool = 3;
|
| const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
|
| const int kMaxNumDeviceAddressChar = 127;
|
| const int kServiceDiscoveryResultBufferSize = 5000;
|
| -const int kMaxDeviceDiscoveryTimeout = 48;
|
|
|
| -typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
|
| +// 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;
|
|
|
| -std::string BluetoothAddressToString(const BLUETOOTH_ADDRESS& btha) {
|
| - return 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]);
|
| -}
|
| +typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
|
|
|
| -device::BluetoothUUID BluetoothLowEnergyUuidToUBluetoothUuid(
|
| +// Note: The string returned here must have the same format as
|
| +// BluetoothDevice::CanonicalizeAddress.
|
| +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::BluetoothDevice::CanonicalizeAddress(result));
|
| + return result;
|
| +}
|
| +
|
| +device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid(
|
| const BTH_LE_UUID& bth_le_uuid) {
|
| if (bth_le_uuid.IsShortUuid) {
|
| std::string uuid_hex =
|
| @@ -76,7 +87,7 @@ void GetAdapterState(HANDLE adapter_handle,
|
| ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
|
| &adapter_info)) {
|
| name = base::SysWideToUTF8(adapter_info.szName);
|
| - address = BluetoothAddressToString(adapter_info.address);
|
| + address = BluetoothAddressToCanonicalString(adapter_info.address);
|
| powered = !!BluetoothIsConnectable(adapter_handle);
|
| }
|
| state->name = name;
|
| @@ -87,55 +98,13 @@ void GetAdapterState(HANDLE adapter_handle,
|
| void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
|
| device::BluetoothTaskManagerWin::DeviceState* state) {
|
| state->name = base::SysWideToUTF8(device_info.szName);
|
| - state->address = BluetoothAddressToString(device_info.Address);
|
| + 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;
|
| }
|
|
|
| -void DiscoverDeviceServices(
|
| - const std::string& device_address,
|
| - const GUID& protocol_uuid,
|
| - ScopedVector<ServiceRecordState>* service_record_states) {
|
| - // 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;
|
| - HANDLE sdp_handle;
|
| - if (ERROR_SUCCESS !=
|
| - WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) {
|
| - return;
|
| - }
|
| - 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, LUP_RETURN_ALL, &sdp_buffer_size, sdp_result_data)) {
|
| - break;
|
| - }
|
| - ServiceRecordState* service_record_state = new ServiceRecordState();
|
| - service_record_state->name =
|
| - base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
|
| - for (uint64 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(service_record_state);
|
| - }
|
| - WSALookupServiceEnd(sdp_handle);
|
| -}
|
| -
|
| } // namespace
|
|
|
| namespace device {
|
| @@ -168,7 +137,8 @@ BluetoothTaskManagerWin::DeviceState::~DeviceState() {
|
| BluetoothTaskManagerWin::BluetoothTaskManagerWin(
|
| scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
|
| : ui_task_runner_(ui_task_runner),
|
| - discovering_(false) {
|
| + discovering_(false),
|
| + current_logging_batch_count_(0) {
|
| }
|
|
|
| BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
|
| @@ -257,6 +227,38 @@ void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
|
| base::Bind(&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::TimeDelta::FromMilliseconds(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_->RunsTasksOnCurrentThread());
|
| FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
|
| @@ -275,18 +277,11 @@ void BluetoothTaskManagerWin::OnDiscoveryStopped() {
|
| DiscoveryStopped());
|
| }
|
|
|
| -void BluetoothTaskManagerWin::OnDevicesUpdated(
|
| - const ScopedVector<DeviceState>* devices) {
|
| - DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
|
| - FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
|
| - DevicesUpdated(*devices));
|
| -}
|
| -
|
| -void BluetoothTaskManagerWin::OnDevicesDiscovered(
|
| +void BluetoothTaskManagerWin::OnDevicesPolled(
|
| const ScopedVector<DeviceState>* devices) {
|
| DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
|
| - FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
|
| - DevicesDiscovered(*devices));
|
| + FOR_EACH_OBSERVER(
|
| + BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices));
|
| }
|
|
|
| void BluetoothTaskManagerWin::PollAdapter() {
|
| @@ -372,7 +367,7 @@ void BluetoothTaskManagerWin::StopDiscovery() {
|
| base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
|
| }
|
|
|
| -void BluetoothTaskManagerWin::DiscoverDevices(int timeout) {
|
| +void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
|
| DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
|
| if (!discovering_ || !adapter_handle_) {
|
| ui_task_runner_->PostTask(
|
| @@ -381,133 +376,252 @@ void BluetoothTaskManagerWin::DiscoverDevices(int timeout) {
|
| return;
|
| }
|
|
|
| - ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
|
| - SearchDevices(timeout, false, device_list);
|
| - if (device_list->empty()) {
|
| - delete device_list;
|
| - } else {
|
| - DiscoverServices(device_list);
|
| + scoped_ptr<ScopedVector<DeviceState> > device_list(
|
| + new ScopedVector<DeviceState>());
|
| + if (SearchDevices(timeout_multiplier, false, device_list.get())) {
|
| ui_task_runner_->PostTask(
|
| FROM_HERE,
|
| - base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered,
|
| + base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
|
| this,
|
| - base::Owned(device_list)));
|
| + base::Owned(device_list.release())));
|
| }
|
|
|
| - if (timeout < kMaxDeviceDiscoveryTimeout) {
|
| - bluetooth_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&BluetoothTaskManagerWin::DiscoverDevices,
|
| - this,
|
| - timeout + 1));
|
| - } else {
|
| + if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
|
| + ++timeout_multiplier;
|
| + bluetooth_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
|
| +}
|
| +
|
| +void BluetoothTaskManagerWin::GetKnownDevices() {
|
| + scoped_ptr<ScopedVector<DeviceState> > device_list(
|
| + new ScopedVector<DeviceState>());
|
| + if (SearchDevices(1, true, device_list.get())) {
|
| ui_task_runner_->PostTask(
|
| FROM_HERE,
|
| - base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
|
| - discovering_ = false;
|
| + base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
|
| + this,
|
| + base::Owned(device_list.release())));
|
| }
|
| }
|
|
|
| -void BluetoothTaskManagerWin::GetKnownDevices() {
|
| - ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
|
| - SearchDevices(1, true, device_list);
|
| -
|
| - // Search for Bluetooth Low Energy devices
|
| - if (win::IsBluetoothLowEnergySupported()) {
|
| - ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
|
| - std::string error;
|
| - bool success =
|
| - win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
|
| - if (success) {
|
| - for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
|
| - btle_devices.begin();
|
| - iter != btle_devices.end();
|
| - ++iter) {
|
| - win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
|
| -
|
| - DeviceState* device_state = new DeviceState();
|
| - device_state->name = device_info->friendly_name;
|
| - device_state->address = BluetoothAddressToString(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;
|
| -
|
| - ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
|
| - success = win::EnumerateKnownBluetoothLowEnergyServices(
|
| - device_info, &services, &error);
|
| - if (success) {
|
| - for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator
|
| - iter2 = services.begin();
|
| - iter2 != services.end();
|
| - ++iter2) {
|
| - ServiceRecordState* service_state = new ServiceRecordState();
|
| - service_state->gatt_uuid =
|
| - BluetoothLowEnergyUuidToUBluetoothUuid((*iter2)->uuid);
|
| - device_state->service_record_states.push_back(service_state);
|
| - }
|
| - }
|
| - device_list->push_back(device_state);
|
| +bool BluetoothTaskManagerWin::SearchDevices(
|
| + int timeout_multiplier,
|
| + bool search_cached_devices_only,
|
| + ScopedVector<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,
|
| + ScopedVector<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 =
|
| + BluetoothFindFirstDevice(&device_search_params, &device_info);
|
| + if (!handle) {
|
| + int last_error = GetLastError();
|
| + 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) {
|
| + DeviceState* device_state = new DeviceState();
|
| + GetDeviceState(device_info, device_state);
|
| + device_list->push_back(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 (!BluetoothFindNextDevice(handle, &device_info)) {
|
| + int last_error = GetLastError();
|
| + if (last_error == ERROR_NO_MORE_ITEMS) {
|
| + break; // No more items is expected error when done enumerating.
|
| }
|
| + LogPollingError("Error calling BluetoothFindNextDevice", last_error);
|
| + BluetoothFindDeviceClose(handle);
|
| + return false;
|
| }
|
| }
|
|
|
| - if (device_list->empty()) {
|
| - delete device_list;
|
| - return;
|
| + if (!BluetoothFindDeviceClose(handle)) {
|
| + LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError());
|
| + return false;
|
| }
|
| - DiscoverServices(device_list);
|
| - ui_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated,
|
| - this,
|
| - base::Owned(device_list)));
|
| + return true;
|
| }
|
|
|
| -void BluetoothTaskManagerWin::SearchDevices(
|
| - int timeout,
|
| - bool search_cached_devices_only,
|
| +bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
|
| ScopedVector<DeviceState>* device_list) {
|
| - BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = {
|
| - sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS),
|
| - 1, // return authenticated devices
|
| - 1, // return remembered devicess
|
| - search_cached_devices_only ? 0 : 1, // return unknown devices
|
| - 1, // return connected devices
|
| - search_cached_devices_only ? 0 : 1, // issue a new inquiry
|
| - timeout, // timeout for the inquiry in increments of 1.28 seconds
|
| - adapter_handle_
|
| - };
|
| -
|
| - BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 };
|
| - // Issues a device inquiry and waits for |timeout| * 1.28 seconds.
|
| - HBLUETOOTH_DEVICE_FIND handle =
|
| - BluetoothFindFirstDevice(&device_search_params, &device_info);
|
| - if (handle) {
|
| - do {
|
| - DeviceState* device_state = new DeviceState();
|
| - GetDeviceState(device_info, device_state);
|
| - device_list->push_back(device_state);
|
| - } while (BluetoothFindNextDevice(handle, &device_info));
|
| -
|
| - BluetoothFindDeviceClose(handle);
|
| + if (!win::IsBluetoothLowEnergySupported())
|
| + return true; // Bluetooth LE not supported is not an error.
|
| +
|
| + ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
|
| + std::string error;
|
| + bool success =
|
| + win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
|
| + if (!success) {
|
| + LogPollingError(error.c_str(), 0);
|
| + return false;
|
| + }
|
| +
|
| + for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
|
| + btle_devices.begin();
|
| + iter != btle_devices.end();
|
| + ++iter) {
|
| + win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
|
| + DeviceState* device_state = new 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(device_state);
|
| }
|
| + return true;
|
| }
|
|
|
| -void BluetoothTaskManagerWin::DiscoverServices(
|
| - ScopedVector<DeviceState>* device_list) {
|
| +bool BluetoothTaskManagerWin::DiscoverServices(
|
| + ScopedVector<DeviceState>* device_list,
|
| + bool search_cached_services_only) {
|
| DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
|
| net::EnsureWinsockInit();
|
| for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
|
| iter != device_list->end();
|
| ++iter) {
|
| - const std::string device_address = (*iter)->address;
|
| + DeviceState* device = (*iter);
|
| ScopedVector<ServiceRecordState>* service_record_states =
|
| &(*iter)->service_record_states;
|
|
|
| - DiscoverDeviceServices(
|
| - device_address, L2CAP_PROTOCOL_UUID, service_record_states);
|
| + if ((*iter)->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;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
|
| + const std::string& device_address,
|
| + const GUID& protocol_uuid,
|
| + bool search_cached_services_only,
|
| + ScopedVector<ServiceRecordState>* service_record_states) {
|
| + // 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)) {
|
| + LogPollingError("Error calling WSALookupServiceBegin", WSAGetLastError());
|
| + return false;
|
| + }
|
| + 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 false;
|
| + }
|
| + ServiceRecordState* service_record_state = new ServiceRecordState();
|
| + service_record_state->name =
|
| + base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
|
| + for (uint64 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(service_record_state);
|
| + }
|
| + if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
|
| + LogPollingError("Error calling WSALookupServiceEnd", WSAGetLastError());
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
|
| + const base::FilePath& device_path,
|
| + ScopedVector<ServiceRecordState>* service_record_states) {
|
| + if (!win::IsBluetoothLowEnergySupported())
|
| + return true; // Bluetooth LE not supported is not an error.
|
| +
|
| + std::string error;
|
| + ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
|
| + bool success = win::EnumerateKnownBluetoothLowEnergyServices(
|
| + device_path, &services, &error);
|
| + if (!success) {
|
| + LogPollingError(error.c_str(), 0);
|
| + return false;
|
| + }
|
| +
|
| + for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 =
|
| + services.begin();
|
| + iter2 != services.end();
|
| + ++iter2) {
|
| + ServiceRecordState* service_state = new ServiceRecordState();
|
| + service_state->gatt_uuid =
|
| + BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid);
|
| + service_record_states->push_back(service_state);
|
| }
|
| + return true;
|
| }
|
|
|
| } // namespace device
|
|
|