blob: 82f3ab402527db2e3412f6e162179ec85a7b64f3 [file] [log] [blame]
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -07001//
Jakub Pawlowski5b790fe2017-09-18 09:00:20 -07002// Copyright 2016 The Android Open Source Project
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -07003//
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
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070019#include "service/adapter.h"
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070020#include "service/logging_helpers.h"
21#include "stack/include/bt_types.h"
22#include "stack/include/hcidefs.h"
23
Jakub Pawlowski67f5f372018-07-23 10:00:25 -070024#include <base/bind.h>
25#include <base/callback.h>
26#include <base/logging.h>
27
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070028using 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|.
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -080044size_t GetScanRecordLength(std::vector<uint8_t> bytes) {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070045 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.
Myles Watson911d1ae2016-11-28 16:44:40 -080057 if (field_len == 0) return i;
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070058 }
59
60 // We have reached the end.
61 return kScanRecordLength;
62}
63
64} // namespace
65
66// LowEnergyScanner implementation
67// ========================================================
68
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -070069LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const Uuid& uuid,
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070070 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
Jakub Pawlowski83f1d962016-12-14 09:49:38 -080084 hal::BluetoothGattInterface::Get()->GetScannerHALInterface()->Unregister(
85 scanner_id_);
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070086
87 // Stop any scans started by this client.
Myles Watson911d1ae2016-11-28 16:44:40 -080088 if (scan_started_.load()) StopScan();
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070089}
90
91void LowEnergyScanner::SetDelegate(Delegate* delegate) {
92 lock_guard<mutex> lock(delegate_mutex_);
93 delegate_ = delegate;
94}
95
96bool LowEnergyScanner::StartScan(const ScanSettings& settings,
Myles Watson911d1ae2016-11-28 16:44:40 -080097 const std::vector<ScanFilter>& filters) {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -070098 VLOG(2) << __func__;
99
100 // Cannot start a scan if the adapter is not enabled.
101 if (!adapter_.IsEnabled()) {
102 LOG(ERROR) << "Cannot scan while Bluetooth is disabled";
103 return false;
104 }
105
106 // TODO(jpawlowski): Push settings and filtering logic below the HAL.
Myles Watson911d1ae2016-11-28 16:44:40 -0800107 bt_status_t status =
108 hal::BluetoothGattInterface::Get()->StartScan(scanner_id_);
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700109 if (status != BT_STATUS_SUCCESS) {
110 LOG(ERROR) << "Failed to initiate scanning for client: " << scanner_id_;
111 return false;
112 }
113
114 scan_started_ = true;
115 return true;
116}
117
118bool LowEnergyScanner::StopScan() {
119 VLOG(2) << __func__;
120
121 // TODO(armansito): We don't support batch scanning yet so call
122 // StopRegularScanForClient directly. In the future we will need to
123 // conditionally call a batch scan API here.
Myles Watson911d1ae2016-11-28 16:44:40 -0800124 bt_status_t status =
125 hal::BluetoothGattInterface::Get()->StopScan(scanner_id_);
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700126 if (status != BT_STATUS_SUCCESS) {
127 LOG(ERROR) << "Failed to stop scan for client: " << scanner_id_;
128 return false;
129 }
130
131 scan_started_ = false;
132 return true;
133}
134
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700135const Uuid& LowEnergyScanner::GetAppIdentifier() const {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700136 return app_identifier_;
137}
138
Myles Watson911d1ae2016-11-28 16:44:40 -0800139int LowEnergyScanner::GetInstanceId() const { return scanner_id_; }
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700140
141void LowEnergyScanner::ScanResultCallback(
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700142 hal::BluetoothGattInterface* gatt_iface, const RawAddress& bda, int rssi,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800143 std::vector<uint8_t> adv_data) {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700144 // Ignore scan results if this client didn't start a scan.
Myles Watson911d1ae2016-11-28 16:44:40 -0800145 if (!scan_started_.load()) return;
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700146
147 lock_guard<mutex> lock(delegate_mutex_);
Myles Watson911d1ae2016-11-28 16:44:40 -0800148 if (!delegate_) return;
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700149
150 // TODO(armansito): Apply software filters here.
151
152 size_t record_len = GetScanRecordLength(adv_data);
Myles Watson911d1ae2016-11-28 16:44:40 -0800153 std::vector<uint8_t> scan_record(adv_data.begin(),
154 adv_data.begin() + record_len);
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700155
156 ScanResult result(BtAddrString(&bda), scan_record, rssi);
157
158 delegate_->OnScanResult(this, result);
159}
160
161// LowEnergyScannerFactory implementation
162// ========================================================
163
Myles Watson911d1ae2016-11-28 16:44:40 -0800164LowEnergyScannerFactory::LowEnergyScannerFactory(Adapter& adapter)
165 : adapter_(adapter) {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700166 hal::BluetoothGattInterface::Get()->AddScannerObserver(this);
167}
168
169LowEnergyScannerFactory::~LowEnergyScannerFactory() {
170 hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this);
171}
172
173bool LowEnergyScannerFactory::RegisterInstance(
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700174 const Uuid& uuid, const RegisterCallback& callback) {
175 VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700176 lock_guard<mutex> lock(pending_calls_lock_);
177
178 if (pending_calls_.find(uuid) != pending_calls_.end()) {
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700179 LOG(ERROR) << "Low-Energy scanner with given Uuid already registered - "
180 << "Uuid: " << uuid.ToString();
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700181 return false;
182 }
183
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800184 BleScannerInterface* hal_iface =
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700185 hal::BluetoothGattInterface::Get()->GetScannerHALInterface();
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700186
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800187 hal_iface->RegisterScanner(
188 base::Bind(&LowEnergyScannerFactory::RegisterScannerCallback,
189 base::Unretained(this), callback, uuid));
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700190
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800191 pending_calls_.insert(uuid);
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700192
193 return true;
194}
195
196void LowEnergyScannerFactory::RegisterScannerCallback(
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700197 const RegisterCallback& callback, const Uuid& app_uuid, uint8_t scanner_id,
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800198 uint8_t status) {
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700199 Uuid uuid(app_uuid);
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700200
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700201 VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700202 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
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800216 hal::BluetoothGattInterface::Get()->AddScannerObserver(scanner.get());
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700217
218 result = BLE_STATUS_SUCCESS;
219 }
220
221 // Notify the result via the result callback.
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800222 callback(result, app_uuid, std::move(scanner));
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700223
224 pending_calls_.erase(iter);
225}
226
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700227} // namespace bluetooth