Home | History | Annotate | Download | only in bluetooth
      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