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 // Populates bluetooth adapter state using adapter_handle.
34 void GetAdapterState(HANDLE adapter_handle
,
35 device::BluetoothTaskManagerWin::AdapterState
* state
) {
39 BLUETOOTH_RADIO_INFO adapter_info
= { sizeof(BLUETOOTH_RADIO_INFO
), 0 };
41 ERROR_SUCCESS
== BluetoothGetRadioInfo(adapter_handle
,
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
);
54 state
->address
= address
;
55 state
->powered
= powered
;
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
;
79 const int BluetoothTaskManagerWin::kPollIntervalMs
= 500;
81 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
82 scoped_refptr
<base::SequencedTaskRunner
> ui_task_runner
)
83 : ui_task_runner_(ui_task_runner
),
87 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
90 void BluetoothTaskManagerWin::AddObserver(Observer
* observer
) {
92 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
93 observers_
.AddObserver(observer
);
96 void BluetoothTaskManagerWin::RemoveObserver(Observer
* observer
) {
98 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
99 observers_
.RemoveObserver(observer
);
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
));
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(
118 base::Bind(&BluetoothTaskManagerWin::StartPolling
, this));
121 void BluetoothTaskManagerWin::StartPolling() {
122 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
124 if (device::bluetooth_init_win::HasBluetoothStack()) {
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(
133 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged
,
135 base::Owned(state
)));
139 void BluetoothTaskManagerWin::Shutdown() {
140 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
142 worker_pool_
->Shutdown();
145 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
147 const base::Closure
& callback
,
148 const BluetoothAdapter::ErrorCallback
& error_callback
) {
149 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
150 bluetooth_task_runner_
->PostTask(
152 base::Bind(&BluetoothTaskManagerWin::SetPowered
,
159 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
160 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
161 bluetooth_task_runner_
->PostTask(
163 base::Bind(&BluetoothTaskManagerWin::StartDiscovery
, this));
166 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
167 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
168 bluetooth_task_runner_
->PostTask(
170 base::Bind(&BluetoothTaskManagerWin::StopDiscovery
, this));
173 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState
* state
) {
174 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
175 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
176 AdapterStateChanged(*state
));
179 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success
) {
180 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
181 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
182 DiscoveryStarted(success
));
185 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
186 DCHECK(ui_task_runner_
->RunsTasksOnCurrentThread());
187 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer
, observers_
,
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
));
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
));
205 void BluetoothTaskManagerWin::PollAdapter() {
206 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
208 // Skips updating the adapter info if the adapter is in discovery mode.
210 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param
=
211 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS
) };
213 adapter_handle_
.Close();
214 HANDLE temp_adapter_handle
;
215 HBLUETOOTH_RADIO_FIND handle
= BluetoothFindFirstRadio(
216 &adapter_param
, &temp_adapter_handle
);
219 adapter_handle_
.Set(temp_adapter_handle
);
221 BluetoothFindRadioClose(handle
);
223 PostAdapterStateToUi();
227 bluetooth_task_runner_
->PostDelayedTask(
229 base::Bind(&BluetoothTaskManagerWin::PollAdapter
,
231 base::TimeDelta::FromMilliseconds(kPollIntervalMs
));
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(
240 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged
,
242 base::Owned(state
)));
245 void BluetoothTaskManagerWin::SetPowered(
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_
) {
253 BluetoothEnableDiscovery(adapter_handle_
, false);
254 success
= !!BluetoothEnableIncomingConnections(adapter_handle_
, powered
);
258 PostAdapterStateToUi();
259 ui_task_runner_
->PostTask(FROM_HERE
, callback
);
261 ui_task_runner_
->PostTask(FROM_HERE
, error_callback
);
265 void BluetoothTaskManagerWin::StartDiscovery() {
266 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
267 ui_task_runner_
->PostTask(
269 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted
,
272 if (!adapter_handle_
)
279 void BluetoothTaskManagerWin::StopDiscovery() {
280 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
281 discovering_
= false;
282 ui_task_runner_
->PostTask(
284 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped
, this));
287 void BluetoothTaskManagerWin::DiscoverDevices(int timeout
) {
288 DCHECK(bluetooth_task_runner_
->RunsTasksOnCurrentThread());
289 if (!discovering_
|| !adapter_handle_
) {
290 ui_task_runner_
->PostTask(
292 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped
, this));
296 ScopedVector
<DeviceState
>* device_list
= new ScopedVector
<DeviceState
>();
297 SearchDevices(timeout
, false, device_list
);
298 if (device_list
->empty()) {
301 DiscoverServices(device_list
);
302 ui_task_runner_
->PostTask(
304 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered
,
306 base::Owned(device_list
)));
309 if (timeout
< kMaxDeviceDiscoveryTimeout
) {
310 bluetooth_task_runner_
->PostTask(
312 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices
,
316 ui_task_runner_
->PostTask(
318 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped
, this));
319 discovering_
= false;
323 void BluetoothTaskManagerWin::GetKnownDevices() {
324 ScopedVector
<DeviceState
>* device_list
= new ScopedVector
<DeviceState
>();
325 SearchDevices(1, true, device_list
);
326 if (device_list
->empty()) {
330 DiscoverServices(device_list
);
331 ui_task_runner_
->PostTask(
333 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated
,
335 base::Owned(device_list
)));
338 void BluetoothTaskManagerWin::SearchDevices(
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
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
);
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
));
364 BluetoothFindDeviceClose(handle
);
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();
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
];
386 base::SysUTF8ToWide("(" + device_address
+ ")").copy(
387 device_address_context
, kMaxNumDeviceAddressChar
);
388 device_address_context
[length
] = NULL
;
389 sdp_query
.lpszContext
= device_address_context
;
392 WSALookupServiceBegin(&sdp_query
, LUP_RETURN_ALL
, &sdp_handle
)) {
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
,
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
]);
410 service_record_states
->push_back(service_record_state
);
412 WSALookupServiceEnd(sdp_handle
);
416 } // namespace device