12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_task_manager_win.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <winsock2.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string> 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/ref_counted.h" 149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/sequenced_task_runner.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_handle.h" 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "device/bluetooth/bluetooth_device.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_init_win.h" 22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "device/bluetooth/bluetooth_low_energy_win.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "device/bluetooth/bluetooth_service_record_win.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/winsock_init.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kNumThreadsInWorkerPool = 3; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaxNumDeviceAddressChar = 127; 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kServiceDiscoveryResultBufferSize = 5000; 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// out for the inquiry, expressed in increments of 1.28 seconds. For example, an 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// value for this member is 48. When a value greater than 48 is used, the 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// calling function immediately fails and returns 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kMaxDeviceDiscoveryTimeoutMultiplier = 48; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochtypedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; 41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Note: The string returned here must have the same format as 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// BluetoothDevice::CanonicalizeAddress. 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) { 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btha.rgBytes[5], 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btha.rgBytes[4], 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btha.rgBytes[3], 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btha.rgBytes[2], 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btha.rgBytes[1], 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btha.rgBytes[0]); 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result)); 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return result; 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid( 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const BTH_LE_UUID& bth_le_uuid) { 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (bth_le_uuid.IsShortUuid) { 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string uuid_hex = 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid); 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return device::BluetoothUUID(uuid_hex); 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return device::BluetoothUUID( 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data1, 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data2, 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data3, 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[0], 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[1], 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[2], 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[3], 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[4], 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[5], 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[6], 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bth_le_uuid.Value.LongUuid.Data4[7])); 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Populates bluetooth adapter state using adapter_handle. 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GetAdapterState(HANDLE adapter_handle, 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device::BluetoothTaskManagerWin::AdapterState* state) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string name; 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string address; 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool powered = false; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 }; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (adapter_handle && 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle, 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &adapter_info)) { 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) name = base::SysWideToUTF8(adapter_info.szName); 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) address = BluetoothAddressToCanonicalString(adapter_info.address); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) powered = !!BluetoothIsConnectable(adapter_handle); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->name = name; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->address = address; 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->powered = powered; 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device::BluetoothTaskManagerWin::DeviceState* state) { 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->name = base::SysWideToUTF8(device_info.szName); 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) state->address = BluetoothAddressToCanonicalString(device_info.Address); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->bluetooth_class = device_info.ulClassofDevice; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->visible = true; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->connected = !!device_info.fConnected; 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->authenticated = !!device_info.fAuthenticated; 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace device { 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int BluetoothTaskManagerWin::kPollIntervalMs = 500; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) { 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::AdapterState::~AdapterState() { 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::ServiceRecordState::ServiceRecordState() { 1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::ServiceRecordState::~ServiceRecordState() { 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::DeviceState::DeviceState() 1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : bluetooth_class(0), 1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu visible(false), 1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu connected(false), 1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu authenticated(false) { 1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothTaskManagerWin::DeviceState::~DeviceState() { 1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BluetoothTaskManagerWin::BluetoothTaskManagerWin( 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> ui_task_runner) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : ui_task_runner_(ui_task_runner), 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) discovering_(false), 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_logging_batch_count_(0) { 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::AddObserver(Observer* observer) { 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(observer); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) { 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(observer); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::Initialize() { 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool, 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kBluetoothThreadName); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InitializeWithBluetoothTaskRunner( 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) worker_pool_->GetSequenceToken(), 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner( 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) { 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bluetooth_task_runner_ = bluetooth_task_runner; 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bluetooth_task_runner_->PostTask( 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::StartPolling, this)); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::StartPolling() { 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (device::bluetooth_init_win::HasBluetoothStack()) { 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PollAdapter(); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IF the bluetooth stack is not available, we still send an empty state 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to BluetoothAdapter so that it is marked initialized, but the adapter 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // will not be present. 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AdapterState* state = new AdapterState(); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Owned(state))); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::Shutdown() { 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (worker_pool_) 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) worker_pool_->Shutdown(); 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask( 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool powered, 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& callback, 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BluetoothAdapter::ErrorCallback& error_callback) { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bluetooth_task_runner_->PostTask( 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::SetPowered, 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) powered, 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback, 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) error_callback)); 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostStartDiscoveryTask() { 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bluetooth_task_runner_->PostTask( 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostStopDiscoveryTask() { 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bluetooth_task_runner_->PostTask( 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::LogPollingError(const char* message, 2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int win32_error) { 2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int kLogPeriodInMilliseconds = 60 * 1000; 2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int kMaxMessagesPerLogPeriod = 10; 2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Check if we need to discard this message 2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!current_logging_batch_ticks_.is_null()) { 2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (base::TimeTicks::Now() - current_logging_batch_ticks_ <= 2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) { 2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod) 2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The batch expired, reset it to "null". 2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_logging_batch_ticks_ = base::TimeTicks(); 2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Keep track of this batch of messages 2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (current_logging_batch_ticks_.is_null()) { 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_logging_batch_ticks_ = base::TimeTicks::Now(); 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_logging_batch_count_ = 0; 2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++current_logging_batch_count_; 2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Log the message 2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (win32_error == 0) 2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(WARNING) << message; 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else 2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(WARNING) << message << ": " 2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << logging::SystemErrorCodeToString(win32_error); 2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AdapterStateChanged(*state)); 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiscoveryStarted(success)); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::OnDiscoveryStopped() { 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiscoveryStopped()); 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::OnDevicesPolled( 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ScopedVector<DeviceState>* devices) { 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); 2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FOR_EACH_OBSERVER( 2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices)); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PollAdapter() { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Skips updating the adapter info if the adapter is in discovery mode. 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!discovering_) { 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (adapter_handle_) 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) adapter_handle_.Close(); 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) HANDLE temp_adapter_handle; 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio( 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &adapter_param, &temp_adapter_handle); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (handle) { 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) adapter_handle_.Set(temp_adapter_handle); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetKnownDevices(); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BluetoothFindRadioClose(handle); 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PostAdapterStateToUi(); 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Re-poll. 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bluetooth_task_runner_->PostDelayedTask( 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::PollAdapter, 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this), 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kPollIntervalMs)); 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::PostAdapterStateToUi() { 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AdapterState* state = new AdapterState(); 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetAdapterState(adapter_handle_, state); 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Owned(state))); 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::SetPowered( 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool powered, 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& callback, 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BluetoothAdapter::ErrorCallback& error_callback) { 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success = false; 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (adapter_handle_) { 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!powered) 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BluetoothEnableDiscovery(adapter_handle_, false); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success = !!BluetoothEnableIncomingConnections(adapter_handle_, powered); 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (success) { 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PostAdapterStateToUi(); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask(FROM_HERE, callback); 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask(FROM_HERE, error_callback); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::StartDiscovery() { 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted, 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !!adapter_handle_)); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!adapter_handle_) 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) discovering_ = true; 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DiscoverDevices(1); 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothTaskManagerWin::StopDiscovery() { 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) discovering_ = false; 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) { 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!discovering_ || !adapter_handle_) { 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<ScopedVector<DeviceState> > device_list( 3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new ScopedVector<DeviceState>()); 3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (SearchDevices(timeout_multiplier, false, device_list.get())) { 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, 3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Owned(device_list.release()))); 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier) 3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++timeout_multiplier; 3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bluetooth_task_runner_->PostTask( 3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind( 3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier)); 3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothTaskManagerWin::GetKnownDevices() { 3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<ScopedVector<DeviceState> > device_list( 3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new ScopedVector<DeviceState>()); 4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (SearchDevices(1, true, device_list.get())) { 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, 4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this, 4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Owned(device_list.release()))); 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::SearchDevices( 4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int timeout_multiplier, 4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool search_cached_devices_only, 4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<DeviceState>* device_list) { 4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return SearchClassicDevices( 4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) timeout_multiplier, search_cached_devices_only, device_list) && 4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SearchLowEnergyDevices(device_list) && 4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DiscoverServices(device_list, search_cached_devices_only); 4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::SearchClassicDevices( 4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int timeout_multiplier, 4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool search_cached_devices_only, 4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<DeviceState>* device_list) { 4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds. 4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params; 4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ZeroMemory(&device_search_params, sizeof(device_search_params)); 4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS); 4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.fReturnAuthenticated = 1; 4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.fReturnRemembered = 1; 4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1); 4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.fReturnConnected = 1; 4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1); 4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_search_params.cTimeoutMultiplier = timeout_multiplier; 4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BLUETOOTH_DEVICE_INFO device_info; 4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ZeroMemory(&device_info, sizeof(device_info)); 4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); 4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HBLUETOOTH_DEVICE_FIND handle = 4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothFindFirstDevice(&device_search_params, &device_info); 4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!handle) { 4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int last_error = GetLastError(); 4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (last_error == ERROR_NO_MORE_ITEMS) { 4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; // No devices is not an error. 4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogPollingError("Error calling BluetoothFindFirstDevice", last_error); 4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (true) { 4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DeviceState* device_state = new DeviceState(); 4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetDeviceState(device_info, device_state); 4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_list->push_back(device_state); 4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Reset device info before next call (as a safety precaution). 4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ZeroMemory(&device_info, sizeof(device_info)); 4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); 4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!BluetoothFindNextDevice(handle, &device_info)) { 4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int last_error = GetLastError(); 4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (last_error == ERROR_NO_MORE_ITEMS) { 4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) break; // No more items is expected error when done enumerating. 460116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 4615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogPollingError("Error calling BluetoothFindNextDevice", last_error); 4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothFindDeviceClose(handle); 4635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 464116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 465116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 466116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!BluetoothFindDeviceClose(handle)) { 4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError()); 4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::SearchLowEnergyDevices( 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedVector<DeviceState>* device_list) { 4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!win::IsBluetoothLowEnergySupported()) 4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; // Bluetooth LE not supported is not an error. 4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices; 4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string error; 4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool success = 4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error); 4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!success) { 4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogPollingError(error.c_str(), 0); 4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter = 4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) btle_devices.begin(); 4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) iter != btle_devices.end(); 4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++iter) { 4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) win::BluetoothLowEnergyDeviceInfo* device_info = (*iter); 4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DeviceState* device_state = new DeviceState(); 4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_state->name = device_info->friendly_name; 4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_state->address = 4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAddressToCanonicalString(device_info->address); 4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_state->visible = device_info->visible; 4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_state->authenticated = device_info->authenticated; 4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_state->connected = device_info->connected; 5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_state->path = device_info->path; 5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_list->push_back(device_state); 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::DiscoverServices( 5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<DeviceState>* device_list, 5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool search_cached_services_only) { 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::EnsureWinsockInit(); 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iter != device_list->end(); 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++iter) { 5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DeviceState* device = (*iter); 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedVector<ServiceRecordState>* service_record_states = 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &(*iter)->service_record_states; 517c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ((*iter)->is_bluetooth_classic()) { 5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!DiscoverClassicDeviceServices(device->address, 5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) L2CAP_PROTOCOL_UUID, 5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) search_cached_services_only, 5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_record_states)) { 5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!DiscoverLowEnergyDeviceServices(device->path, 5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_record_states)) { 5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices( 5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string& device_address, 5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const GUID& protocol_uuid, 5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool search_cached_services_only, 5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<ServiceRecordState>* service_record_states) { 54003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int error_code = 54103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DiscoverClassicDeviceServicesWorker(device_address, 54203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) protocol_uuid, 54303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) search_cached_services_only, 54403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) service_record_states); 54503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // If the device is "offline", no services are returned when specifying 54603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // "LUP_FLUSHCACHE". Try again without flushing the cache so that the list 54703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // of previously known services is returned. 54803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!search_cached_services_only && 54903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) (error_code == WSASERVICE_NOT_FOUND || error_code == WSANO_DATA)) { 55003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) error_code = DiscoverClassicDeviceServicesWorker( 55103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) device_address, protocol_uuid, true, service_record_states); 55203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 55303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 55403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return (error_code == ERROR_SUCCESS); 55503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 55603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 55703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker( 55803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const std::string& device_address, 55903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const GUID& protocol_uuid, 56003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) bool search_cached_services_only, 56103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ScopedVector<ServiceRecordState>* service_record_states) { 5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. 5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WSAQUERYSET sdp_query; 5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ZeroMemory(&sdp_query, sizeof(sdp_query)); 5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sdp_query.dwSize = sizeof(sdp_query); 5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GUID protocol = protocol_uuid; 5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sdp_query.lpServiceClassId = &protocol; 5685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sdp_query.dwNameSpace = NS_BTH; 5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) wchar_t device_address_context[kMaxNumDeviceAddressChar]; 5705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( 5715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_address_context, kMaxNumDeviceAddressChar); 5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_address_context[length] = NULL; 5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sdp_query.lpszContext = device_address_context; 5745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DWORD control_flags = LUP_RETURN_ALL; 5755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // See http://goo.gl/t1Hulo: "Applications should generally specify 5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached 5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // information and establish an over-the-air SDP connection to the specified 5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // device to perform the SDP search. This non-cached operation may take 5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // several seconds (whereas a cached search returns quickly)." 5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list 5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // of services for devices which have not been discovered before. 5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!search_cached_services_only) 5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) control_flags |= LUP_FLUSHCACHE; 5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HANDLE sdp_handle; 5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ERROR_SUCCESS != 5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) { 58703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int last_error = WSAGetLastError(); 58803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // If the device is "offline", no services are returned when specifying 58903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // "LUP_FLUSHCACHE". Don't log error in that case. 59003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!search_cached_services_only && 59103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) (last_error == WSASERVICE_NOT_FOUND || last_error == WSANO_DATA)) { 59203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return last_error; 59303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 59403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) LogPollingError("Error calling WSALookupServiceBegin", last_error); 59503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return last_error; 5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) char sdp_buffer[kServiceDiscoveryResultBufferSize]; 5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); 5995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (true) { 6005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DWORD sdp_buffer_size = sizeof(sdp_buffer); 6015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ERROR_SUCCESS != 6025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WSALookupServiceNext( 6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) { 6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int last_error = WSAGetLastError(); 6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) { 6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) break; 6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogPollingError("Error calling WSALookupServiceNext", last_error); 6095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WSALookupServiceEnd(sdp_handle); 61003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return last_error; 6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ServiceRecordState* service_record_state = new ServiceRecordState(); 6135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_record_state->name = 6145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); 6155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { 6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_record_state->sdp_bytes.push_back( 6175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) sdp_result_data->lpBlob->pBlobData[i]); 6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_record_states->push_back(service_record_state); 6205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) { 62203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int last_error = WSAGetLastError(); 62303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) LogPollingError("Error calling WSALookupServiceEnd", last_error); 62403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return last_error; 6255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 62703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return ERROR_SUCCESS; 6285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 6295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 6305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices( 6315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::FilePath& device_path, 6325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<ServiceRecordState>* service_record_states) { 6335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!win::IsBluetoothLowEnergySupported()) 6345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; // Bluetooth LE not supported is not an error. 6355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 6365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string error; 6375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScopedVector<win::BluetoothLowEnergyServiceInfo> services; 6385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool success = win::EnumerateKnownBluetoothLowEnergyServices( 6395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_path, &services, &error); 6405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!success) { 6415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LogPollingError(error.c_str(), 0); 6425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 6435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 6455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 = 6465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) services.begin(); 6475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) iter2 != services.end(); 6485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++iter2) { 6495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ServiceRecordState* service_state = new ServiceRecordState(); 6505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_state->gatt_uuid = 6515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid); 6525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_record_states->push_back(service_state); 6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace device 658