xref: /aosp_15_r20/system/chre/apps/nearby/location/lbs/contexthub/nanoapps/nearby/ble_scanner.cc (revision 84e339476a462649f82315436d70fd732297a399)
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