Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Side by Side Diff: device/bluetooth/bluetooth_task_manager_win.cc

Issue 424093004: Improve processing of Bluetooth device discovery on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing, code cleanup, git cl format. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "device/bluetooth/bluetooth_task_manager_win.h" 5 #include "device/bluetooth/bluetooth_task_manager_win.h"
6 6
7 #include <winsock2.h> 7 #include <winsock2.h>
8 8
9 #include <string> 9 #include <string>
10 10
11 #include "base/basictypes.h" 11 #include "base/basictypes.h"
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/memory/ref_counted.h" 13 #include "base/memory/ref_counted.h"
14 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
15 #include "base/sequenced_task_runner.h" 15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
17 #include "base/strings/sys_string_conversions.h" 17 #include "base/strings/sys_string_conversions.h"
18 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/win/scoped_handle.h" 19 #include "base/win/scoped_handle.h"
20 #include "device/bluetooth/bluetooth_device.h"
20 #include "device/bluetooth/bluetooth_init_win.h" 21 #include "device/bluetooth/bluetooth_init_win.h"
21 #include "device/bluetooth/bluetooth_low_energy_win.h" 22 #include "device/bluetooth/bluetooth_low_energy_win.h"
22 #include "device/bluetooth/bluetooth_service_record_win.h" 23 #include "device/bluetooth/bluetooth_service_record_win.h"
23 #include "net/base/winsock_init.h" 24 #include "net/base/winsock_init.h"
24 25
25 namespace { 26 namespace {
26 27
27 const int kNumThreadsInWorkerPool = 3; 28 const int kNumThreadsInWorkerPool = 3;
28 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; 29 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
29 const int kMaxNumDeviceAddressChar = 127; 30 const int kMaxNumDeviceAddressChar = 127;
30 const int kServiceDiscoveryResultBufferSize = 5000; 31 const int kServiceDiscoveryResultBufferSize = 5000;
31 const int kMaxDeviceDiscoveryTimeout = 48; 32
33 // See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time
34 // out for the inquiry, expressed in increments of 1.28 seconds. For example, an
35 // inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum
36 // value for this member is 48. When a value greater than 48 is used, the
37 // calling function immediately fails and returns
38 const int kMaxDeviceDiscoveryTimeoutMultiplier = 48;
32 39
33 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; 40 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
34 41
35 std::string BluetoothAddressToString(const BLUETOOTH_ADDRESS& btha) { 42 // Note: The string returned here must have the same format as
36 return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", 43 // BluetoothDevice::CanonicalizeAddress.
37 btha.rgBytes[5], 44 std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) {
38 btha.rgBytes[4], 45 std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
39 btha.rgBytes[3], 46 btha.rgBytes[5],
40 btha.rgBytes[2], 47 btha.rgBytes[4],
41 btha.rgBytes[1], 48 btha.rgBytes[3],
42 btha.rgBytes[0]); 49 btha.rgBytes[2],
50 btha.rgBytes[1],
51 btha.rgBytes[0]);
52 DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result));
53 return result;
43 } 54 }
44 55
45 device::BluetoothUUID BluetoothLowEnergyUuidToUBluetoothUuid( 56 device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid(
46 const BTH_LE_UUID& bth_le_uuid) { 57 const BTH_LE_UUID& bth_le_uuid) {
47 if (bth_le_uuid.IsShortUuid) { 58 if (bth_le_uuid.IsShortUuid) {
48 std::string uuid_hex = 59 std::string uuid_hex =
49 base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid); 60 base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid);
50 return device::BluetoothUUID(uuid_hex); 61 return device::BluetoothUUID(uuid_hex);
51 } else { 62 } else {
52 return device::BluetoothUUID( 63 return device::BluetoothUUID(
53 base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 64 base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
54 bth_le_uuid.Value.LongUuid.Data1, 65 bth_le_uuid.Value.LongUuid.Data1,
55 bth_le_uuid.Value.LongUuid.Data2, 66 bth_le_uuid.Value.LongUuid.Data2,
(...skipping 13 matching lines...) Expand all
69 void GetAdapterState(HANDLE adapter_handle, 80 void GetAdapterState(HANDLE adapter_handle,
70 device::BluetoothTaskManagerWin::AdapterState* state) { 81 device::BluetoothTaskManagerWin::AdapterState* state) {
71 std::string name; 82 std::string name;
72 std::string address; 83 std::string address;
73 bool powered = false; 84 bool powered = false;
74 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 }; 85 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
75 if (adapter_handle && 86 if (adapter_handle &&
76 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle, 87 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
77 &adapter_info)) { 88 &adapter_info)) {
78 name = base::SysWideToUTF8(adapter_info.szName); 89 name = base::SysWideToUTF8(adapter_info.szName);
79 address = BluetoothAddressToString(adapter_info.address); 90 address = BluetoothAddressToCanonicalString(adapter_info.address);
80 powered = !!BluetoothIsConnectable(adapter_handle); 91 powered = !!BluetoothIsConnectable(adapter_handle);
81 } 92 }
82 state->name = name; 93 state->name = name;
83 state->address = address; 94 state->address = address;
84 state->powered = powered; 95 state->powered = powered;
85 } 96 }
86 97
87 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, 98 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
88 device::BluetoothTaskManagerWin::DeviceState* state) { 99 device::BluetoothTaskManagerWin::DeviceState* state) {
89 state->name = base::SysWideToUTF8(device_info.szName); 100 state->name = base::SysWideToUTF8(device_info.szName);
90 state->address = BluetoothAddressToString(device_info.Address); 101 state->address = BluetoothAddressToCanonicalString(device_info.Address);
91 state->bluetooth_class = device_info.ulClassofDevice; 102 state->bluetooth_class = device_info.ulClassofDevice;
92 state->visible = true; 103 state->visible = true;
93 state->connected = !!device_info.fConnected; 104 state->connected = !!device_info.fConnected;
94 state->authenticated = !!device_info.fAuthenticated; 105 state->authenticated = !!device_info.fAuthenticated;
95 } 106 }
96 107
97 void DiscoverDeviceServices(
98 const std::string& device_address,
99 const GUID& protocol_uuid,
100 ScopedVector<ServiceRecordState>* service_record_states) {
101 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
102 WSAQUERYSET sdp_query;
103 ZeroMemory(&sdp_query, sizeof(sdp_query));
104 sdp_query.dwSize = sizeof(sdp_query);
105 GUID protocol = protocol_uuid;
106 sdp_query.lpServiceClassId = &protocol;
107 sdp_query.dwNameSpace = NS_BTH;
108 wchar_t device_address_context[kMaxNumDeviceAddressChar];
109 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
110 device_address_context, kMaxNumDeviceAddressChar);
111 device_address_context[length] = NULL;
112 sdp_query.lpszContext = device_address_context;
113 HANDLE sdp_handle;
114 if (ERROR_SUCCESS !=
115 WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) {
116 return;
117 }
118 char sdp_buffer[kServiceDiscoveryResultBufferSize];
119 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
120 while (true) {
121 DWORD sdp_buffer_size = sizeof(sdp_buffer);
122 if (ERROR_SUCCESS !=
123 WSALookupServiceNext(
124 sdp_handle, LUP_RETURN_ALL, &sdp_buffer_size, sdp_result_data)) {
125 break;
126 }
127 ServiceRecordState* service_record_state = new ServiceRecordState();
128 service_record_state->name =
129 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
130 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
131 service_record_state->sdp_bytes.push_back(
132 sdp_result_data->lpBlob->pBlobData[i]);
133 }
134 service_record_states->push_back(service_record_state);
135 }
136 WSALookupServiceEnd(sdp_handle);
137 }
138
139 } // namespace 108 } // namespace
140 109
141 namespace device { 110 namespace device {
142 111
143 // static 112 // static
144 const int BluetoothTaskManagerWin::kPollIntervalMs = 500; 113 const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
145 114
146 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) { 115 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) {
147 } 116 }
148 117
(...skipping 12 matching lines...) Expand all
161 connected(false), 130 connected(false),
162 authenticated(false) { 131 authenticated(false) {
163 } 132 }
164 133
165 BluetoothTaskManagerWin::DeviceState::~DeviceState() { 134 BluetoothTaskManagerWin::DeviceState::~DeviceState() {
166 } 135 }
167 136
168 BluetoothTaskManagerWin::BluetoothTaskManagerWin( 137 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
169 scoped_refptr<base::SequencedTaskRunner> ui_task_runner) 138 scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
170 : ui_task_runner_(ui_task_runner), 139 : ui_task_runner_(ui_task_runner),
171 discovering_(false) { 140 discovering_(false),
141 current_logging_batch_count_(0) {
172 } 142 }
173 143
174 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { 144 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
175 } 145 }
176 146
177 void BluetoothTaskManagerWin::AddObserver(Observer* observer) { 147 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
178 DCHECK(observer); 148 DCHECK(observer);
179 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 149 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
180 observers_.AddObserver(observer); 150 observers_.AddObserver(observer);
181 } 151 }
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); 220 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
251 } 221 }
252 222
253 void BluetoothTaskManagerWin::PostStopDiscoveryTask() { 223 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
254 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 224 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
255 bluetooth_task_runner_->PostTask( 225 bluetooth_task_runner_->PostTask(
256 FROM_HERE, 226 FROM_HERE,
257 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); 227 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
258 } 228 }
259 229
230 void BluetoothTaskManagerWin::LogPollingError(const char* message,
231 int win32_error) {
232 const int kLogPeriodInMilliseconds = 60 * 1000;
233 const int kMaxMessagesPerLogPeriod = 10;
234
235 // Check if we need to discard this message
236 if (!current_logging_batch_ticks_.is_null()) {
237 if (base::TimeTicks::Now() - current_logging_batch_ticks_ <=
238 base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) {
239 if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod)
240 return;
241 } else {
242 // The batch expired, reset it to "null".
243 current_logging_batch_ticks_ = base::TimeTicks();
244 }
245 }
246
247 // Keep track of this batch of messages
248 if (current_logging_batch_ticks_.is_null()) {
249 current_logging_batch_ticks_ = base::TimeTicks::Now();
250 current_logging_batch_count_ = 0;
251 }
252 current_logging_batch_count_++;
xiyuan 2014/07/30 21:41:47 nit: ++current_logging_batch_count_;
rpaquay 2014/07/30 22:34:25 Done.
253
254 // Log the message
255 if (win32_error == 0)
256 LOG(WARNING) << message;
257 else
258 LOG(WARNING) << message << ": "
259 << logging::SystemErrorCodeToString(win32_error);
xiyuan 2014/07/30 21:41:47 nit: indent looks strange.
rpaquay 2014/07/30 22:34:25 Done.
260 }
261
260 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { 262 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
261 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 263 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
262 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 264 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
263 AdapterStateChanged(*state)); 265 AdapterStateChanged(*state));
264 } 266 }
265 267
266 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { 268 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
267 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 269 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
268 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 270 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
269 DiscoveryStarted(success)); 271 DiscoveryStarted(success));
270 } 272 }
271 273
272 void BluetoothTaskManagerWin::OnDiscoveryStopped() { 274 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
273 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 275 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
274 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 276 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
275 DiscoveryStopped()); 277 DiscoveryStopped());
276 } 278 }
277 279
278 void BluetoothTaskManagerWin::OnDevicesUpdated( 280 void BluetoothTaskManagerWin::OnDevicesPolled(
279 const ScopedVector<DeviceState>* devices) { 281 const ScopedVector<DeviceState>* devices) {
280 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 282 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
281 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 283 FOR_EACH_OBSERVER(
282 DevicesUpdated(*devices)); 284 BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices));
283 }
284
285 void BluetoothTaskManagerWin::OnDevicesDiscovered(
286 const ScopedVector<DeviceState>* devices) {
287 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
288 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
289 DevicesDiscovered(*devices));
290 } 285 }
291 286
292 void BluetoothTaskManagerWin::PollAdapter() { 287 void BluetoothTaskManagerWin::PollAdapter() {
293 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 288 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
294 289
295 // Skips updating the adapter info if the adapter is in discovery mode. 290 // Skips updating the adapter info if the adapter is in discovery mode.
296 if (!discovering_) { 291 if (!discovering_) {
297 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = 292 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
298 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; 293 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
299 if (adapter_handle_) 294 if (adapter_handle_)
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 } 360 }
366 361
367 void BluetoothTaskManagerWin::StopDiscovery() { 362 void BluetoothTaskManagerWin::StopDiscovery() {
368 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 363 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
369 discovering_ = false; 364 discovering_ = false;
370 ui_task_runner_->PostTask( 365 ui_task_runner_->PostTask(
371 FROM_HERE, 366 FROM_HERE,
372 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 367 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
373 } 368 }
374 369
375 void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { 370 void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
376 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 371 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
377 if (!discovering_ || !adapter_handle_) { 372 if (!discovering_ || !adapter_handle_) {
378 ui_task_runner_->PostTask( 373 ui_task_runner_->PostTask(
379 FROM_HERE, 374 FROM_HERE,
380 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 375 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
381 return; 376 return;
382 } 377 }
383 378
384 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); 379 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
xiyuan 2014/07/30 21:41:47 Would we leak |device_list| if SearchDevices() ret
rpaquay 2014/07/30 22:34:25 Done.
385 SearchDevices(timeout, false, device_list); 380 if (SearchDevices(timeout_multiplier, false, device_list)) {
386 if (device_list->empty()) {
387 delete device_list;
388 } else {
389 DiscoverServices(device_list);
390 ui_task_runner_->PostTask( 381 ui_task_runner_->PostTask(
391 FROM_HERE, 382 FROM_HERE,
392 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, 383 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
393 this, 384 this,
394 base::Owned(device_list))); 385 base::Owned(device_list)));
395 } 386 }
396 387
397 if (timeout < kMaxDeviceDiscoveryTimeout) { 388 if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
398 bluetooth_task_runner_->PostTask( 389 timeout_multiplier++;
xiyuan 2014/07/30 21:41:47 nit: ++timeout_multiplier;
rpaquay 2014/07/30 22:34:25 Done.
399 FROM_HERE, 390 bluetooth_task_runner_->PostTask(
400 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, 391 FROM_HERE,
401 this, 392 base::Bind(
402 timeout + 1)); 393 &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
403 } else { 394 }
395
396 void BluetoothTaskManagerWin::GetKnownDevices() {
397 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
xiyuan 2014/07/30 21:41:47 Same here.
rpaquay 2014/07/30 22:34:25 Done.
398 if (SearchDevices(1, true, device_list)) {
404 ui_task_runner_->PostTask( 399 ui_task_runner_->PostTask(
405 FROM_HERE, 400 FROM_HERE,
406 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 401 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
407 discovering_ = false; 402 this,
408 } 403 base::Owned(device_list)));
409 } 404 }
410 405 }
411 void BluetoothTaskManagerWin::GetKnownDevices() { 406
412 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); 407 bool BluetoothTaskManagerWin::SearchDevices(
413 SearchDevices(1, true, device_list); 408 int timeout_multiplier,
414
415 // Search for Bluetooth Low Energy devices
416 if (win::IsBluetoothLowEnergySupported()) {
417 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
418 std::string error;
419 bool success =
420 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
421 if (success) {
422 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
423 btle_devices.begin();
424 iter != btle_devices.end();
425 ++iter) {
426 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
427
428 DeviceState* device_state = new DeviceState();
429 device_state->name = device_info->friendly_name;
430 device_state->address = BluetoothAddressToString(device_info->address);
431 device_state->visible = device_info->visible;
432 device_state->authenticated = device_info->authenticated;
433 device_state->connected = device_info->connected;
434 device_state->path = device_info->path;
435
436 ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
437 success = win::EnumerateKnownBluetoothLowEnergyServices(
438 device_info, &services, &error);
439 if (success) {
440 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator
441 iter2 = services.begin();
442 iter2 != services.end();
443 ++iter2) {
444 ServiceRecordState* service_state = new ServiceRecordState();
445 service_state->gatt_uuid =
446 BluetoothLowEnergyUuidToUBluetoothUuid((*iter2)->uuid);
447 device_state->service_record_states.push_back(service_state);
448 }
449 }
450 device_list->push_back(device_state);
451 }
452 }
453 }
454
455 if (device_list->empty()) {
456 delete device_list;
457 return;
458 }
459 DiscoverServices(device_list);
460 ui_task_runner_->PostTask(
461 FROM_HERE,
462 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated,
463 this,
464 base::Owned(device_list)));
465 }
466
467 void BluetoothTaskManagerWin::SearchDevices(
468 int timeout,
469 bool search_cached_devices_only, 409 bool search_cached_devices_only,
470 ScopedVector<DeviceState>* device_list) { 410 ScopedVector<DeviceState>* device_list) {
471 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { 411 return SearchClassicDevices(
472 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), 412 timeout_multiplier, search_cached_devices_only, device_list) &&
473 1, // return authenticated devices 413 SearchLowEnergyDevices(device_list) &&
474 1, // return remembered devicess 414 DiscoverServices(device_list, search_cached_devices_only);
475 search_cached_devices_only ? 0 : 1, // return unknown devices 415 }
476 1, // return connected devices 416
477 search_cached_devices_only ? 0 : 1, // issue a new inquiry 417 bool BluetoothTaskManagerWin::SearchClassicDevices(
478 timeout, // timeout for the inquiry in increments of 1.28 seconds 418 int timeout_multiplier,
479 adapter_handle_ 419 bool search_cached_devices_only,
480 }; 420 ScopedVector<DeviceState>* device_list) {
481 421 // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds.
482 BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; 422 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params;
483 // Issues a device inquiry and waits for |timeout| * 1.28 seconds. 423 ZeroMemory(&device_search_params, sizeof(device_search_params));
424 device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
425 device_search_params.fReturnAuthenticated = 1;
426 device_search_params.fReturnRemembered = 1;
427 device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1);
428 device_search_params.fReturnConnected = 1;
429 device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1);
430 device_search_params.cTimeoutMultiplier = timeout_multiplier;
431
432 BLUETOOTH_DEVICE_INFO device_info;
433 ZeroMemory(&device_info, sizeof(device_info));
434 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
484 HBLUETOOTH_DEVICE_FIND handle = 435 HBLUETOOTH_DEVICE_FIND handle =
485 BluetoothFindFirstDevice(&device_search_params, &device_info); 436 BluetoothFindFirstDevice(&device_search_params, &device_info);
486 if (handle) { 437 if (!handle) {
487 do { 438 int last_error = GetLastError();
488 DeviceState* device_state = new DeviceState(); 439 if (last_error == ERROR_NO_MORE_ITEMS) {
489 GetDeviceState(device_info, device_state); 440 return true; // No devices is not an error.
490 device_list->push_back(device_state); 441 }
491 } while (BluetoothFindNextDevice(handle, &device_info)); 442 LogPollingError("Error calling BluetoothFindFirstDevice", last_error);
492 443 return false;
493 BluetoothFindDeviceClose(handle); 444 }
494 } 445
495 } 446 while (true) {
496 447 DeviceState* device_state = new DeviceState();
497 void BluetoothTaskManagerWin::DiscoverServices( 448 GetDeviceState(device_info, device_state);
449 device_list->push_back(device_state);
450
451 // Reset device info before next call (as a safety precaution).
452 ZeroMemory(&device_info, sizeof(device_info));
453 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
454 if (!BluetoothFindNextDevice(handle, &device_info)) {
455 int last_error = GetLastError();
456 if (last_error == ERROR_NO_MORE_ITEMS) {
457 break; // No more items is expected error when done enumerating.
458 }
459 LogPollingError("Error calling BluetoothFindNextDevice", last_error);
460 BluetoothFindDeviceClose(handle);
461 return false;
462 }
463 }
464
465 if (!BluetoothFindDeviceClose(handle)) {
466 LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError());
467 return false;
468 }
469 return true;
470 }
471
472 bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
498 ScopedVector<DeviceState>* device_list) { 473 ScopedVector<DeviceState>* device_list) {
474 if (!win::IsBluetoothLowEnergySupported())
475 return true; // Bluetooth LE not supported is not an error.
476
477 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
478 std::string error;
479 bool success =
480 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
481 if (!success) {
482 LogPollingError(error.c_str(), 0);
483 return false;
484 }
485
486 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
487 btle_devices.begin();
488 iter != btle_devices.end();
489 ++iter) {
490 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
491 DeviceState* device_state = new DeviceState();
492 device_state->name = device_info->friendly_name;
493 device_state->address =
494 BluetoothAddressToCanonicalString(device_info->address);
495 device_state->visible = device_info->visible;
496 device_state->authenticated = device_info->authenticated;
497 device_state->connected = device_info->connected;
498 device_state->path = device_info->path;
499 device_list->push_back(device_state);
500 }
501 return true;
502 }
503
504 bool BluetoothTaskManagerWin::DiscoverServices(
505 ScopedVector<DeviceState>* device_list,
506 bool search_cached_services_only) {
499 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 507 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
500 net::EnsureWinsockInit(); 508 net::EnsureWinsockInit();
501 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); 509 for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
502 iter != device_list->end(); 510 iter != device_list->end();
503 ++iter) { 511 ++iter) {
504 const std::string device_address = (*iter)->address; 512 DeviceState* device = (*iter);
505 ScopedVector<ServiceRecordState>* service_record_states = 513 ScopedVector<ServiceRecordState>* service_record_states =
506 &(*iter)->service_record_states; 514 &(*iter)->service_record_states;
507 515
508 DiscoverDeviceServices( 516 if ((*iter)->is_bluetooth_classic()) {
509 device_address, L2CAP_PROTOCOL_UUID, service_record_states); 517 if (!DiscoverClassicDeviceServices(device->address,
510 } 518 L2CAP_PROTOCOL_UUID,
519 search_cached_services_only,
520 service_record_states)) {
521 return false;
522 }
523 } else {
524 if (!DiscoverLowEnergyDeviceServices(device->path,
525 service_record_states)) {
526 return false;
527 }
528 }
529 }
530 return true;
531 }
532
533 bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
534 const std::string& device_address,
535 const GUID& protocol_uuid,
536 bool search_cached_services_only,
537 ScopedVector<ServiceRecordState>* service_record_states) {
538 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
539 WSAQUERYSET sdp_query;
540 ZeroMemory(&sdp_query, sizeof(sdp_query));
541 sdp_query.dwSize = sizeof(sdp_query);
542 GUID protocol = protocol_uuid;
543 sdp_query.lpServiceClassId = &protocol;
544 sdp_query.dwNameSpace = NS_BTH;
545 wchar_t device_address_context[kMaxNumDeviceAddressChar];
546 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
547 device_address_context, kMaxNumDeviceAddressChar);
548 device_address_context[length] = NULL;
549 sdp_query.lpszContext = device_address_context;
550 DWORD control_flags = LUP_RETURN_ALL;
551 // See http://goo.gl/t1Hulo: "Applications should generally specify
552 // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached
553 // information and establish an over-the-air SDP connection to the specified
554 // device to perform the SDP search. This non-cached operation may take
555 // several seconds (whereas a cached search returns quickly)."
556 // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list
557 // of services for devices which have not been discovered before.
558 if (!search_cached_services_only)
559 control_flags |= LUP_FLUSHCACHE;
560 HANDLE sdp_handle;
561 if (ERROR_SUCCESS !=
562 WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) {
563 LogPollingError("Error calling WSALookupServiceBegin", WSAGetLastError());
564 return false;
565 }
566 char sdp_buffer[kServiceDiscoveryResultBufferSize];
567 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
568 while (true) {
569 DWORD sdp_buffer_size = sizeof(sdp_buffer);
570 if (ERROR_SUCCESS !=
571 WSALookupServiceNext(
572 sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) {
573 int last_error = WSAGetLastError();
574 if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) {
575 break;
576 }
577 LogPollingError("Error calling WSALookupServiceNext", last_error);
578 WSALookupServiceEnd(sdp_handle);
579 return false;
580 }
581 ServiceRecordState* service_record_state = new ServiceRecordState();
582 service_record_state->name =
583 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
584 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
585 service_record_state->sdp_bytes.push_back(
586 sdp_result_data->lpBlob->pBlobData[i]);
587 }
588 service_record_states->push_back(service_record_state);
589 }
590 if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
591 LogPollingError("Error calling WSALookupServiceEnd", WSAGetLastError());
592 return false;
593 }
594
595 return true;
596 }
597
598 bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
599 const base::FilePath& device_path,
600 ScopedVector<ServiceRecordState>* service_record_states) {
601 if (!win::IsBluetoothLowEnergySupported())
602 return true; // Bluetooth LE not supported is not an error.
603
604 std::string error;
605 ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
606 bool success = win::EnumerateKnownBluetoothLowEnergyServices(
607 device_path, &services, &error);
608 if (!success) {
609 LogPollingError(error.c_str(), 0);
610 return false;
611 }
612
613 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 =
614 services.begin();
615 iter2 != services.end();
616 ++iter2) {
617 ServiceRecordState* service_state = new ServiceRecordState();
618 service_state->gatt_uuid =
619 BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid);
620 service_record_states->push_back(service_state);
621 }
622 return true;
511 } 623 }
512 624
513 } // namespace device 625 } // namespace device
OLDNEW
« device/bluetooth/bluetooth_device_win.cc ('K') | « device/bluetooth/bluetooth_task_manager_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698