low_energy_scanner.cc revision 911d1ae03efec2d54c3b1b605589d790d1745488
1// 2// Copyright (C) 2016 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at: 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "service/low_energy_scanner.h" 18 19#include <base/bind.h> 20#include <base/logging.h> 21 22#include "service/adapter.h" 23#include "service/common/bluetooth/util/address_helper.h" 24#include "service/logging_helpers.h" 25#include "stack/include/bt_types.h" 26#include "stack/include/hcidefs.h" 27 28using std::lock_guard; 29using std::mutex; 30 31namespace bluetooth { 32 33namespace { 34 35// 31 + 31 for advertising data and scan response. This is the maximum length 36// TODO(armansito): Fix the HAL to return a concatenated blob that contains the 37// true length of each field and also provide a length parameter so that we 38// can support advertising length extensions in the future. 39const size_t kScanRecordLength = 62; 40 41// Returns the length of the given scan record array. We have to calculate this 42// based on the maximum possible data length and the TLV data. See TODO above 43// |kScanRecordLength|. 44size_t GetScanRecordLength(vector<uint8_t> bytes) { 45 for (size_t i = 0, field_len = 0; i < kScanRecordLength; 46 i += (field_len + 1)) { 47 field_len = bytes[i]; 48 49 // Assert here that the data returned from the stack is correctly formatted 50 // in TLV form and that the length of the current field won't exceed the 51 // total data length. 52 CHECK(i + field_len < kScanRecordLength); 53 54 // If the field length is zero and we haven't reached the maximum length, 55 // then we have found the length, as the stack will pad the data with zeros 56 // accordingly. 57 if (field_len == 0) return i; 58 } 59 60 // We have reached the end. 61 return kScanRecordLength; 62} 63 64} // namespace 65 66// LowEnergyScanner implementation 67// ======================================================== 68 69LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const UUID& uuid, 70 int scanner_id) 71 : adapter_(adapter), 72 app_identifier_(uuid), 73 scanner_id_(scanner_id), 74 scan_started_(false), 75 delegate_(nullptr) {} 76 77LowEnergyScanner::~LowEnergyScanner() { 78 // Automatically unregister the scanner. 79 VLOG(1) << "LowEnergyScanner unregistering scanner: " << scanner_id_; 80 81 // Unregister as observer so we no longer receive any callbacks. 82 hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this); 83 84 hal::BluetoothGattInterface::Get() 85 ->GetScannerHALInterface() 86 ->unregister_scanner(scanner_id_); 87 88 // Stop any scans started by this client. 89 if (scan_started_.load()) StopScan(); 90} 91 92void LowEnergyScanner::SetDelegate(Delegate* delegate) { 93 lock_guard<mutex> lock(delegate_mutex_); 94 delegate_ = delegate; 95} 96 97bool LowEnergyScanner::StartScan(const ScanSettings& settings, 98 const std::vector<ScanFilter>& filters) { 99 VLOG(2) << __func__; 100 101 // Cannot start a scan if the adapter is not enabled. 102 if (!adapter_.IsEnabled()) { 103 LOG(ERROR) << "Cannot scan while Bluetooth is disabled"; 104 return false; 105 } 106 107 // TODO(jpawlowski): Push settings and filtering logic below the HAL. 108 bt_status_t status = 109 hal::BluetoothGattInterface::Get()->StartScan(scanner_id_); 110 if (status != BT_STATUS_SUCCESS) { 111 LOG(ERROR) << "Failed to initiate scanning for client: " << scanner_id_; 112 return false; 113 } 114 115 scan_started_ = true; 116 return true; 117} 118 119bool LowEnergyScanner::StopScan() { 120 VLOG(2) << __func__; 121 122 // TODO(armansito): We don't support batch scanning yet so call 123 // StopRegularScanForClient directly. In the future we will need to 124 // conditionally call a batch scan API here. 125 bt_status_t status = 126 hal::BluetoothGattInterface::Get()->StopScan(scanner_id_); 127 if (status != BT_STATUS_SUCCESS) { 128 LOG(ERROR) << "Failed to stop scan for client: " << scanner_id_; 129 return false; 130 } 131 132 scan_started_ = false; 133 return true; 134} 135 136const UUID& LowEnergyScanner::GetAppIdentifier() const { 137 return app_identifier_; 138} 139 140int LowEnergyScanner::GetInstanceId() const { return scanner_id_; } 141 142void LowEnergyScanner::ScanResultCallback( 143 hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi, 144 vector<uint8_t> adv_data) { 145 // Ignore scan results if this client didn't start a scan. 146 if (!scan_started_.load()) return; 147 148 lock_guard<mutex> lock(delegate_mutex_); 149 if (!delegate_) return; 150 151 // TODO(armansito): Apply software filters here. 152 153 size_t record_len = GetScanRecordLength(adv_data); 154 std::vector<uint8_t> scan_record(adv_data.begin(), 155 adv_data.begin() + record_len); 156 157 ScanResult result(BtAddrString(&bda), scan_record, rssi); 158 159 delegate_->OnScanResult(this, result); 160} 161 162// LowEnergyScannerFactory implementation 163// ======================================================== 164 165LowEnergyScannerFactory::LowEnergyScannerFactory(Adapter& adapter) 166 : adapter_(adapter) { 167 hal::BluetoothGattInterface::Get()->AddScannerObserver(this); 168} 169 170LowEnergyScannerFactory::~LowEnergyScannerFactory() { 171 hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this); 172} 173 174bool LowEnergyScannerFactory::RegisterInstance( 175 const UUID& uuid, const RegisterCallback& callback) { 176 VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); 177 lock_guard<mutex> lock(pending_calls_lock_); 178 179 if (pending_calls_.find(uuid) != pending_calls_.end()) { 180 LOG(ERROR) << "Low-Energy scanner with given UUID already registered - " 181 << "UUID: " << uuid.ToString(); 182 return false; 183 } 184 185 const btgatt_scanner_interface_t* hal_iface = 186 hal::BluetoothGattInterface::Get()->GetScannerHALInterface(); 187 bt_uuid_t app_uuid = uuid.GetBlueDroid(); 188 189 if (hal_iface->register_scanner(&app_uuid) != BT_STATUS_SUCCESS) return false; 190 191 pending_calls_[uuid] = callback; 192 193 return true; 194} 195 196void LowEnergyScannerFactory::RegisterScannerCallback( 197 hal::BluetoothGattInterface* gatt_iface, int status, int scanner_id, 198 const bt_uuid_t& app_uuid) { 199 UUID uuid(app_uuid); 200 201 VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); 202 lock_guard<mutex> lock(pending_calls_lock_); 203 204 auto iter = pending_calls_.find(uuid); 205 if (iter == pending_calls_.end()) { 206 VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString(); 207 return; 208 } 209 210 // No need to construct a scanner if the call wasn't successful. 211 std::unique_ptr<LowEnergyScanner> scanner; 212 BLEStatus result = BLE_STATUS_FAILURE; 213 if (status == BT_STATUS_SUCCESS) { 214 scanner.reset(new LowEnergyScanner(adapter_, uuid, scanner_id)); 215 216 gatt_iface->AddScannerObserver(scanner.get()); 217 218 result = BLE_STATUS_SUCCESS; 219 } 220 221 // Notify the result via the result callback. 222 iter->second(result, uuid, std::move(scanner)); 223 224 pending_calls_.erase(iter); 225} 226 227} // namespace bluetooth 228