• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetAdapterState(HANDLE adapter_handle,device::BluetoothTaskManagerWin::AdapterState * state)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 
GetDeviceState(const BLUETOOTH_DEVICE_INFO & device_info,device::BluetoothTaskManagerWin::DeviceState * state)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 
BluetoothTaskManagerWin(scoped_refptr<base::SequencedTaskRunner> ui_task_runner)81 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
82     scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
83     : ui_task_runner_(ui_task_runner),
84       discovering_(false) {
85 }
86 
~BluetoothTaskManagerWin()87 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
88 }
89 
AddObserver(Observer * observer)90 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
91   DCHECK(observer);
92   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
93   observers_.AddObserver(observer);
94 }
95 
RemoveObserver(Observer * observer)96 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
97   DCHECK(observer);
98   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
99   observers_.RemoveObserver(observer);
100 }
101 
Initialize()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 
InitializeWithBluetoothTaskRunner(scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner)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 
StartPolling()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 
Shutdown()139 void BluetoothTaskManagerWin::Shutdown() {
140   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
141   if (worker_pool_)
142     worker_pool_->Shutdown();
143 }
144 
PostSetPoweredBluetoothTask(bool powered,const base::Closure & callback,const BluetoothAdapter::ErrorCallback & error_callback)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 
PostStartDiscoveryTask()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 
PostStopDiscoveryTask()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 
OnAdapterStateChanged(const AdapterState * state)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 
OnDiscoveryStarted(bool success)179 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
180   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
181   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
182                     DiscoveryStarted(success));
183 }
184 
OnDiscoveryStopped()185 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
186   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
187   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
188                     DiscoveryStopped());
189 }
190 
OnDevicesUpdated(const ScopedVector<DeviceState> * devices)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 
OnDevicesDiscovered(const ScopedVector<DeviceState> * devices)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 
PollAdapter()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 
PostAdapterStateToUi()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 
SetPowered(bool powered,const base::Closure & callback,const BluetoothAdapter::ErrorCallback & error_callback)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 
StartDiscovery()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 
StopDiscovery()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 
DiscoverDevices(int timeout)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 
GetKnownDevices()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 
SearchDevices(int timeout,bool search_cached_devices_only,ScopedVector<DeviceState> * device_list)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 
DiscoverServices(ScopedVector<DeviceState> * device_list)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