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 3 // found in the LICENSE file. 4 5 #include "device/bluetooth/bluetooth_task_manager_win.h" 6 7 #include <winsock2.h> 8 9 #include <string> 10 11 #include "base/basictypes.h" 12 #include "base/bind.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/memory/scoped_vector.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/sequenced_task_runner.h" 17 #include "base/strings/stringprintf.h" 18 #include "base/strings/sys_string_conversions.h" 19 #include "base/threading/sequenced_worker_pool.h" 20 #include "base/win/scoped_handle.h" 21 #include "device/bluetooth/bluetooth_init_win.h" 22 #include "device/bluetooth/bluetooth_service_record_win.h" 23 #include "net/base/winsock_init.h" 24 25 namespace { 26 27 const int kNumThreadsInWorkerPool = 3; 28 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; 29 const int kMaxNumDeviceAddressChar = 127; 30 const int kServiceDiscoveryResultBufferSize = 5000; 31 const int kMaxDeviceDiscoveryTimeout = 48; 32 33 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; 34 35 // Populates bluetooth adapter state using adapter_handle. 36 void GetAdapterState(HANDLE adapter_handle, 37 device::BluetoothTaskManagerWin::AdapterState* state) { 38 std::string name; 39 std::string address; 40 bool powered = false; 41 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 }; 42 if (adapter_handle && 43 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle, 44 &adapter_info)) { 45 name = base::SysWideToUTF8(adapter_info.szName); 46 address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", 47 adapter_info.address.rgBytes[5], 48 adapter_info.address.rgBytes[4], 49 adapter_info.address.rgBytes[3], 50 adapter_info.address.rgBytes[2], 51 adapter_info.address.rgBytes[1], 52 adapter_info.address.rgBytes[0]); 53 powered = !!BluetoothIsConnectable(adapter_handle); 54 } 55 state->name = name; 56 state->address = address; 57 state->powered = powered; 58 } 59 60 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, 61 device::BluetoothTaskManagerWin::DeviceState* state) { 62 state->name = base::SysWideToUTF8(device_info.szName); 63 state->address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", 64 device_info.Address.rgBytes[5], 65 device_info.Address.rgBytes[4], 66 device_info.Address.rgBytes[3], 67 device_info.Address.rgBytes[2], 68 device_info.Address.rgBytes[1], 69 device_info.Address.rgBytes[0]); 70 state->bluetooth_class = device_info.ulClassofDevice; 71 state->visible = true; 72 state->connected = !!device_info.fConnected; 73 state->authenticated = !!device_info.fAuthenticated; 74 } 75 76 void DiscoverDeviceServices( 77 const std::string& device_address, 78 const GUID& protocol_uuid, 79 ScopedVector<ServiceRecordState>* service_record_states) { 80 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. 81 WSAQUERYSET sdp_query; 82 ZeroMemory(&sdp_query, sizeof(sdp_query)); 83 sdp_query.dwSize = sizeof(sdp_query); 84 GUID protocol = protocol_uuid; 85 sdp_query.lpServiceClassId = &protocol; 86 sdp_query.dwNameSpace = NS_BTH; 87 wchar_t device_address_context[kMaxNumDeviceAddressChar]; 88 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( 89 device_address_context, kMaxNumDeviceAddressChar); 90 device_address_context[length] = NULL; 91 sdp_query.lpszContext = device_address_context; 92 HANDLE sdp_handle; 93 if (ERROR_SUCCESS != 94 WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) { 95 return; 96 } 97 char sdp_buffer[kServiceDiscoveryResultBufferSize]; 98 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); 99 while (true) { 100 DWORD sdp_buffer_size = sizeof(sdp_buffer); 101 if (ERROR_SUCCESS != 102 WSALookupServiceNext( 103 sdp_handle, LUP_RETURN_ALL, &sdp_buffer_size, sdp_result_data)) { 104 break; 105 } 106 ServiceRecordState* service_record_state = new ServiceRecordState(); 107 service_record_state->name = 108 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); 109 service_record_state->address = device_address; 110 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { 111 service_record_state->sdp_bytes.push_back( 112 sdp_result_data->lpBlob->pBlobData[i]); 113 } 114 service_record_states->push_back(service_record_state); 115 } 116 WSALookupServiceEnd(sdp_handle); 117 } 118 119 } // namespace 120 121 namespace device { 122 123 // static 124 const int BluetoothTaskManagerWin::kPollIntervalMs = 500; 125 126 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) { 127 } 128 129 BluetoothTaskManagerWin::AdapterState::~AdapterState() { 130 } 131 132 BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() { 133 } 134 135 BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() { 136 } 137 138 BluetoothTaskManagerWin::DeviceState::DeviceState() 139 : bluetooth_class(0), 140 visible(false), 141 connected(false), 142 authenticated(false) { 143 } 144 145 BluetoothTaskManagerWin::DeviceState::~DeviceState() { 146 } 147 148 BluetoothTaskManagerWin::BluetoothTaskManagerWin( 149 scoped_refptr<base::SequencedTaskRunner> ui_task_runner) 150 : ui_task_runner_(ui_task_runner), 151 discovering_(false) { 152 } 153 154 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { 155 } 156 157 void BluetoothTaskManagerWin::AddObserver(Observer* observer) { 158 DCHECK(observer); 159 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 160 observers_.AddObserver(observer); 161 } 162 163 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) { 164 DCHECK(observer); 165 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 166 observers_.RemoveObserver(observer); 167 } 168 169 void BluetoothTaskManagerWin::Initialize() { 170 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 171 worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool, 172 kBluetoothThreadName); 173 InitializeWithBluetoothTaskRunner( 174 worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( 175 worker_pool_->GetSequenceToken(), 176 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)); 177 } 178 179 void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner( 180 scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) { 181 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 182 bluetooth_task_runner_ = bluetooth_task_runner; 183 bluetooth_task_runner_->PostTask( 184 FROM_HERE, 185 base::Bind(&BluetoothTaskManagerWin::StartPolling, this)); 186 } 187 188 void BluetoothTaskManagerWin::StartPolling() { 189 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 190 191 if (device::bluetooth_init_win::HasBluetoothStack()) { 192 PollAdapter(); 193 } else { 194 // IF the bluetooth stack is not available, we still send an empty state 195 // to BluetoothAdapter so that it is marked initialized, but the adapter 196 // will not be present. 197 AdapterState* state = new AdapterState(); 198 ui_task_runner_->PostTask( 199 FROM_HERE, 200 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, 201 this, 202 base::Owned(state))); 203 } 204 } 205 206 void BluetoothTaskManagerWin::Shutdown() { 207 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 208 if (worker_pool_) 209 worker_pool_->Shutdown(); 210 } 211 212 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask( 213 bool powered, 214 const base::Closure& callback, 215 const BluetoothAdapter::ErrorCallback& error_callback) { 216 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 217 bluetooth_task_runner_->PostTask( 218 FROM_HERE, 219 base::Bind(&BluetoothTaskManagerWin::SetPowered, 220 this, 221 powered, 222 callback, 223 error_callback)); 224 } 225 226 void BluetoothTaskManagerWin::PostStartDiscoveryTask() { 227 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 228 bluetooth_task_runner_->PostTask( 229 FROM_HERE, 230 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); 231 } 232 233 void BluetoothTaskManagerWin::PostStopDiscoveryTask() { 234 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 235 bluetooth_task_runner_->PostTask( 236 FROM_HERE, 237 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); 238 } 239 240 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { 241 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 242 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 243 AdapterStateChanged(*state)); 244 } 245 246 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { 247 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 248 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 249 DiscoveryStarted(success)); 250 } 251 252 void BluetoothTaskManagerWin::OnDiscoveryStopped() { 253 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 254 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 255 DiscoveryStopped()); 256 } 257 258 void BluetoothTaskManagerWin::OnDevicesUpdated( 259 const ScopedVector<DeviceState>* devices) { 260 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 261 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 262 DevicesUpdated(*devices)); 263 } 264 265 void BluetoothTaskManagerWin::OnDevicesDiscovered( 266 const ScopedVector<DeviceState>* devices) { 267 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 268 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 269 DevicesDiscovered(*devices)); 270 } 271 272 void BluetoothTaskManagerWin::PollAdapter() { 273 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 274 275 // Skips updating the adapter info if the adapter is in discovery mode. 276 if (!discovering_) { 277 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = 278 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; 279 if (adapter_handle_) 280 adapter_handle_.Close(); 281 HANDLE temp_adapter_handle; 282 HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio( 283 &adapter_param, &temp_adapter_handle); 284 285 if (handle) { 286 adapter_handle_.Set(temp_adapter_handle); 287 GetKnownDevices(); 288 BluetoothFindRadioClose(handle); 289 } 290 PostAdapterStateToUi(); 291 } 292 293 // Re-poll. 294 bluetooth_task_runner_->PostDelayedTask( 295 FROM_HERE, 296 base::Bind(&BluetoothTaskManagerWin::PollAdapter, 297 this), 298 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); 299 } 300 301 void BluetoothTaskManagerWin::PostAdapterStateToUi() { 302 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 303 AdapterState* state = new AdapterState(); 304 GetAdapterState(adapter_handle_, state); 305 ui_task_runner_->PostTask( 306 FROM_HERE, 307 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, 308 this, 309 base::Owned(state))); 310 } 311 312 void BluetoothTaskManagerWin::SetPowered( 313 bool powered, 314 const base::Closure& callback, 315 const BluetoothAdapter::ErrorCallback& error_callback) { 316 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 317 bool success = false; 318 if (adapter_handle_) { 319 if (!powered) 320 BluetoothEnableDiscovery(adapter_handle_, false); 321 success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered); 322 } 323 324 if (success) { 325 PostAdapterStateToUi(); 326 ui_task_runner_->PostTask(FROM_HERE, callback); 327 } else { 328 ui_task_runner_->PostTask(FROM_HERE, error_callback); 329 } 330 } 331 332 void BluetoothTaskManagerWin::StartDiscovery() { 333 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 334 ui_task_runner_->PostTask( 335 FROM_HERE, 336 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted, 337 this, 338 !!adapter_handle_)); 339 if (!adapter_handle_) 340 return; 341 discovering_ = true; 342 343 DiscoverDevices(1); 344 } 345 346 void BluetoothTaskManagerWin::StopDiscovery() { 347 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 348 discovering_ = false; 349 ui_task_runner_->PostTask( 350 FROM_HERE, 351 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 352 } 353 354 void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { 355 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 356 if (!discovering_ || !adapter_handle_) { 357 ui_task_runner_->PostTask( 358 FROM_HERE, 359 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 360 return; 361 } 362 363 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); 364 SearchDevices(timeout, false, device_list); 365 if (device_list->empty()) { 366 delete device_list; 367 } else { 368 DiscoverServices(device_list); 369 ui_task_runner_->PostTask( 370 FROM_HERE, 371 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, 372 this, 373 base::Owned(device_list))); 374 } 375 376 if (timeout < kMaxDeviceDiscoveryTimeout) { 377 bluetooth_task_runner_->PostTask( 378 FROM_HERE, 379 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, 380 this, 381 timeout + 1)); 382 } else { 383 ui_task_runner_->PostTask( 384 FROM_HERE, 385 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 386 discovering_ = false; 387 } 388 } 389 390 void BluetoothTaskManagerWin::GetKnownDevices() { 391 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); 392 SearchDevices(1, true, device_list); 393 if (device_list->empty()) { 394 delete device_list; 395 return; 396 } 397 DiscoverServices(device_list); 398 ui_task_runner_->PostTask( 399 FROM_HERE, 400 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated, 401 this, 402 base::Owned(device_list))); 403 } 404 405 void BluetoothTaskManagerWin::SearchDevices( 406 int timeout, 407 bool search_cached_devices_only, 408 ScopedVector<DeviceState>* device_list) { 409 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { 410 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), 411 1, // return authenticated devices 412 1, // return remembered devicess 413 search_cached_devices_only ? 0 : 1, // return unknown devices 414 1, // return connected devices 415 search_cached_devices_only ? 0 : 1, // issue a new inquiry 416 timeout, // timeout for the inquiry in increments of 1.28 seconds 417 adapter_handle_ 418 }; 419 420 BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; 421 // Issues a device inquiry and waits for |timeout| * 1.28 seconds. 422 HBLUETOOTH_DEVICE_FIND handle = 423 BluetoothFindFirstDevice(&device_search_params, &device_info); 424 if (handle) { 425 do { 426 DeviceState* device_state = new DeviceState(); 427 GetDeviceState(device_info, device_state); 428 device_list->push_back(device_state); 429 } while (BluetoothFindNextDevice(handle, &device_info)); 430 431 BluetoothFindDeviceClose(handle); 432 } 433 } 434 435 void BluetoothTaskManagerWin::DiscoverServices( 436 ScopedVector<DeviceState>* device_list) { 437 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 438 net::EnsureWinsockInit(); 439 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); 440 iter != device_list->end(); 441 ++iter) { 442 const std::string device_address = (*iter)->address; 443 ScopedVector<ServiceRecordState>* service_record_states = 444 &(*iter)->service_record_states; 445 446 DiscoverDeviceServices( 447 device_address, L2CAP_PROTOCOL_UUID, service_record_states); 448 } 449 } 450 451 } // namespace device 452