OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |