1 /*
2 * Copyright (C) 2023 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 "location/lbs/contexthub/nanoapps/nearby/ble_scanner.h"
18
19 #include <chre.h>
20
21 #include <cstdint>
22 #include <cstring>
23 #include <utility>
24
25 #include "third_party/contexthub/chre/util/include/chre/util/macros.h"
26 #include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
27
28 #ifdef MOCK_BLE
29 #include "chre/util/time.h"
30 #include "location/lbs/contexthub/nanoapps/nearby/mock_ble.h"
31
32 uint32_t mock_ble_timer_id = CHRE_TIMER_INVALID;
33 uint32_t mock_ble_flush_complete_timer_id = CHRE_TIMER_INVALID;
34 #endif
35
36 uint32_t ble_scan_keep_alive_timer_id = CHRE_TIMER_INVALID;
37
38 #define LOG_TAG "[NEARBY][BLE_SCANNER]"
39
40 namespace nearby {
41 #ifdef MOCK_BLE
BleScanner()42 BleScanner::BleScanner() {
43 is_ble_scan_supported_ = true;
44 is_batch_supported_ = nearby::MockBle::kBleBatchScanSupported;
45 report_delay_ms_ = kBatchScanReportDelayLowPowerMilliSec;
46 }
47
Start()48 void BleScanner::Start() {
49 if (is_started_) {
50 LOGD("Mock BLE scan already started.");
51 return;
52 }
53 Restart();
54 }
55
Restart()56 void BleScanner::Restart() {
57 LOGD("Start mock BLE events in scan mode %d.", scan_mode_);
58 if (is_started_) {
59 chreTimerCancel(mock_ble_timer_id);
60 }
61 mock_ble_timer_id =
62 chreTimerSet(chre::Milliseconds(report_delay_ms_).toRawNanoseconds(),
63 &mock_ble_timer_id, false);
64 is_started_ = true;
65 }
66
Stop()67 void BleScanner::Stop() {
68 if (!is_started_) {
69 LOGD("Mock BLE scan already stopped.");
70 return;
71 }
72 LOGD("Stop mock BLE events.");
73 chreTimerCancel(mock_ble_timer_id);
74 if (mock_ble_flush_complete_timer_id != CHRE_TIMER_INVALID) {
75 chreTimerCancel(mock_ble_flush_complete_timer_id);
76 mock_ble_flush_complete_timer_id = CHRE_TIMER_INVALID;
77 }
78 is_started_ = false;
79 }
80
UpdateBatchDelay(uint32_t delay_ms)81 void BleScanner::UpdateBatchDelay(uint32_t delay_ms) {
82 bool is_updated = false;
83 if (!is_batch_supported_) {
84 LOGD("Batch scan is not supported");
85 return;
86 }
87 // avoids the report delay from being set too small for simulation
88 if (delay_ms < nearby::MockBle::kBleReportDelayMinMs) {
89 LOGE("Requested report delay is too small");
90 return;
91 }
92 if (report_delay_ms_ != delay_ms) {
93 report_delay_ms_ = delay_ms;
94 is_updated = true;
95 }
96 // restart scan with new parameter if scan is already started
97 if (is_updated && is_started_) {
98 Restart();
99 }
100 }
101
Flush()102 bool BleScanner::Flush() {
103 if (!is_batch_supported_) {
104 LOGD("Batch scan is not supported");
105 return false;
106 }
107 if (!is_started_) {
108 LOGD("Mock BLE scan was not started.");
109 return false;
110 }
111 if (IsFlushing()) {
112 LOGD("Flushing BLE scan is already in progress.");
113 return true;
114 }
115 // stops normal BLE scan result timer internally
116 chreTimerCancel(mock_ble_timer_id);
117 // simulates the flushed scan results
118 mock_ble_flush_complete_timer_id = chreTimerSet(
119 chre::Milliseconds(nearby::MockBle::kBleFlushCompleteTimeoutMs)
120 .toRawNanoseconds(),
121 &mock_ble_flush_complete_timer_id, true);
122 mock_ble_timer_id = chreTimerSet(
123 chre::Milliseconds(nearby::MockBle::kBleFlushScanResultIntervalMs)
124 .toRawNanoseconds(),
125 &mock_ble_timer_id, false);
126 is_batch_flushing_ = true;
127 return true;
128 }
129
HandleEvent(uint16_t event_type,const void * event_data)130 void BleScanner::HandleEvent(uint16_t event_type, const void *event_data) {
131 const chreAsyncResult *async_result;
132 switch (event_type) {
133 case CHRE_EVENT_BLE_FLUSH_COMPLETE:
134 async_result = static_cast<const chreAsyncResult *>(event_data);
135 LOGD("Received mock flush complete event: return_code(%u) cookie(%p)",
136 async_result->errorCode, async_result->cookie);
137 // stops the flushed scan results timer internally
138 chreTimerCancel(mock_ble_timer_id);
139 mock_ble_flush_complete_timer_id = CHRE_TIMER_INVALID;
140 is_batch_flushing_ = false;
141 if (is_started_) {
142 Restart();
143 }
144 break;
145 default:
146 LOGD("Unknown mock scan control event_type: %d", event_type);
147 }
148 }
149 #else
150 constexpr chreBleGenericFilter kDefaultGenericFilters[] = {
151 {
152 .type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE,
153 .len = 2,
154 // Fast Pair Service UUID in OTA format.
155 .data = {0x2c, 0xfe},
156 .dataMask = {0xff, 0xff},
157 },
158 {
159 .type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE,
160 .len = 2,
161 // Presence Service UUID in OTA format.
162 .data = {0xf1, 0xfc},
163 .dataMask = {0xff, 0xff},
164 }};
165
166 BleScanner::BleScanner() {
167 if (!(chreBleGetCapabilities() & CHRE_BLE_CAPABILITIES_SCAN)) {
168 LOGE("BLE scan not supported.");
169 is_ble_scan_supported_ = false;
170 }
171 if (!(chreBleGetFilterCapabilities() &
172 CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA)) {
173 LOGI("BLE filter by service UUID not supported.");
174 }
175 if (chreBleGetCapabilities() & CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING) {
176 is_batch_supported_ = true;
177 report_delay_ms_ = kBatchScanReportDelayLowPowerMilliSec;
178 }
179 }
180
181 void BleScanner::Start() {
182 if (is_started_) {
183 LOGD("BLE scan already started.");
184 return;
185 }
186 Restart();
187 }
188
189 bool BleScanner::ContainsFilter(
190 const chre::DynamicVector<chreBleGenericFilter> &filters,
191 const chreBleGenericFilter &src) {
192 bool contained = false;
193 for (const auto &dst : filters) {
194 if (src.type == dst.type && src.len == dst.len) {
195 if (memcmp(src.data, dst.data, src.len) == 0 &&
196 memcmp(src.dataMask, dst.dataMask, src.len) == 0) {
197 contained = true;
198 break;
199 }
200 }
201 }
202 return contained;
203 }
204
205 void BleScanner::Restart() {
206 if (!is_ble_scan_supported_) {
207 LOGE("Failed to start BLE scan on an unsupported device");
208 return;
209 }
210 chre::DynamicVector<chreBleGenericFilter> generic_filters;
211 if (is_default_generic_filter_enabled_) {
212 for (size_t i = 0; i < ARRAY_SIZE(kDefaultGenericFilters); i++) {
213 generic_filters.push_back(kDefaultGenericFilters[i]);
214 }
215 }
216 if (is_tracker_filter_enabled_) {
217 for (auto &tracker_filter : tracker_filters_) {
218 if (!ContainsFilter(generic_filters, tracker_filter)) {
219 generic_filters.push_back(tracker_filter);
220 }
221 }
222 }
223 for (auto &oem_generic_filters : generic_filters_list_) {
224 for (auto &generic_filter : oem_generic_filters.filters) {
225 if (!ContainsFilter(generic_filters, generic_filter)) {
226 generic_filters.push_back(generic_filter);
227 }
228 }
229 }
230 chreBleScanFilter scan_filter;
231 memset(&scan_filter, 0, sizeof(scan_filter));
232 scan_filter.rssiThreshold = CHRE_BLE_RSSI_THRESHOLD_NONE;
233 scan_filter.scanFilters = generic_filters.data();
234 scan_filter.scanFilterCount = static_cast<uint8_t>(generic_filters.size());
235 if (chreBleStartScanAsync(scan_mode_, report_delay_ms_, &scan_filter)) {
236 LOGD("Succeeded to start BLE scan");
237 // is_started_ is set to true here, but it can be set back to false
238 // if CHRE_BLE_REQUEST_TYPE_START_SCAN request is failed in
239 // CHRE_EVENT_BLE_ASYNC_RESULT event.
240 is_started_ = true;
241 StartKeepAliveTimer();
242 } else {
243 LOGE("Failed to start BLE scan");
244 }
245 }
246
247 void BleScanner::Stop() {
248 if (!is_started_) {
249 LOGD("BLE scan already stopped.");
250 return;
251 }
252 if (chreBleStopScanAsync()) {
253 LOGD("Succeeded Stop BLE scan.");
254 is_started_ = false;
255 } else {
256 LOGE("Failed to stop BLE scan");
257 }
258 if (tracker_filters_.empty()) {
259 StopKeepAliveTimer();
260 }
261 }
262
263 bool BleScanner::UpdateFilters(
264 uint16_t host_end_point,
265 chre::DynamicVector<chreBleGenericFilter> *generic_filters) {
266 size_t index = 0;
267 while (index < generic_filters_list_.size()) {
268 if (generic_filters_list_[index].end_point == host_end_point) {
269 if (generic_filters->empty()) {
270 generic_filters_list_.erase(index);
271 } else {
272 generic_filters_list_[index].filters = std::move(*generic_filters);
273 }
274 return true;
275 }
276 ++index;
277 }
278 if (generic_filters_list_.push_back(GenericFilters(host_end_point))) {
279 generic_filters_list_.back().filters = std::move(*generic_filters);
280 } else {
281 LOGE("Failed to add new hardware filter.");
282 return false;
283 }
284 return true;
285 }
286
287 void BleScanner::UpdateBatchDelay(uint32_t delay_ms) {
288 bool is_updated = false;
289 if (!is_batch_supported_) {
290 LOGD("Batch scan is not supported");
291 return;
292 }
293 if (report_delay_ms_ != delay_ms) {
294 report_delay_ms_ = delay_ms;
295 is_updated = true;
296 }
297 // restart scan with new parameter if scan is already started
298 if (is_updated && is_started_) {
299 Restart();
300 }
301 }
302
303 bool BleScanner::Flush() {
304 if (!is_batch_supported_) {
305 LOGD("Batch scan is not supported");
306 return false;
307 }
308 if (!is_started_) {
309 LOGE("BLE scan was not started.");
310 return false;
311 }
312 if (IsFlushing()) {
313 LOGD("Flushing BLE scan is already in progress.");
314 return true;
315 }
316 LOGD("Flush batch scan results");
317 if (!chreBleFlushAsync(nullptr)) {
318 LOGE("Failed to call chreBleFlushAsync()");
319 return false;
320 }
321 is_batch_flushing_ = true;
322 return true;
323 }
324
325 void BleScanner::StartKeepAliveTimer() {
326 if (ble_scan_keep_alive_timer_id == CHRE_TIMER_INVALID) {
327 ble_scan_keep_alive_timer_id = chreTimerSet(keep_alive_timer_interval_ns_,
328 &ble_scan_keep_alive_timer_id,
329 /*oneShot=*/false);
330 if (ble_scan_keep_alive_timer_id == CHRE_TIMER_INVALID) {
331 LOGE("Error in configuring BLE scan keep alive timer.");
332 }
333 }
334 }
335
336 void BleScanner::StopKeepAliveTimer() {
337 if (ble_scan_keep_alive_timer_id != CHRE_TIMER_INVALID &&
338 chreTimerCancel(ble_scan_keep_alive_timer_id)) {
339 ble_scan_keep_alive_timer_id = CHRE_TIMER_INVALID;
340 }
341 }
342
343 void BleScanner::HandleEvent(uint16_t event_type, const void *event_data) {
344 const chreAsyncResult *async_result =
345 static_cast<const chreAsyncResult *>(event_data);
346 switch (event_type) {
347 case CHRE_EVENT_BLE_FLUSH_COMPLETE:
348 LOGD("Received flush complete event: return_code(%u) cookie(%p)",
349 async_result->errorCode, async_result->cookie);
350 if (async_result->errorCode != CHRE_ERROR_NONE) {
351 LOGE("Flush failed: %u", async_result->errorCode);
352 }
353 is_batch_flushing_ = false;
354 break;
355 case CHRE_EVENT_BLE_ASYNC_RESULT:
356 if (async_result->errorCode != CHRE_ERROR_NONE) {
357 LOGE(
358 "Failed to complete the async request: "
359 "request type (%u) error code(%u)",
360 async_result->requestType, async_result->errorCode);
361 if (async_result->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN) {
362 LOGD("Failed in CHRE_BLE_REQUEST_TYPE_START_SCAN");
363 if (is_started_) {
364 is_started_ = false;
365 }
366 StopKeepAliveTimer();
367 } else if (async_result->requestType ==
368 CHRE_BLE_REQUEST_TYPE_STOP_SCAN) {
369 LOGD("Failed in CHRE_BLE_REQUEST_TYPE_STOP_SCAN");
370 }
371 }
372 break;
373 default:
374 LOGD("Unknown scan control event_type: %d", event_type);
375 }
376 }
377 #endif /* end ifdef MOCK_BLE */
378
379 } // namespace nearby
380