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/message_loop/message_loop.h"
     15 #include "base/sequenced_task_runner.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "base/strings/sys_string_conversions.h"
     18 #include "base/threading/sequenced_worker_pool.h"
     19 #include "base/win/scoped_handle.h"
     20 #include "device/bluetooth/bluetooth_device.h"
     21 #include "device/bluetooth/bluetooth_init_win.h"
     22 #include "device/bluetooth/bluetooth_low_energy_win.h"
     23 #include "device/bluetooth/bluetooth_service_record_win.h"
     24 #include "net/base/winsock_init.h"
     25 
     26 namespace {
     27 
     28 const int kNumThreadsInWorkerPool = 3;
     29 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
     30 const int kMaxNumDeviceAddressChar = 127;
     31 const int kServiceDiscoveryResultBufferSize = 5000;
     32 
     33 // See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time
     34 // out for the inquiry, expressed in increments of 1.28 seconds. For example, an
     35 // inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum
     36 // value for this member is 48. When a value greater than 48 is used, the
     37 // calling function immediately fails and returns
     38 const int kMaxDeviceDiscoveryTimeoutMultiplier = 48;
     39 
     40 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
     41 
     42 // Note: The string returned here must have the same format as
     43 // BluetoothDevice::CanonicalizeAddress.
     44 std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) {
     45   std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
     46                                           btha.rgBytes[5],
     47                                           btha.rgBytes[4],
     48                                           btha.rgBytes[3],
     49                                           btha.rgBytes[2],
     50                                           btha.rgBytes[1],
     51                                           btha.rgBytes[0]);
     52   DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result));
     53   return result;
     54 }
     55 
     56 device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid(
     57     const BTH_LE_UUID& bth_le_uuid) {
     58   if (bth_le_uuid.IsShortUuid) {
     59     std::string uuid_hex =
     60         base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid);
     61     return device::BluetoothUUID(uuid_hex);
     62   } else {
     63     return device::BluetoothUUID(
     64         base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
     65                            bth_le_uuid.Value.LongUuid.Data1,
     66                            bth_le_uuid.Value.LongUuid.Data2,
     67                            bth_le_uuid.Value.LongUuid.Data3,
     68                            bth_le_uuid.Value.LongUuid.Data4[0],
     69                            bth_le_uuid.Value.LongUuid.Data4[1],
     70                            bth_le_uuid.Value.LongUuid.Data4[2],
     71                            bth_le_uuid.Value.LongUuid.Data4[3],
     72                            bth_le_uuid.Value.LongUuid.Data4[4],
     73                            bth_le_uuid.Value.LongUuid.Data4[5],
     74                            bth_le_uuid.Value.LongUuid.Data4[6],
     75                            bth_le_uuid.Value.LongUuid.Data4[7]));
     76   }
     77 }
     78 
     79 // Populates bluetooth adapter state using adapter_handle.
     80 void GetAdapterState(HANDLE adapter_handle,
     81                      device::BluetoothTaskManagerWin::AdapterState* state) {
     82   std::string name;
     83   std::string address;
     84   bool powered = false;
     85   BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
     86   if (adapter_handle &&
     87       ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
     88                                              &adapter_info)) {
     89     name = base::SysWideToUTF8(adapter_info.szName);
     90     address = BluetoothAddressToCanonicalString(adapter_info.address);
     91     powered = !!BluetoothIsConnectable(adapter_handle);
     92   }
     93   state->name = name;
     94   state->address = address;
     95   state->powered = powered;
     96 }
     97 
     98 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info,
     99                     device::BluetoothTaskManagerWin::DeviceState* state) {
    100   state->name = base::SysWideToUTF8(device_info.szName);
    101   state->address = BluetoothAddressToCanonicalString(device_info.Address);
    102   state->bluetooth_class = device_info.ulClassofDevice;
    103   state->visible = true;
    104   state->connected = !!device_info.fConnected;
    105   state->authenticated = !!device_info.fAuthenticated;
    106 }
    107 
    108 }  // namespace
    109 
    110 namespace device {
    111 
    112 // static
    113 const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
    114 
    115 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) {
    116 }
    117 
    118 BluetoothTaskManagerWin::AdapterState::~AdapterState() {
    119 }
    120 
    121 BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() {
    122 }
    123 
    124 BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() {
    125 }
    126 
    127 BluetoothTaskManagerWin::DeviceState::DeviceState()
    128     : bluetooth_class(0),
    129       visible(false),
    130       connected(false),
    131       authenticated(false) {
    132 }
    133 
    134 BluetoothTaskManagerWin::DeviceState::~DeviceState() {
    135 }
    136 
    137 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
    138     scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
    139     : ui_task_runner_(ui_task_runner),
    140       discovering_(false),
    141       current_logging_batch_count_(0) {
    142 }
    143 
    144 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
    145 }
    146 
    147 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
    148   DCHECK(observer);
    149   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    150   observers_.AddObserver(observer);
    151 }
    152 
    153 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
    154   DCHECK(observer);
    155   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    156   observers_.RemoveObserver(observer);
    157 }
    158 
    159 void BluetoothTaskManagerWin::Initialize() {
    160   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    161   worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool,
    162                                                kBluetoothThreadName);
    163   InitializeWithBluetoothTaskRunner(
    164       worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
    165           worker_pool_->GetSequenceToken(),
    166           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
    167 }
    168 
    169 void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
    170     scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
    171   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    172   bluetooth_task_runner_ = bluetooth_task_runner;
    173   bluetooth_task_runner_->PostTask(
    174       FROM_HERE,
    175       base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
    176 }
    177 
    178 void BluetoothTaskManagerWin::StartPolling() {
    179   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    180 
    181   if (device::bluetooth_init_win::HasBluetoothStack()) {
    182     PollAdapter();
    183   } else {
    184     // IF the bluetooth stack is not available, we still send an empty state
    185     // to BluetoothAdapter so that it is marked initialized, but the adapter
    186     // will not be present.
    187     AdapterState* state = new AdapterState();
    188     ui_task_runner_->PostTask(
    189       FROM_HERE,
    190       base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
    191                  this,
    192                  base::Owned(state)));
    193   }
    194 }
    195 
    196 void BluetoothTaskManagerWin::Shutdown() {
    197   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    198   if (worker_pool_)
    199     worker_pool_->Shutdown();
    200 }
    201 
    202 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
    203     bool powered,
    204     const base::Closure& callback,
    205     const BluetoothAdapter::ErrorCallback& error_callback) {
    206   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    207   bluetooth_task_runner_->PostTask(
    208       FROM_HERE,
    209       base::Bind(&BluetoothTaskManagerWin::SetPowered,
    210                  this,
    211                  powered,
    212                  callback,
    213                  error_callback));
    214 }
    215 
    216 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
    217   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    218   bluetooth_task_runner_->PostTask(
    219       FROM_HERE,
    220       base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
    221 }
    222 
    223 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
    224   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    225   bluetooth_task_runner_->PostTask(
    226       FROM_HERE,
    227       base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
    228 }
    229 
    230 void BluetoothTaskManagerWin::LogPollingError(const char* message,
    231                                               int win32_error) {
    232   const int kLogPeriodInMilliseconds = 60 * 1000;
    233   const int kMaxMessagesPerLogPeriod = 10;
    234 
    235   // Check if we need to discard this message
    236   if (!current_logging_batch_ticks_.is_null()) {
    237     if (base::TimeTicks::Now() - current_logging_batch_ticks_ <=
    238         base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) {
    239       if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod)
    240         return;
    241     } else {
    242       // The batch expired, reset it to "null".
    243       current_logging_batch_ticks_ = base::TimeTicks();
    244     }
    245   }
    246 
    247   // Keep track of this batch of messages
    248   if (current_logging_batch_ticks_.is_null()) {
    249     current_logging_batch_ticks_ = base::TimeTicks::Now();
    250     current_logging_batch_count_ = 0;
    251   }
    252   ++current_logging_batch_count_;
    253 
    254   // Log the message
    255   if (win32_error == 0)
    256     LOG(WARNING) << message;
    257   else
    258     LOG(WARNING) << message << ": "
    259                  << logging::SystemErrorCodeToString(win32_error);
    260 }
    261 
    262 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
    263   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    264   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
    265                     AdapterStateChanged(*state));
    266 }
    267 
    268 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
    269   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    270   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
    271                     DiscoveryStarted(success));
    272 }
    273 
    274 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
    275   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    276   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
    277                     DiscoveryStopped());
    278 }
    279 
    280 void BluetoothTaskManagerWin::OnDevicesPolled(
    281     const ScopedVector<DeviceState>* devices) {
    282   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
    283   FOR_EACH_OBSERVER(
    284       BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices));
    285 }
    286 
    287 void BluetoothTaskManagerWin::PollAdapter() {
    288   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    289 
    290   // Skips updating the adapter info if the adapter is in discovery mode.
    291   if (!discovering_) {
    292     const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
    293         { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
    294     if (adapter_handle_)
    295       adapter_handle_.Close();
    296     HANDLE temp_adapter_handle;
    297     HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
    298         &adapter_param, &temp_adapter_handle);
    299 
    300     if (handle) {
    301       adapter_handle_.Set(temp_adapter_handle);
    302       GetKnownDevices();
    303       BluetoothFindRadioClose(handle);
    304     }
    305 
    306     PostAdapterStateToUi();
    307   }
    308 
    309   // Re-poll.
    310   bluetooth_task_runner_->PostDelayedTask(
    311       FROM_HERE,
    312       base::Bind(&BluetoothTaskManagerWin::PollAdapter,
    313                  this),
    314       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
    315 }
    316 
    317 void BluetoothTaskManagerWin::PostAdapterStateToUi() {
    318   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    319   AdapterState* state = new AdapterState();
    320   GetAdapterState(adapter_handle_, state);
    321   ui_task_runner_->PostTask(
    322       FROM_HERE,
    323       base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
    324                  this,
    325                  base::Owned(state)));
    326 }
    327 
    328 void BluetoothTaskManagerWin::SetPowered(
    329     bool powered,
    330     const base::Closure& callback,
    331     const BluetoothAdapter::ErrorCallback& error_callback) {
    332   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    333   bool success = false;
    334   if (adapter_handle_) {
    335     if (!powered)
    336       BluetoothEnableDiscovery(adapter_handle_, false);
    337     success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
    338   }
    339 
    340   if (success) {
    341     PostAdapterStateToUi();
    342     ui_task_runner_->PostTask(FROM_HERE, callback);
    343   } else {
    344     ui_task_runner_->PostTask(FROM_HERE, error_callback);
    345   }
    346 }
    347 
    348 void BluetoothTaskManagerWin::StartDiscovery() {
    349   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    350   ui_task_runner_->PostTask(
    351       FROM_HERE,
    352       base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
    353                  this,
    354                  !!adapter_handle_));
    355   if (!adapter_handle_)
    356     return;
    357   discovering_ = true;
    358 
    359   DiscoverDevices(1);
    360 }
    361 
    362 void BluetoothTaskManagerWin::StopDiscovery() {
    363   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    364   discovering_ = false;
    365   ui_task_runner_->PostTask(
    366       FROM_HERE,
    367       base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
    368 }
    369 
    370 void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
    371   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    372   if (!discovering_ || !adapter_handle_) {
    373     ui_task_runner_->PostTask(
    374         FROM_HERE,
    375         base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
    376     return;
    377   }
    378 
    379   scoped_ptr<ScopedVector<DeviceState> > device_list(
    380       new ScopedVector<DeviceState>());
    381   if (SearchDevices(timeout_multiplier, false, device_list.get())) {
    382     ui_task_runner_->PostTask(
    383         FROM_HERE,
    384         base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
    385                    this,
    386                    base::Owned(device_list.release())));
    387   }
    388 
    389   if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
    390     ++timeout_multiplier;
    391   bluetooth_task_runner_->PostTask(
    392       FROM_HERE,
    393       base::Bind(
    394           &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier));
    395 }
    396 
    397 void BluetoothTaskManagerWin::GetKnownDevices() {
    398   scoped_ptr<ScopedVector<DeviceState> > device_list(
    399       new ScopedVector<DeviceState>());
    400   if (SearchDevices(1, true, device_list.get())) {
    401     ui_task_runner_->PostTask(
    402         FROM_HERE,
    403         base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled,
    404                    this,
    405                    base::Owned(device_list.release())));
    406   }
    407 }
    408 
    409 bool BluetoothTaskManagerWin::SearchDevices(
    410     int timeout_multiplier,
    411     bool search_cached_devices_only,
    412     ScopedVector<DeviceState>* device_list) {
    413   return SearchClassicDevices(
    414              timeout_multiplier, search_cached_devices_only, device_list) &&
    415          SearchLowEnergyDevices(device_list) &&
    416          DiscoverServices(device_list, search_cached_devices_only);
    417 }
    418 
    419 bool BluetoothTaskManagerWin::SearchClassicDevices(
    420     int timeout_multiplier,
    421     bool search_cached_devices_only,
    422     ScopedVector<DeviceState>* device_list) {
    423   // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds.
    424   BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params;
    425   ZeroMemory(&device_search_params, sizeof(device_search_params));
    426   device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
    427   device_search_params.fReturnAuthenticated = 1;
    428   device_search_params.fReturnRemembered = 1;
    429   device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1);
    430   device_search_params.fReturnConnected = 1;
    431   device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1);
    432   device_search_params.cTimeoutMultiplier = timeout_multiplier;
    433 
    434   BLUETOOTH_DEVICE_INFO device_info;
    435   ZeroMemory(&device_info, sizeof(device_info));
    436   device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
    437   HBLUETOOTH_DEVICE_FIND handle =
    438       BluetoothFindFirstDevice(&device_search_params, &device_info);
    439   if (!handle) {
    440     int last_error = GetLastError();
    441     if (last_error == ERROR_NO_MORE_ITEMS) {
    442       return true;  // No devices is not an error.
    443     }
    444     LogPollingError("Error calling BluetoothFindFirstDevice", last_error);
    445     return false;
    446   }
    447 
    448   while (true) {
    449     DeviceState* device_state = new DeviceState();
    450     GetDeviceState(device_info, device_state);
    451     device_list->push_back(device_state);
    452 
    453     // Reset device info before next call (as a safety precaution).
    454     ZeroMemory(&device_info, sizeof(device_info));
    455     device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
    456     if (!BluetoothFindNextDevice(handle, &device_info)) {
    457       int last_error = GetLastError();
    458       if (last_error == ERROR_NO_MORE_ITEMS) {
    459         break;  // No more items is expected error when done enumerating.
    460       }
    461       LogPollingError("Error calling BluetoothFindNextDevice", last_error);
    462       BluetoothFindDeviceClose(handle);
    463       return false;
    464     }
    465   }
    466 
    467   if (!BluetoothFindDeviceClose(handle)) {
    468     LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError());
    469     return false;
    470   }
    471   return true;
    472 }
    473 
    474 bool BluetoothTaskManagerWin::SearchLowEnergyDevices(
    475     ScopedVector<DeviceState>* device_list) {
    476   if (!win::IsBluetoothLowEnergySupported())
    477     return true;  // Bluetooth LE not supported is not an error.
    478 
    479   ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices;
    480   std::string error;
    481   bool success =
    482       win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error);
    483   if (!success) {
    484     LogPollingError(error.c_str(), 0);
    485     return false;
    486   }
    487 
    488   for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter =
    489            btle_devices.begin();
    490        iter != btle_devices.end();
    491        ++iter) {
    492     win::BluetoothLowEnergyDeviceInfo* device_info = (*iter);
    493     DeviceState* device_state = new DeviceState();
    494     device_state->name = device_info->friendly_name;
    495     device_state->address =
    496         BluetoothAddressToCanonicalString(device_info->address);
    497     device_state->visible = device_info->visible;
    498     device_state->authenticated = device_info->authenticated;
    499     device_state->connected = device_info->connected;
    500     device_state->path = device_info->path;
    501     device_list->push_back(device_state);
    502   }
    503   return true;
    504 }
    505 
    506 bool BluetoothTaskManagerWin::DiscoverServices(
    507     ScopedVector<DeviceState>* device_list,
    508     bool search_cached_services_only) {
    509   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
    510   net::EnsureWinsockInit();
    511   for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
    512       iter != device_list->end();
    513       ++iter) {
    514     DeviceState* device = (*iter);
    515     ScopedVector<ServiceRecordState>* service_record_states =
    516         &(*iter)->service_record_states;
    517 
    518     if ((*iter)->is_bluetooth_classic()) {
    519       if (!DiscoverClassicDeviceServices(device->address,
    520                                          L2CAP_PROTOCOL_UUID,
    521                                          search_cached_services_only,
    522                                          service_record_states)) {
    523         return false;
    524       }
    525     } else {
    526       if (!DiscoverLowEnergyDeviceServices(device->path,
    527                                            service_record_states)) {
    528         return false;
    529       }
    530     }
    531   }
    532   return true;
    533 }
    534 
    535 bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices(
    536     const std::string& device_address,
    537     const GUID& protocol_uuid,
    538     bool search_cached_services_only,
    539     ScopedVector<ServiceRecordState>* service_record_states) {
    540   int error_code =
    541       DiscoverClassicDeviceServicesWorker(device_address,
    542                                           protocol_uuid,
    543                                           search_cached_services_only,
    544                                           service_record_states);
    545   // If the device is "offline", no services are returned when specifying
    546   // "LUP_FLUSHCACHE". Try again without flushing the cache so that the list
    547   // of previously known services is returned.
    548   if (!search_cached_services_only &&
    549       (error_code == WSASERVICE_NOT_FOUND || error_code == WSANO_DATA)) {
    550     error_code = DiscoverClassicDeviceServicesWorker(
    551         device_address, protocol_uuid, true, service_record_states);
    552   }
    553 
    554   return (error_code == ERROR_SUCCESS);
    555 }
    556 
    557 int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker(
    558     const std::string& device_address,
    559     const GUID& protocol_uuid,
    560     bool search_cached_services_only,
    561     ScopedVector<ServiceRecordState>* service_record_states) {
    562   // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt.
    563   WSAQUERYSET sdp_query;
    564   ZeroMemory(&sdp_query, sizeof(sdp_query));
    565   sdp_query.dwSize = sizeof(sdp_query);
    566   GUID protocol = protocol_uuid;
    567   sdp_query.lpServiceClassId = &protocol;
    568   sdp_query.dwNameSpace = NS_BTH;
    569   wchar_t device_address_context[kMaxNumDeviceAddressChar];
    570   std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy(
    571       device_address_context, kMaxNumDeviceAddressChar);
    572   device_address_context[length] = NULL;
    573   sdp_query.lpszContext = device_address_context;
    574   DWORD control_flags = LUP_RETURN_ALL;
    575   // See http://goo.gl/t1Hulo: "Applications should generally specify
    576   // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached
    577   // information and establish an over-the-air SDP connection to the specified
    578   // device to perform the SDP search. This non-cached operation may take
    579   // several seconds (whereas a cached search returns quickly)."
    580   // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list
    581   // of services for devices which have not been discovered before.
    582   if (!search_cached_services_only)
    583     control_flags |= LUP_FLUSHCACHE;
    584   HANDLE sdp_handle;
    585   if (ERROR_SUCCESS !=
    586       WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) {
    587     int last_error = WSAGetLastError();
    588     // If the device is "offline", no services are returned when specifying
    589     // "LUP_FLUSHCACHE". Don't log error in that case.
    590     if (!search_cached_services_only &&
    591         (last_error == WSASERVICE_NOT_FOUND || last_error == WSANO_DATA)) {
    592       return last_error;
    593     }
    594     LogPollingError("Error calling WSALookupServiceBegin", last_error);
    595     return last_error;
    596   }
    597   char sdp_buffer[kServiceDiscoveryResultBufferSize];
    598   LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
    599   while (true) {
    600     DWORD sdp_buffer_size = sizeof(sdp_buffer);
    601     if (ERROR_SUCCESS !=
    602         WSALookupServiceNext(
    603             sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) {
    604       int last_error = WSAGetLastError();
    605       if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) {
    606         break;
    607       }
    608       LogPollingError("Error calling WSALookupServiceNext", last_error);
    609       WSALookupServiceEnd(sdp_handle);
    610       return last_error;
    611     }
    612     ServiceRecordState* service_record_state = new ServiceRecordState();
    613     service_record_state->name =
    614         base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName);
    615     for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) {
    616       service_record_state->sdp_bytes.push_back(
    617           sdp_result_data->lpBlob->pBlobData[i]);
    618     }
    619     service_record_states->push_back(service_record_state);
    620   }
    621   if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) {
    622     int last_error = WSAGetLastError();
    623     LogPollingError("Error calling WSALookupServiceEnd", last_error);
    624     return last_error;
    625   }
    626 
    627   return ERROR_SUCCESS;
    628 }
    629 
    630 bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices(
    631     const base::FilePath& device_path,
    632     ScopedVector<ServiceRecordState>* service_record_states) {
    633   if (!win::IsBluetoothLowEnergySupported())
    634     return true;  // Bluetooth LE not supported is not an error.
    635 
    636   std::string error;
    637   ScopedVector<win::BluetoothLowEnergyServiceInfo> services;
    638   bool success = win::EnumerateKnownBluetoothLowEnergyServices(
    639       device_path, &services, &error);
    640   if (!success) {
    641     LogPollingError(error.c_str(), 0);
    642     return false;
    643   }
    644 
    645   for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 =
    646            services.begin();
    647        iter2 != services.end();
    648        ++iter2) {
    649     ServiceRecordState* service_state = new ServiceRecordState();
    650     service_state->gatt_uuid =
    651         BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid);
    652     service_record_states->push_back(service_state);
    653   }
    654   return true;
    655 }
    656 
    657 }  // namespace device
    658