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 // Populates bluetooth adapter state using adapter_handle.
     34 void 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 
     58 void 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 
     76 namespace device {
     77 
     78 // static
     79 const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
     80 
     81 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
     82     scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
     83     : ui_task_runner_(ui_task_runner),
     84       discovering_(false) {
     85 }
     86 
     87 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
     88 }
     89 
     90 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
     91   DCHECK(observer);
     92   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
     93   observers_.AddObserver(observer);
     94 }
     95 
     96 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
     97   DCHECK(observer);
     98   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
     99   observers_.RemoveObserver(observer);
    100 }
    101 
    102 void 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 
    112 void 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 
    121 void 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 
    139 void BluetoothTaskManagerWin::Shutdown() {
    140   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    141   if (worker_pool_)
    142     worker_pool_->Shutdown();
    143 }
    144 
    145 void 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 
    159 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
    160   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    161   bluetooth_task_runner_->PostTask(
    162       FROM_HERE,
    163       base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
    164 }
    165 
    166 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
    167   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    168   bluetooth_task_runner_->PostTask(
    169       FROM_HERE,
    170       base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
    171 }
    172 
    173 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
    174   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    175   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
    176                     AdapterStateChanged(*state));
    177 }
    178 
    179 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
    180   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    181   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
    182                     DiscoveryStarted(success));
    183 }
    184 
    185 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
    186   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    187   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
    188                     DiscoveryStopped());
    189 }
    190 
    191 void 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 
    198 void 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 
    205 void 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 
    232 void 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 
    243 void 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 
    263 void 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 
    277 void 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 
    285 void 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 
    321 void 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 
    336 void 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 
    366 void 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