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