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