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 |