Chromium Code Reviews| 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 |