| 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_; |
| 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); |
| 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 scoped_ptr<ScopedVector<DeviceState> > device_list( |
| 385 SearchDevices(timeout, false, device_list); | 380 new ScopedVector<DeviceState>()); |
| 386 if (device_list->empty()) { | 381 if (SearchDevices(timeout_multiplier, false, device_list.get())) { |
| 387 delete device_list; | |
| 388 } else { | |
| 389 DiscoverServices(device_list); | |
| 390 ui_task_runner_->PostTask( | 382 ui_task_runner_->PostTask( |
| 391 FROM_HERE, | 383 FROM_HERE, |
| 392 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, | 384 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, |
| 393 this, | 385 this, |
| 394 base::Owned(device_list))); | 386 base::Owned(device_list.release()))); |
| 395 } | 387 } |
| 396 | 388 |
| 397 if (timeout < kMaxDeviceDiscoveryTimeout) { | 389 if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier) |
| 398 bluetooth_task_runner_->PostTask( | 390 ++timeout_multiplier; |
| 399 FROM_HERE, | 391 bluetooth_task_runner_->PostTask( |
| 400 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, | 392 FROM_HERE, |
| 401 this, | 393 base::Bind( |
| 402 timeout + 1)); | 394 &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier)); |
| 403 } else { | 395 } |
| 396 |
| 397 void BluetoothTaskManagerWin::GetKnownDevices() { |
| 398 scoped_ptr<ScopedVector<DeviceState> > device_list( |
| 399 new ScopedVector<DeviceState>()); |
| 400 if (SearchDevices(1, true, device_list.get())) { |
| 404 ui_task_runner_->PostTask( | 401 ui_task_runner_->PostTask( |
| 405 FROM_HERE, | 402 FROM_HERE, |
| 406 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); | 403 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, |
| 407 discovering_ = false; | 404 this, |
| 408 } | 405 base::Owned(device_list.release()))); |
| 409 } | 406 } |
| 410 | 407 } |
| 411 void BluetoothTaskManagerWin::GetKnownDevices() { | 408 |
| 412 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); | 409 bool BluetoothTaskManagerWin::SearchDevices( |
| 413 SearchDevices(1, true, device_list); | 410 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, | 411 bool search_cached_devices_only, |
| 470 ScopedVector<DeviceState>* device_list) { | 412 ScopedVector<DeviceState>* device_list) { |
| 471 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { | 413 return SearchClassicDevices( |
| 472 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), | 414 timeout_multiplier, search_cached_devices_only, device_list) && |
| 473 1, // return authenticated devices | 415 SearchLowEnergyDevices(device_list) && |
| 474 1, // return remembered devicess | 416 DiscoverServices(device_list, search_cached_devices_only); |
| 475 search_cached_devices_only ? 0 : 1, // return unknown devices | 417 } |
| 476 1, // return connected devices | 418 |
| 477 search_cached_devices_only ? 0 : 1, // issue a new inquiry | 419 bool BluetoothTaskManagerWin::SearchClassicDevices( |
| 478 timeout, // timeout for the inquiry in increments of 1.28 seconds | 420 int timeout_multiplier, |
| 479 adapter_handle_ | 421 bool search_cached_devices_only, |
| 480 }; | 422 ScopedVector<DeviceState>* device_list) { |
| 481 | 423 // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds. |
| 482 BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; | 424 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params; |
| 483 // Issues a device inquiry and waits for |timeout| * 1.28 seconds. | 425 ZeroMemory(&device_search_params, sizeof(device_search_params)); |
| 426 device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS); |
| 427 device_search_params.fReturnAuthenticated = 1; |
| 428 device_search_params.fReturnRemembered = 1; |
| 429 device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1); |
| 430 device_search_params.fReturnConnected = 1; |
| 431 device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1); |
| 432 device_search_params.cTimeoutMultiplier = timeout_multiplier; |
| 433 |
| 434 BLUETOOTH_DEVICE_INFO device_info; |
| 435 ZeroMemory(&device_info, sizeof(device_info)); |
| 436 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); |
| 484 HBLUETOOTH_DEVICE_FIND handle = | 437 HBLUETOOTH_DEVICE_FIND handle = |
| 485 BluetoothFindFirstDevice(&device_search_params, &device_info); | 438 BluetoothFindFirstDevice(&device_search_params, &device_info); |
| 486 if (handle) { | 439 if (!handle) { |
| 487 do { | 440 int last_error = GetLastError(); |
| 488 DeviceState* device_state = new DeviceState(); | 441 if (last_error == ERROR_NO_MORE_ITEMS) { |
| 489 GetDeviceState(device_info, device_state); | 442 return true; // No devices is not an error. |
| 490 device_list->push_back(device_state); | 443 } |
| 491 } while (BluetoothFindNextDevice(handle, &device_info)); | 444 LogPollingError("Error calling BluetoothFindFirstDevice", last_error); |
| 492 | 445 return false; |
| 493 BluetoothFindDeviceClose(handle); | 446 } |
| 494 } | 447 |
| 495 } | 448 while (true) { |
| 496 | 449 DeviceState* device_state = new DeviceState(); |
| 497 void BluetoothTaskManagerWin::DiscoverServices( | 450 GetDeviceState(device_info, device_state); |
| 451 device_list->push_back(device_state); |
| 452 |
| 453 // Reset device info before next call (as a safety precaution). |
| 454 ZeroMemory(&device_info, sizeof(device_info)); |
| 455 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); |
| 456 if (!BluetoothFindNextDevice(handle, &device_info)) { |
| 457 int last_error = GetLastError(); |
| 458 if (last_error == ERROR_NO_MORE_ITEMS) { |
| 459 break; // No more items is expected error when done enumerating. |
| 460 } |
| 461 LogPollingError("Error calling BluetoothFindNextDevice", last_error); |
| 462 BluetoothFindDeviceClose(handle); |
| 463 return false; |
| 464 } |
| 465 } |
| 466 |
| 467 if (!BluetoothFindDeviceClose(handle)) { |
| 468 LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError()); |
| 469 return false; |
| 470 } |
| 471 return true; |
| 472 } |
| 473 |
| 474 bool BluetoothTaskManagerWin::SearchLowEnergyDevices( |
| 498 ScopedVector<DeviceState>* device_list) { | 475 ScopedVector<DeviceState>* device_list) { |
| 476 if (!win::IsBluetoothLowEnergySupported()) |
| 477 return true; // Bluetooth LE not supported is not an error. |
| 478 |
| 479 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices; |
| 480 std::string error; |
| 481 bool success = |
| 482 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error); |
| 483 if (!success) { |
| 484 LogPollingError(error.c_str(), 0); |
| 485 return false; |
| 486 } |
| 487 |
| 488 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter = |
| 489 btle_devices.begin(); |
| 490 iter != btle_devices.end(); |
| 491 ++iter) { |
| 492 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter); |
| 493 DeviceState* device_state = new DeviceState(); |
| 494 device_state->name = device_info->friendly_name; |
| 495 device_state->address = |
| 496 BluetoothAddressToCanonicalString(device_info->address); |
| 497 device_state->visible = device_info->visible; |
| 498 device_state->authenticated = device_info->authenticated; |
| 499 device_state->connected = device_info->connected; |
| 500 device_state->path = device_info->path; |
| 501 device_list->push_back(device_state); |
| 502 } |
| 503 return true; |
| 504 } |
| 505 |
| 506 bool BluetoothTaskManagerWin::DiscoverServices( |
| 507 ScopedVector<DeviceState>* device_list, |
| 508 bool search_cached_services_only) { |
| 499 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); | 509 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
| 500 net::EnsureWinsockInit(); | 510 net::EnsureWinsockInit(); |
| 501 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); | 511 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); |
| 502 iter != device_list->end(); | 512 iter != device_list->end(); |
| 503 ++iter) { | 513 ++iter) { |
| 504 const std::string device_address = (*iter)->address; | 514 DeviceState* device = (*iter); |
| 505 ScopedVector<ServiceRecordState>* service_record_states = | 515 ScopedVector<ServiceRecordState>* service_record_states = |
| 506 &(*iter)->service_record_states; | 516 &(*iter)->service_record_states; |
| 507 | 517 |
| 508 DiscoverDeviceServices( | 518 if ((*iter)->is_bluetooth_classic()) { |
| 509 device_address, L2CAP_PROTOCOL_UUID, service_record_states); | 519 if (!DiscoverClassicDeviceServices(device->address, |
| 510 } | 520 L2CAP_PROTOCOL_UUID, |
| 521 search_cached_services_only, |
| 522 service_record_states)) { |
| 523 return false; |
| 524 } |
| 525 } else { |
| 526 if (!DiscoverLowEnergyDeviceServices(device->path, |
| 527 service_record_states)) { |
| 528 return false; |
| 529 } |
| 530 } |
| 531 } |
| 532 return true; |
| 533 } |
| 534 |
| 535 bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices( |
| 536 const std::string& device_address, |
| 537 const GUID& protocol_uuid, |
| 538 bool search_cached_services_only, |
| 539 ScopedVector<ServiceRecordState>* service_record_states) { |
| 540 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. |
| 541 WSAQUERYSET sdp_query; |
| 542 ZeroMemory(&sdp_query, sizeof(sdp_query)); |
| 543 sdp_query.dwSize = sizeof(sdp_query); |
| 544 GUID protocol = protocol_uuid; |
| 545 sdp_query.lpServiceClassId = &protocol; |
| 546 sdp_query.dwNameSpace = NS_BTH; |
| 547 wchar_t device_address_context[kMaxNumDeviceAddressChar]; |
| 548 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( |
| 549 device_address_context, kMaxNumDeviceAddressChar); |
| 550 device_address_context[length] = NULL; |
| 551 sdp_query.lpszContext = device_address_context; |
| 552 DWORD control_flags = LUP_RETURN_ALL; |
| 553 // See http://goo.gl/t1Hulo: "Applications should generally specify |
| 554 // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached |
| 555 // information and establish an over-the-air SDP connection to the specified |
| 556 // device to perform the SDP search. This non-cached operation may take |
| 557 // several seconds (whereas a cached search returns quickly)." |
| 558 // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list |
| 559 // of services for devices which have not been discovered before. |
| 560 if (!search_cached_services_only) |
| 561 control_flags |= LUP_FLUSHCACHE; |
| 562 HANDLE sdp_handle; |
| 563 if (ERROR_SUCCESS != |
| 564 WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) { |
| 565 LogPollingError("Error calling WSALookupServiceBegin", WSAGetLastError()); |
| 566 return false; |
| 567 } |
| 568 char sdp_buffer[kServiceDiscoveryResultBufferSize]; |
| 569 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); |
| 570 while (true) { |
| 571 DWORD sdp_buffer_size = sizeof(sdp_buffer); |
| 572 if (ERROR_SUCCESS != |
| 573 WSALookupServiceNext( |
| 574 sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) { |
| 575 int last_error = WSAGetLastError(); |
| 576 if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) { |
| 577 break; |
| 578 } |
| 579 LogPollingError("Error calling WSALookupServiceNext", last_error); |
| 580 WSALookupServiceEnd(sdp_handle); |
| 581 return false; |
| 582 } |
| 583 ServiceRecordState* service_record_state = new ServiceRecordState(); |
| 584 service_record_state->name = |
| 585 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); |
| 586 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { |
| 587 service_record_state->sdp_bytes.push_back( |
| 588 sdp_result_data->lpBlob->pBlobData[i]); |
| 589 } |
| 590 service_record_states->push_back(service_record_state); |
| 591 } |
| 592 if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) { |
| 593 LogPollingError("Error calling WSALookupServiceEnd", WSAGetLastError()); |
| 594 return false; |
| 595 } |
| 596 |
| 597 return true; |
| 598 } |
| 599 |
| 600 bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices( |
| 601 const base::FilePath& device_path, |
| 602 ScopedVector<ServiceRecordState>* service_record_states) { |
| 603 if (!win::IsBluetoothLowEnergySupported()) |
| 604 return true; // Bluetooth LE not supported is not an error. |
| 605 |
| 606 std::string error; |
| 607 ScopedVector<win::BluetoothLowEnergyServiceInfo> services; |
| 608 bool success = win::EnumerateKnownBluetoothLowEnergyServices( |
| 609 device_path, &services, &error); |
| 610 if (!success) { |
| 611 LogPollingError(error.c_str(), 0); |
| 612 return false; |
| 613 } |
| 614 |
| 615 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 = |
| 616 services.begin(); |
| 617 iter2 != services.end(); |
| 618 ++iter2) { |
| 619 ServiceRecordState* service_state = new ServiceRecordState(); |
| 620 service_state->gatt_uuid = |
| 621 BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid); |
| 622 service_record_states->push_back(service_state); |
| 623 } |
| 624 return true; |
| 511 } | 625 } |
| 512 | 626 |
| 513 } // namespace device | 627 } // namespace device |
| OLD | NEW |