Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / device / bluetooth / bluetooth_task_manager_win.cc
blob95b580a0402f7e1799e8895f59e7a64bcea317d1
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"
7 #include <winsock2.h>
9 #include <string>
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"
25 namespace {
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) {
38 std::string name;
39 std::string address;
40 bool powered = false;
41 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
42 if (adapter_handle &&
43 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
44 &adapter_info)) {
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);
55 state->name = name;
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;
92 HANDLE sdp_handle;
93 if (ERROR_SUCCESS !=
94 WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) {
95 return;
97 char sdp_buffer[kServiceDiscoveryResultBufferSize];
98 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer);
99 while (true) {
100 DWORD sdp_buffer_size = sizeof(sdp_buffer);
101 if (ERROR_SUCCESS !=
102 WSALookupServiceNext(
103 sdp_handle, LUP_RETURN_ALL, &sdp_buffer_size, sdp_result_data)) {
104 break;
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);
119 } // namespace
121 namespace device {
123 // static
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) {
136 DCHECK(observer);
137 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
138 observers_.AddObserver(observer);
141 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
142 DCHECK(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(
162 FROM_HERE,
163 base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
166 void BluetoothTaskManagerWin::StartPolling() {
167 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
169 if (device::bluetooth_init_win::HasBluetoothStack()) {
170 PollAdapter();
171 } else {
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(
177 FROM_HERE,
178 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
179 this,
180 base::Owned(state)));
184 void BluetoothTaskManagerWin::Shutdown() {
185 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
186 if (worker_pool_)
187 worker_pool_->Shutdown();
190 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
191 bool powered,
192 const base::Closure& callback,
193 const BluetoothAdapter::ErrorCallback& error_callback) {
194 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
195 bluetooth_task_runner_->PostTask(
196 FROM_HERE,
197 base::Bind(&BluetoothTaskManagerWin::SetPowered,
198 this,
199 powered,
200 callback,
201 error_callback));
204 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
205 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
206 bluetooth_task_runner_->PostTask(
207 FROM_HERE,
208 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
211 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
212 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
213 bluetooth_task_runner_->PostTask(
214 FROM_HERE,
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_,
233 DiscoveryStopped());
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.
254 if (!discovering_) {
255 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
256 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
257 if (adapter_handle_)
258 adapter_handle_.Close();
259 HANDLE temp_adapter_handle;
260 HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
261 &adapter_param, &temp_adapter_handle);
263 if (handle) {
264 adapter_handle_.Set(temp_adapter_handle);
265 GetKnownDevices();
266 BluetoothFindRadioClose(handle);
268 PostAdapterStateToUi();
271 // Re-poll.
272 bluetooth_task_runner_->PostDelayedTask(
273 FROM_HERE,
274 base::Bind(&BluetoothTaskManagerWin::PollAdapter,
275 this),
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(
284 FROM_HERE,
285 base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
286 this,
287 base::Owned(state)));
290 void BluetoothTaskManagerWin::SetPowered(
291 bool powered,
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_) {
297 if (!powered)
298 BluetoothEnableDiscovery(adapter_handle_, false);
299 success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
302 if (success) {
303 PostAdapterStateToUi();
304 ui_task_runner_->PostTask(FROM_HERE, callback);
305 } else {
306 ui_task_runner_->PostTask(FROM_HERE, error_callback);
310 void BluetoothTaskManagerWin::StartDiscovery() {
311 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
312 ui_task_runner_->PostTask(
313 FROM_HERE,
314 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
315 this,
316 !!adapter_handle_));
317 if (!adapter_handle_)
318 return;
319 discovering_ = true;
321 DiscoverDevices(1);
324 void BluetoothTaskManagerWin::StopDiscovery() {
325 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
326 discovering_ = false;
327 ui_task_runner_->PostTask(
328 FROM_HERE,
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(
336 FROM_HERE,
337 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
338 return;
341 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
342 SearchDevices(timeout, false, device_list);
343 if (device_list->empty()) {
344 delete device_list;
345 } else {
346 DiscoverServices(device_list);
347 ui_task_runner_->PostTask(
348 FROM_HERE,
349 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered,
350 this,
351 base::Owned(device_list)));
354 if (timeout < kMaxDeviceDiscoveryTimeout) {
355 bluetooth_task_runner_->PostTask(
356 FROM_HERE,
357 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices,
358 this,
359 timeout + 1));
360 } else {
361 ui_task_runner_->PostTask(
362 FROM_HERE,
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()) {
372 delete device_list;
373 return;
375 DiscoverServices(device_list);
376 ui_task_runner_->PostTask(
377 FROM_HERE,
378 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated,
379 this,
380 base::Owned(device_list)));
383 void BluetoothTaskManagerWin::SearchDevices(
384 int timeout,
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
395 adapter_handle_
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);
402 if (handle) {
403 do {
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();
419 ++iter) {
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