Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / device / bluetooth / bluetooth_task_manager_win.cc
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 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState;
34
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);
54   }
55   state->name = name;
56   state->address = address;
57   state->powered = powered;
58 }
59
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;
74 }
75
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;
96   }
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;
105     }
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]);
113     }
114     service_record_states->push_back(service_record_state);
115   }
116   WSALookupServiceEnd(sdp_handle);
117 }
118
119 }  // namespace
120
121 namespace device {
122
123 // static
124 const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
125
126 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) {
127 }
128
129 BluetoothTaskManagerWin::AdapterState::~AdapterState() {
130 }
131
132 BluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() {
133 }
134
135 BluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() {
136 }
137
138 BluetoothTaskManagerWin::DeviceState::DeviceState()
139     : bluetooth_class(0),
140       visible(false),
141       connected(false),
142       authenticated(false) {
143 }
144
145 BluetoothTaskManagerWin::DeviceState::~DeviceState() {
146 }
147
148 BluetoothTaskManagerWin::BluetoothTaskManagerWin(
149     scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
150     : ui_task_runner_(ui_task_runner),
151       discovering_(false) {
152 }
153
154 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
155 }
156
157 void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
158   DCHECK(observer);
159   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
160   observers_.AddObserver(observer);
161 }
162
163 void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
164   DCHECK(observer);
165   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
166   observers_.RemoveObserver(observer);
167 }
168
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));
177 }
178
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(
184       FROM_HERE,
185       base::Bind(&BluetoothTaskManagerWin::StartPolling, this));
186 }
187
188 void BluetoothTaskManagerWin::StartPolling() {
189   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
190
191   if (device::bluetooth_init_win::HasBluetoothStack()) {
192     PollAdapter();
193   } else {
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(
199       FROM_HERE,
200       base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
201                  this,
202                  base::Owned(state)));
203   }
204 }
205
206 void BluetoothTaskManagerWin::Shutdown() {
207   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
208   if (worker_pool_)
209     worker_pool_->Shutdown();
210 }
211
212 void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask(
213     bool powered,
214     const base::Closure& callback,
215     const BluetoothAdapter::ErrorCallback& error_callback) {
216   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
217   bluetooth_task_runner_->PostTask(
218       FROM_HERE,
219       base::Bind(&BluetoothTaskManagerWin::SetPowered,
220                  this,
221                  powered,
222                  callback,
223                  error_callback));
224 }
225
226 void BluetoothTaskManagerWin::PostStartDiscoveryTask() {
227   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
228   bluetooth_task_runner_->PostTask(
229       FROM_HERE,
230       base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this));
231 }
232
233 void BluetoothTaskManagerWin::PostStopDiscoveryTask() {
234   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
235   bluetooth_task_runner_->PostTask(
236       FROM_HERE,
237       base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this));
238 }
239
240 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
241   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
242   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
243                     AdapterStateChanged(*state));
244 }
245
246 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) {
247   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
248   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
249                     DiscoveryStarted(success));
250 }
251
252 void BluetoothTaskManagerWin::OnDiscoveryStopped() {
253   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
254   FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
255                     DiscoveryStopped());
256 }
257
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));
263 }
264
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));
270 }
271
272 void BluetoothTaskManagerWin::PollAdapter() {
273   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
274
275   // Skips updating the adapter info if the adapter is in discovery mode.
276   if (!discovering_) {
277     const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
278         { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
279     if (adapter_handle_)
280       adapter_handle_.Close();
281     HANDLE temp_adapter_handle;
282     HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
283         &adapter_param, &temp_adapter_handle);
284
285     if (handle) {
286       adapter_handle_.Set(temp_adapter_handle);
287       GetKnownDevices();
288       BluetoothFindRadioClose(handle);
289     }
290     PostAdapterStateToUi();
291   }
292
293   // Re-poll.
294   bluetooth_task_runner_->PostDelayedTask(
295       FROM_HERE,
296       base::Bind(&BluetoothTaskManagerWin::PollAdapter,
297                  this),
298       base::TimeDelta::FromMilliseconds(kPollIntervalMs));
299 }
300
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(
306       FROM_HERE,
307       base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged,
308                  this,
309                  base::Owned(state)));
310 }
311
312 void BluetoothTaskManagerWin::SetPowered(
313     bool powered,
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_) {
319     if (!powered)
320       BluetoothEnableDiscovery(adapter_handle_, false);
321     success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered);
322   }
323
324   if (success) {
325     PostAdapterStateToUi();
326     ui_task_runner_->PostTask(FROM_HERE, callback);
327   } else {
328     ui_task_runner_->PostTask(FROM_HERE, error_callback);
329   }
330 }
331
332 void BluetoothTaskManagerWin::StartDiscovery() {
333   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
334   ui_task_runner_->PostTask(
335       FROM_HERE,
336       base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted,
337                  this,
338                  !!adapter_handle_));
339   if (!adapter_handle_)
340     return;
341   discovering_ = true;
342
343   DiscoverDevices(1);
344 }
345
346 void BluetoothTaskManagerWin::StopDiscovery() {
347   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
348   discovering_ = false;
349   ui_task_runner_->PostTask(
350       FROM_HERE,
351       base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
352 }
353
354 void BluetoothTaskManagerWin::DiscoverDevices(int timeout) {
355   DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
356   if (!discovering_ || !adapter_handle_) {
357     ui_task_runner_->PostTask(
358         FROM_HERE,
359         base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
360     return;
361   }
362
363   ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
364   SearchDevices(timeout, false, device_list);
365   if (device_list->empty()) {
366     delete device_list;
367   } else {
368     DiscoverServices(device_list);
369     ui_task_runner_->PostTask(
370         FROM_HERE,
371         base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered,
372                    this,
373                    base::Owned(device_list)));
374   }
375
376   if (timeout < kMaxDeviceDiscoveryTimeout) {
377     bluetooth_task_runner_->PostTask(
378         FROM_HERE,
379         base::Bind(&BluetoothTaskManagerWin::DiscoverDevices,
380                    this,
381                    timeout + 1));
382   } else {
383     ui_task_runner_->PostTask(
384         FROM_HERE,
385         base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
386     discovering_ = false;
387   }
388 }
389
390 void BluetoothTaskManagerWin::GetKnownDevices() {
391   ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>();
392   SearchDevices(1, true, device_list);
393   if (device_list->empty()) {
394     delete device_list;
395     return;
396   }
397   DiscoverServices(device_list);
398   ui_task_runner_->PostTask(
399       FROM_HERE,
400       base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated,
401                  this,
402                  base::Owned(device_list)));
403 }
404
405 void BluetoothTaskManagerWin::SearchDevices(
406     int timeout,
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
417       adapter_handle_
418   };
419
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);
424   if (handle) {
425     do {
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));
430
431     BluetoothFindDeviceClose(handle);
432   }
433 }
434
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();
441       ++iter) {
442     const std::string device_address = (*iter)->address;
443     ScopedVector<ServiceRecordState>* service_record_states =
444         &(*iter)->service_record_states;
445
446     DiscoverDeviceServices(
447         device_address, L2CAP_PROTOCOL_UUID, service_record_states);
448   }
449 }
450
451 }  // namespace device