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     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 
    234 void 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 
    245 void 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 
    265 void 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 
    279 void 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 
    287 void 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 
    323 void 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 
    338 void 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 
    368 void 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