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::AdapterState::AdapterState() : powered(false) {
129 BluetoothTaskManagerWin::AdapterState::~AdapterState() {
132 BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() {
135 BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() {
138 BluetoothTaskManagerWin::DeviceState::DeviceState()
139 : bluetooth_class(0),
142 authenticated(false) {
145 BluetoothTaskManagerWin::DeviceState::~DeviceState() {
148 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
149 scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
150 : ui_task_runner_(ui_task_runner),
151 discovering_(false) {
154 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
157 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
159 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
160 observers_.AddObserver(observer);
163 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
165 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
166 observers_.RemoveObserver(observer);
169 void BluetoothTaskManagerWin::Initialize() {
170 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
171 worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool,
172 kBluetoothThreadName);
173 InitializeWithBluetoothTaskRunner(
174 worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
175 worker_pool_->GetSequenceToken(),
176 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
179 void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner(
180 scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) {
181 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
182 bluetooth_task_runner_ = bluetooth_task_runner;
183 bluetooth_task_runner_->PostTask(
185 base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
188 void BluetoothTaskManagerWin::StartPolling() {
189 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
191 if (device::bluetooth_init_win::HasBluetoothStack()) {
194 // IF the bluetooth stack is not available, we still send an empty state
195 // to BluetoothAdapter so that it is marked initialized, but the adapter
196 // will not be present.
197 AdapterState* state = new AdapterState();
198 ui_task_runner_->PostTask(
200 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
202 base::Owned(state)));
206 void BluetoothTaskManagerWin::Shutdown() {
207 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
209 worker_pool_->Shutdown();
212 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
214 const base::Closure& callback,
215 const BluetoothAdapter::ErrorCallback& error_callback) {
216 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
217 bluetooth_task_runner_->PostTask(
219 base::Bind(&BluetoothTaskManagerWin::SetPowered,
226 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
227 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
228 bluetooth_task_runner_->PostTask(
230 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
233 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
234 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
235 bluetooth_task_runner_->PostTask(
237 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
240 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
241 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
242 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
243 AdapterStateChanged(*state));
246 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
247 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
248 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
249 DiscoveryStarted(success));
252 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
253 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
254 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
258 void BluetoothTaskManagerWin::OnDevicesUpdated(
259 const ScopedVector<DeviceState>* devices) {
260 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
261 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
262 DevicesUpdated(*devices));
265 void BluetoothTaskManagerWin::OnDevicesDiscovered(
266 const ScopedVector<DeviceState>* devices) {
267 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
268 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
269 DevicesDiscovered(*devices));
272 void BluetoothTaskManagerWin::PollAdapter() {
273 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
275 // Skips updating the adapter info if the adapter is in discovery mode.
277 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
278 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
280 adapter_handle_.Close();
281 HANDLE temp_adapter_handle;
282 HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
283 &adapter_param, &temp_adapter_handle);
286 adapter_handle_.Set(temp_adapter_handle);
288 BluetoothFindRadioClose(handle);
290 PostAdapterStateToUi();
294 bluetooth_task_runner_->PostDelayedTask(
296 base::Bind(&BluetoothTaskManagerWin::PollAdapter,
298 base::TimeDelta::FromMilliseconds(kPollIntervalMs));
301 void BluetoothTaskManagerWin::PostAdapterStateToUi() {
302 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
303 AdapterState* state = new AdapterState();
304 GetAdapterState(adapter_handle_, state);
305 ui_task_runner_->PostTask(
307 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
309 base::Owned(state)));
312 void BluetoothTaskManagerWin::SetPowered(
314 const base::Closure& callback,
315 const BluetoothAdapter::ErrorCallback& error_callback) {
316 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
317 bool success = false;
318 if (adapter_handle_) {
320 BluetoothEnableDiscovery(adapter_handle_, false);
321 success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
325 PostAdapterStateToUi();
326 ui_task_runner_->PostTask(FROM_HERE, callback);
328 ui_task_runner_->PostTask(FROM_HERE, error_callback);
332 void BluetoothTaskManagerWin::StartDiscovery() {
333 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
334 ui_task_runner_->PostTask(
336 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
339 if (!adapter_handle_)
346 void BluetoothTaskManagerWin::StopDiscovery() {
347 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
348 discovering_ = false;
349 ui_task_runner_->PostTask(
351 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
354 void BluetoothTaskManagerWin::DiscoverDevices(int timeout) {
355 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
356 if (!discovering_ || !adapter_handle_) {
357 ui_task_runner_->PostTask(
359 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
363 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
364 SearchDevices(timeout, false, device_list);
365 if (device_list->empty()) {
368 DiscoverServices(device_list);
369 ui_task_runner_->PostTask(
371 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered,
373 base::Owned(device_list)));
376 if (timeout < kMaxDeviceDiscoveryTimeout) {
377 bluetooth_task_runner_->PostTask(
379 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices,
383 ui_task_runner_->PostTask(
385 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
386 discovering_ = false;
390 void BluetoothTaskManagerWin::GetKnownDevices() {
391 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
392 SearchDevices(1, true, device_list);
393 if (device_list->empty()) {
397 DiscoverServices(device_list);
398 ui_task_runner_->PostTask(
400 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated,
402 base::Owned(device_list)));
405 void BluetoothTaskManagerWin::SearchDevices(
407 bool search_cached_devices_only,
408 ScopedVector<DeviceState>* device_list) {
409 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = {
410 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS),
411 1, // return authenticated devices
412 1, // return remembered devicess
413 search_cached_devices_only ? 0 : 1, // return unknown devices
414 1, // return connected devices
415 search_cached_devices_only ? 0 : 1, // issue a new inquiry
416 timeout, // timeout for the inquiry in increments of 1.28 seconds
420 BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 };
421 // Issues a device inquiry and waits for |timeout| * 1.28 seconds.
422 HBLUETOOTH_DEVICE_FIND handle =
423 BluetoothFindFirstDevice(&device_search_params, &device_info);
426 DeviceState* device_state = new DeviceState();
427 GetDeviceState(device_info, device_state);
428 device_list->push_back(device_state);
429 } while (BluetoothFindNextDevice(handle, &device_info));
431 BluetoothFindDeviceClose(handle);
435 void BluetoothTaskManagerWin::DiscoverServices(
436 ScopedVector<DeviceState>* device_list) {
437 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
438 net::EnsureWinsockInit();
439 for (ScopedVector<DeviceState>::iterator iter = device_list->begin();
440 iter != device_list->end();
442 const std::string device_address = (*iter)->address;
443 ScopedVector<ServiceRecordState>* service_record_states =
444 &(*iter)->service_record_states;
446 DiscoverDeviceServices(
447 device_address, L2CAP_PROTOCOL_UUID, service_record_states);
451 } // namespace device