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