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.
5 #include "device/bluetooth/bluetooth_task_manager_win.h"
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"
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;
33 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState
;
35 // Populates bluetooth adapter state using adapter_handle.
36 void GetAdapterState(HANDLE adapter_handle
,
37 device::BluetoothTaskManagerWin::AdapterState
* state
) {
41 BLUETOOTH_RADIO_INFO adapter_info
= { sizeof(BLUETOOTH_RADIO_INFO
), 0 };
43 ERROR_SUCCESS
== BluetoothGetRadioInfo(adapter_handle
,
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
);
56 state
->address
= address
;
57 state
->powered
= powered
;
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
;
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
;
94 WSALookupServiceBegin(&sdp_query
, LUP_RETURN_ALL
, &sdp_handle
)) {
97 char sdp_buffer
[kServiceDiscoveryResultBufferSize
];
98 LPWSAQUERYSET sdp_result_data
= reinterpret_cast<LPWSAQUERYSET
>(sdp_buffer
);
100 DWORD sdp_buffer_size
= sizeof(sdp_buffer
);
102 WSALookupServiceNext(
103 sdp_handle
, LUP_RETURN_ALL
, &sdp_buffer_size
, sdp_result_data
)) {
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
]);
114 service_record_states
->push_back(service_record_state
);
116 WSALookupServiceEnd(sdp_handle
);
124 const int BluetoothTaskManagerWin::kPollIntervalMs
= 500;
126 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
127 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
)
128 : ui_task_runner_(ui_task_runner
),
129 discovering_(false) {
132 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
135 void BluetoothTaskManagerWin::AddObserver(Observer
* observer
) {
137 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
138 observers_
.AddObserver(observer
);
141 void BluetoothTaskManagerWin::RemoveObserver(Observer
* observer
) {
143 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
144 observers_
.RemoveObserver(observer
);
147 void BluetoothTaskManagerWin::Initialize() {
148 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
149 worker_pool_
= new base::SequencedWorkerPool(kNumThreadsInWorkerPool
,
150 kBluetoothThreadName
);
151 InitializeWithBluetoothTaskRunner(
152 worker_pool_
->GetSequencedTaskRunnerWithShutdownBehavior(
153 worker_pool_
->GetSequenceToken(),
154 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN
));
157 void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
158 scoped_refptr
<base::SequencedTaskRunner
> bluetooth_task_runner
) {
159 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
160 bluetooth_task_runner_
= bluetooth_task_runner
;
161 bluetooth_task_runner_
->PostTask(
163 base::Bind(&BluetoothTaskManagerWin::StartPolling
, this));
166 void BluetoothTaskManagerWin::StartPolling() {
167 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
169 if (device::bluetooth_init_win::HasBluetoothStack()) {
172 // IF the bluetooth stack is not available, we still send an empty state
173 // to BluetoothAdapter so that it is marked initialized, but the adapter
174 // will not be present.
175 AdapterState
* state
= new AdapterState();
176 ui_task_runner_
->PostTask(
178 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged
,
180 base::Owned(state
)));
184 void BluetoothTaskManagerWin::Shutdown() {
185 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
187 worker_pool_
->Shutdown();
190 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
192 const base::Closure
& callback
,
193 const BluetoothAdapter::ErrorCallback
& error_callback
) {
194 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
195 bluetooth_task_runner_
->PostTask(
197 base::Bind(&BluetoothTaskManagerWin::SetPowered
,
204 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
205 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
206 bluetooth_task_runner_
->PostTask(
208 base::Bind(&BluetoothTaskManagerWin::StartDiscovery
, this));
211 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
212 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
213 bluetooth_task_runner_
->PostTask(
215 base::Bind(&BluetoothTaskManagerWin::StopDiscovery
, this));
218 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState
* state
) {
219 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
220 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
221 AdapterStateChanged(*state
));
224 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success
) {
225 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
226 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
227 DiscoveryStarted(success
));
230 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
231 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
232 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
236 void BluetoothTaskManagerWin::OnDevicesUpdated(
237 const ScopedVector
<DeviceState
>* devices
) {
238 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
239 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
240 DevicesUpdated(*devices
));
243 void BluetoothTaskManagerWin::OnDevicesDiscovered(
244 const ScopedVector
<DeviceState
>* devices
) {
245 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
246 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
247 DevicesDiscovered(*devices
));
250 void BluetoothTaskManagerWin::PollAdapter() {
251 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
253 // Skips updating the adapter info if the adapter is in discovery mode.
255 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param
=
256 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS
) };
258 adapter_handle_
.Close();
259 HANDLE temp_adapter_handle
;
260 HBLUETOOTH_RADIO_FIND handle
= BluetoothFindFirstRadio(
261 &adapter_param
, &temp_adapter_handle
);
264 adapter_handle_
.Set(temp_adapter_handle
);
266 BluetoothFindRadioClose(handle
);
268 PostAdapterStateToUi();
272 bluetooth_task_runner_
->PostDelayedTask(
274 base::Bind(&BluetoothTaskManagerWin::PollAdapter
,
276 base::TimeDelta::FromMilliseconds(kPollIntervalMs
));
279 void BluetoothTaskManagerWin::PostAdapterStateToUi() {
280 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
281 AdapterState
* state
= new AdapterState();
282 GetAdapterState(adapter_handle_
, state
);
283 ui_task_runner_
->PostTask(
285 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged
,
287 base::Owned(state
)));
290 void BluetoothTaskManagerWin::SetPowered(
292 const base::Closure
& callback
,
293 const BluetoothAdapter::ErrorCallback
& error_callback
) {
294 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
295 bool success
= false;
296 if (adapter_handle_
) {
298 BluetoothEnableDiscovery(adapter_handle_
, false);
299 success
= !!BluetoothEnableIncomingConnections(adapter_handle_
, powered
);
303 PostAdapterStateToUi();
304 ui_task_runner_
->PostTask(FROM_HERE
, callback
);
306 ui_task_runner_
->PostTask(FROM_HERE
, error_callback
);
310 void BluetoothTaskManagerWin::StartDiscovery() {
311 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
312 ui_task_runner_
->PostTask(
314 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted
,
317 if (!adapter_handle_
)
324 void BluetoothTaskManagerWin::StopDiscovery() {
325 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
326 discovering_
= false;
327 ui_task_runner_
->PostTask(
329 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped
, this));
332 void BluetoothTaskManagerWin::DiscoverDevices(int timeout
) {
333 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
334 if (!discovering_
|| !adapter_handle_
) {
335 ui_task_runner_
->PostTask(
337 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped
, this));
341 ScopedVector
<DeviceState
>* device_list
= new ScopedVector
<DeviceState
>();
342 SearchDevices(timeout
, false, device_list
);
343 if (device_list
->empty()) {
346 DiscoverServices(device_list
);
347 ui_task_runner_
->PostTask(
349 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered
,
351 base::Owned(device_list
)));
354 if (timeout
< kMaxDeviceDiscoveryTimeout
) {
355 bluetooth_task_runner_
->PostTask(
357 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices
,
361 ui_task_runner_
->PostTask(
363 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped
, this));
364 discovering_
= false;
368 void BluetoothTaskManagerWin::GetKnownDevices() {
369 ScopedVector
<DeviceState
>* device_list
= new ScopedVector
<DeviceState
>();
370 SearchDevices(1, true, device_list
);
371 if (device_list
->empty()) {
375 DiscoverServices(device_list
);
376 ui_task_runner_
->PostTask(
378 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated
,
380 base::Owned(device_list
)));
383 void BluetoothTaskManagerWin::SearchDevices(
385 bool search_cached_devices_only
,
386 ScopedVector
<DeviceState
>* device_list
) {
387 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params
= {
388 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS
),
389 1, // return authenticated devices
390 1, // return remembered devicess
391 search_cached_devices_only
? 0 : 1, // return unknown devices
392 1, // return connected devices
393 search_cached_devices_only
? 0 : 1, // issue a new inquiry
394 timeout
, // timeout for the inquiry in increments of 1.28 seconds
398 BLUETOOTH_DEVICE_INFO device_info
= { sizeof(BLUETOOTH_DEVICE_INFO
), 0 };
399 // Issues a device inquiry and waits for |timeout| * 1.28 seconds.
400 HBLUETOOTH_DEVICE_FIND handle
=
401 BluetoothFindFirstDevice(&device_search_params
, &device_info
);
404 DeviceState
* device_state
= new DeviceState();
405 GetDeviceState(device_info
, device_state
);
406 device_list
->push_back(device_state
);
407 } while (BluetoothFindNextDevice(handle
, &device_info
));
409 BluetoothFindDeviceClose(handle
);
413 void BluetoothTaskManagerWin::DiscoverServices(
414 ScopedVector
<DeviceState
>* device_list
) {
415 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
416 net::EnsureWinsockInit();
417 for (ScopedVector
<DeviceState
>::iterator iter
= device_list
->begin();
418 iter
!= device_list
->end();
420 const std::string device_address
= (*iter
)->address
;
421 ScopedVector
<ServiceRecordState
>* service_record_states
=
422 &(*iter
)->service_record_states
;
424 DiscoverDeviceServices(
425 device_address
, L2CAP_PROTOCOL_UUID
, service_record_states
);
429 } // namespace device