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 HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio( 215 &adapter_param, adapter_handle_.Receive()); 216 217 if (handle) { 218 GetKnownDevices(); 219 BluetoothFindRadioClose(handle); 220 } 221 PostAdapterStateToUi(); 222 } 223 224 // Re-poll. 225 bluetooth_task_runner_->PostDelayedTask( 226 FROM_HERE, 227 base::Bind(&BluetoothTaskManagerWin::PollAdapter, 228 this), 229 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); 230} 231 232void BluetoothTaskManagerWin::PostAdapterStateToUi() { 233 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 234 AdapterState* state = new AdapterState(); 235 GetAdapterState(adapter_handle_, state); 236 ui_task_runner_->PostTask( 237 FROM_HERE, 238 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, 239 this, 240 base::Owned(state))); 241} 242 243void BluetoothTaskManagerWin::SetPowered( 244 bool powered, 245 const base::Closure& callback, 246 const BluetoothAdapter::ErrorCallback& error_callback) { 247 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 248 bool success = false; 249 if (adapter_handle_) { 250 if (!powered) 251 BluetoothEnableDiscovery(adapter_handle_, false); 252 success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered); 253 } 254 255 if (success) { 256 PostAdapterStateToUi(); 257 ui_task_runner_->PostTask(FROM_HERE, callback); 258 } else { 259 ui_task_runner_->PostTask(FROM_HERE, error_callback); 260 } 261} 262 263void BluetoothTaskManagerWin::StartDiscovery() { 264 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 265 ui_task_runner_->PostTask( 266 FROM_HERE, 267 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted, 268 this, 269 !!adapter_handle_)); 270 if (!adapter_handle_) 271 return; 272 discovering_ = true; 273 274 DiscoverDevices(1); 275} 276 277void BluetoothTaskManagerWin::StopDiscovery() { 278 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 279 discovering_ = false; 280 ui_task_runner_->PostTask( 281 FROM_HERE, 282 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 283} 284 285void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { 286 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 287 if (!discovering_ || !adapter_handle_) { 288 ui_task_runner_->PostTask( 289 FROM_HERE, 290 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 291 return; 292 } 293 294 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); 295 SearchDevices(timeout, false, device_list); 296 if (device_list->empty()) { 297 delete device_list; 298 } else { 299 DiscoverServices(device_list); 300 ui_task_runner_->PostTask( 301 FROM_HERE, 302 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, 303 this, 304 base::Owned(device_list))); 305 } 306 307 if (timeout < kMaxDeviceDiscoveryTimeout) { 308 bluetooth_task_runner_->PostTask( 309 FROM_HERE, 310 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, 311 this, 312 timeout + 1)); 313 } else { 314 ui_task_runner_->PostTask( 315 FROM_HERE, 316 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 317 discovering_ = false; 318 } 319} 320 321void BluetoothTaskManagerWin::GetKnownDevices() { 322 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); 323 SearchDevices(1, true, device_list); 324 if (device_list->empty()) { 325 delete device_list; 326 return; 327 } 328 DiscoverServices(device_list); 329 ui_task_runner_->PostTask( 330 FROM_HERE, 331 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated, 332 this, 333 base::Owned(device_list))); 334} 335 336void BluetoothTaskManagerWin::SearchDevices( 337 int timeout, 338 bool search_cached_devices_only, 339 ScopedVector<DeviceState>* device_list) { 340 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { 341 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), 342 1, // return authenticated devices 343 1, // return remembered devicess 344 search_cached_devices_only ? 0 : 1, // return unknown devices 345 1, // return connected devices 346 search_cached_devices_only ? 0 : 1, // issue a new inquiry 347 timeout, // timeout for the inquiry in increments of 1.28 seconds 348 adapter_handle_ 349 }; 350 351 BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; 352 // Issues a device inquiry and waits for |timeout| * 1.28 seconds. 353 HBLUETOOTH_DEVICE_FIND handle = 354 BluetoothFindFirstDevice(&device_search_params, &device_info); 355 if (handle) { 356 do { 357 DeviceState* device_state = new DeviceState(); 358 GetDeviceState(device_info, device_state); 359 device_list->push_back(device_state); 360 } while (BluetoothFindNextDevice(handle, &device_info)); 361 362 BluetoothFindDeviceClose(handle); 363 } 364} 365 366void BluetoothTaskManagerWin::DiscoverServices( 367 ScopedVector<DeviceState>* device_list) { 368 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 369 net::EnsureWinsockInit(); 370 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); 371 iter != device_list->end(); 372 ++iter) { 373 const std::string device_address = (*iter)->address; 374 ScopedVector<ServiceRecordState>* service_record_states = 375 &(*iter)->service_record_states; 376 WSAQUERYSET sdp_query; 377 ZeroMemory(&sdp_query, sizeof(sdp_query)); 378 sdp_query.dwSize = sizeof(sdp_query); 379 GUID protocol = L2CAP_PROTOCOL_UUID; 380 sdp_query.lpServiceClassId = &protocol; 381 sdp_query.dwNameSpace = NS_BTH; 382 wchar_t device_address_context[kMaxNumDeviceAddressChar]; 383 std::size_t length = 384 base::SysUTF8ToWide("(" + device_address + ")").copy( 385 device_address_context, kMaxNumDeviceAddressChar); 386 device_address_context[length] = NULL; 387 sdp_query.lpszContext = device_address_context; 388 HANDLE sdp_handle; 389 if (ERROR_SUCCESS != 390 WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) { 391 return; 392 } 393 char sdp_buffer[kServiceDiscoveryResultBufferSize]; 394 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); 395 DWORD sdp_buffer_size = sizeof(sdp_buffer); 396 while (ERROR_SUCCESS == WSALookupServiceNext(sdp_handle, 397 LUP_RETURN_ALL, 398 &sdp_buffer_size, 399 sdp_result_data)) { 400 ServiceRecordState* service_record_state = new ServiceRecordState(); 401 service_record_state->name = 402 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); 403 service_record_state->address = device_address; 404 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { 405 service_record_state->sdp_bytes.push_back( 406 sdp_result_data->lpBlob->pBlobData[i]); 407 } 408 service_record_states->push_back(service_record_state); 409 } 410 WSALookupServiceEnd(sdp_handle); 411 } 412} 413 414} // namespace device 415