• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "chre/core/ble_request_manager.h"
18 
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/fatal_error.h"
21 #include "chre/platform/log.h"
22 #include "chre/util/nested_data_ptr.h"
23 #include "chre/util/system/event_callbacks.h"
24 
25 namespace chre {
26 
init()27 void BleRequestManager::init() {
28   mPlatformBle.init();
29 }
30 
getCapabilities()31 uint32_t BleRequestManager::getCapabilities() {
32   return mPlatformBle.getCapabilities();
33 }
34 
getFilterCapabilities()35 uint32_t BleRequestManager::getFilterCapabilities() {
36   return mPlatformBle.getFilterCapabilities();
37 }
38 
handleExistingRequest(uint16_t instanceId,bool * hasExistingRequest,size_t * requestIndex)39 void BleRequestManager::handleExistingRequest(uint16_t instanceId,
40                                               bool *hasExistingRequest,
41                                               size_t *requestIndex) {
42   const BleRequest *foundRequest =
43       mRequests.findRequest(instanceId, requestIndex);
44   *hasExistingRequest = (foundRequest != nullptr);
45   if (foundRequest != nullptr &&
46       foundRequest->getRequestStatus() != RequestStatus::APPLIED) {
47     handleAsyncResult(instanceId, foundRequest->isEnabled(),
48                       false /* success */, CHRE_ERROR_OBSOLETE_REQUEST,
49                       true /* forceUnregister */);
50   }
51 }
52 
compliesWithBleSetting(uint16_t instanceId,bool enabled,bool hasExistingRequest,size_t requestIndex)53 bool BleRequestManager::compliesWithBleSetting(uint16_t instanceId,
54                                                bool enabled,
55                                                bool hasExistingRequest,
56                                                size_t requestIndex) {
57   bool success = true;
58   if (enabled && !bleSettingEnabled()) {
59     success = false;
60     handleAsyncResult(instanceId, enabled, false /* success */,
61                       CHRE_ERROR_FUNCTION_DISABLED);
62     if (hasExistingRequest) {
63       bool requestChanged = false;
64       mRequests.removeRequest(requestIndex, &requestChanged);
65     }
66   }
67   return success;
68 }
69 
updateRequests(BleRequest && request,bool hasExistingRequest,bool * requestChanged,size_t * requestIndex)70 bool BleRequestManager::updateRequests(BleRequest &&request,
71                                        bool hasExistingRequest,
72                                        bool *requestChanged,
73                                        size_t *requestIndex) {
74   bool success = true;
75   if (hasExistingRequest) {
76     mRequests.updateRequest(*requestIndex, std::move(request), requestChanged);
77   } else if (request.isEnabled()) {
78     success =
79         mRequests.addRequest(std::move(request), requestIndex, requestChanged);
80   } else {
81     // Already disabled requests shouldn't result in work for the PAL.
82     *requestChanged = false;
83     *requestIndex = mRequests.getRequests().size();
84   }
85   return success;
86 }
87 
startScanAsync(Nanoapp * nanoapp,chreBleScanMode mode,uint32_t reportDelayMs,const struct chreBleScanFilter * filter)88 bool BleRequestManager::startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode,
89                                        uint32_t reportDelayMs,
90                                        const struct chreBleScanFilter *filter) {
91   CHRE_ASSERT(nanoapp);
92   BleRequest request(nanoapp->getInstanceId(), true, mode, reportDelayMs,
93                      filter);
94   return configure(std::move(request));
95 }
96 
stopScanAsync(Nanoapp * nanoapp)97 bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp) {
98   CHRE_ASSERT(nanoapp);
99   BleRequest request(nanoapp->getInstanceId(), false /* enable */);
100   return configure(std::move(request));
101 }
102 
disableActiveScan(const Nanoapp * nanoapp)103 uint32_t BleRequestManager::disableActiveScan(const Nanoapp *nanoapp) {
104   CHRE_ASSERT(nanoapp);
105 
106   size_t requestIndex;
107   const BleRequest *foundRequest =
108       mRequests.findRequest(nanoapp->getInstanceId(), &requestIndex);
109 
110   if (foundRequest == nullptr || !foundRequest->isEnabled()) {
111     // No active request found.
112     return 0;
113   }
114 
115   BleRequest request(nanoapp->getInstanceId(), false /* enable */);
116   configure(std::move(request));
117   return 1;
118 }
119 
120 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
readRssiAsync(Nanoapp * nanoapp,uint16_t connectionHandle,const void * cookie)121 bool BleRequestManager::readRssiAsync(Nanoapp *nanoapp,
122                                       uint16_t connectionHandle,
123                                       const void *cookie) {
124   CHRE_ASSERT(nanoapp);
125   if (mPendingRssiRequests.full()) {
126     LOG_OOM();
127     return false;
128   }
129   if (mPendingRssiRequests.empty()) {
130     // no previous request existed, so issue this one immediately to get
131     // an early exit if we get a failure
132     auto status = readRssi(connectionHandle);
133     if (status != CHRE_ERROR_NONE) {
134       return false;
135     }
136   }
137   // it's pending, so report the result asynchronously
138   mPendingRssiRequests.push(
139       BleReadRssiRequest{nanoapp->getInstanceId(), connectionHandle, cookie});
140   return true;
141 }
142 #endif
143 
addBleRequestLog(uint32_t instanceId,bool enabled,size_t requestIndex,bool compliesWithBleSetting)144 void BleRequestManager::addBleRequestLog(uint32_t instanceId, bool enabled,
145                                          size_t requestIndex,
146                                          bool compliesWithBleSetting) {
147   BleRequestLog log(SystemTime::getMonotonicTime(), instanceId, enabled,
148                     compliesWithBleSetting);
149   if (enabled) {
150     if (instanceId == CHRE_INSTANCE_ID) {
151       log.populateRequestData(mRequests.getCurrentMaximalRequest());
152     } else if (compliesWithBleSetting) {
153       log.populateRequestData(mRequests.getRequests()[requestIndex]);
154     }
155   }
156   mBleRequestLogs.kick_push(log);
157 }
158 
configure(BleRequest && request)159 bool BleRequestManager::configure(BleRequest &&request) {
160   bool success = validateParams(request);
161   if (success) {
162     bool requestChanged = false;
163     size_t requestIndex = 0;
164     bool hasExistingRequest = false;
165     uint16_t instanceId = request.getInstanceId();
166     uint8_t enabled = request.isEnabled();
167     handleExistingRequest(instanceId, &hasExistingRequest, &requestIndex);
168     bool compliant = compliesWithBleSetting(instanceId, enabled,
169                                             hasExistingRequest, requestIndex);
170     if (compliant) {
171       success = updateRequests(std::move(request), hasExistingRequest,
172                                &requestChanged, &requestIndex);
173       if (success) {
174         if (!mPlatformRequestInProgress) {
175           if (!requestChanged) {
176             handleAsyncResult(instanceId, enabled, true /* success */,
177                               CHRE_ERROR_NONE);
178             if (requestIndex < mRequests.getRequests().size()) {
179               mRequests.getMutableRequests()[requestIndex].setRequestStatus(
180                   RequestStatus::APPLIED);
181             }
182           } else {
183             success = controlPlatform();
184             if (!success) {
185               handleNanoappEventRegistration(instanceId, enabled,
186                                              false /* success */,
187                                              true /* forceUnregister */);
188               mRequests.removeRequest(requestIndex, &requestChanged);
189             }
190           }
191         }
192       }
193     }
194     if (success) {
195       addBleRequestLog(instanceId, enabled, requestIndex, compliant);
196     }
197   }
198   return success;
199 }
200 
controlPlatform()201 bool BleRequestManager::controlPlatform() {
202   bool success = false;
203   const BleRequest &maxRequest = mRequests.getCurrentMaximalRequest();
204   bool enable = bleSettingEnabled() && maxRequest.isEnabled();
205   if (enable) {
206     chreBleScanFilter filter = maxRequest.getScanFilter();
207     success = mPlatformBle.startScanAsync(
208         maxRequest.getMode(), maxRequest.getReportDelayMs(), &filter);
209     mPendingPlatformRequest =
210         BleRequest(0, enable, maxRequest.getMode(),
211                    maxRequest.getReportDelayMs(), &filter);
212   } else {
213     success = mPlatformBle.stopScanAsync();
214     mPendingPlatformRequest = BleRequest(0, enable);
215   }
216   if (success) {
217     for (BleRequest &req : mRequests.getMutableRequests()) {
218       if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
219         req.setRequestStatus(RequestStatus::PENDING_RESP);
220       }
221     }
222     mPlatformRequestInProgress = true;
223   }
224 
225   return success;
226 }
227 
handleFreeAdvertisingEvent(struct chreBleAdvertisementEvent * event)228 void BleRequestManager::handleFreeAdvertisingEvent(
229     struct chreBleAdvertisementEvent *event) {
230   mPlatformBle.releaseAdvertisingEvent(event);
231 }
232 
freeAdvertisingEventCallback(uint16_t,void * eventData)233 void BleRequestManager::freeAdvertisingEventCallback(uint16_t /* eventType */,
234                                                      void *eventData) {
235   auto event = static_cast<chreBleAdvertisementEvent *>(eventData);
236   EventLoopManagerSingleton::get()
237       ->getBleRequestManager()
238       .handleFreeAdvertisingEvent(event);
239 }
240 
handleAdvertisementEvent(struct chreBleAdvertisementEvent * event)241 void BleRequestManager::handleAdvertisementEvent(
242     struct chreBleAdvertisementEvent *event) {
243   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
244       CHRE_EVENT_BLE_ADVERTISEMENT, event, freeAdvertisingEventCallback);
245 }
246 
handlePlatformChange(bool enable,uint8_t errorCode)247 void BleRequestManager::handlePlatformChange(bool enable, uint8_t errorCode) {
248   auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
249     bool enable = NestedDataPtr<bool>(data);
250     uint8_t errorCode = NestedDataPtr<uint8_t>(extraData);
251     EventLoopManagerSingleton::get()
252         ->getBleRequestManager()
253         .handlePlatformChangeSync(enable, errorCode);
254   };
255 
256   EventLoopManagerSingleton::get()->deferCallback(
257       SystemCallbackType::BleScanResponse, NestedDataPtr<bool>(enable),
258       callback, NestedDataPtr<uint8_t>(errorCode));
259 }
260 
handlePlatformChangeSync(bool enable,uint8_t errorCode)261 void BleRequestManager::handlePlatformChangeSync(bool enable,
262                                                  uint8_t errorCode) {
263   bool success = (errorCode == CHRE_ERROR_NONE);
264   // Requests to disable BLE scans should always succeed
265   if (!mPendingPlatformRequest.isEnabled() && enable) {
266     errorCode = CHRE_ERROR;
267     success = false;
268     CHRE_ASSERT_LOG(false, "Unable to stop BLE scan");
269   }
270 
271   mPlatformRequestInProgress = false;
272   for (BleRequest &req : mRequests.getMutableRequests()) {
273     if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
274       handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
275                         errorCode);
276       if (success) {
277         req.setRequestStatus(RequestStatus::APPLIED);
278       }
279     }
280   }
281 
282   if (!success) {
283     mRequests.removeRequests(RequestStatus::PENDING_RESP);
284   } else {
285     // No need to waste memory for requests that have no effect on the overall
286     // maximal request.
287     mRequests.removeDisabledRequests();
288     mActivePlatformRequest = std::move(mPendingPlatformRequest);
289   }
290 
291   dispatchPendingRequests();
292 
293   // Only clear mResyncPending if the request succeeded or after all pending
294   // requests are dispatched and a resync request can be issued with only the
295   // requests that were previously applied.
296   if (mResyncPending) {
297     if (success) {
298       mResyncPending = false;
299     } else if (!success && !mPlatformRequestInProgress) {
300       mResyncPending = false;
301       updatePlatformRequest(true /* forceUpdate */);
302     }
303   }
304   // Finish dispatching pending requests before processing the setting change
305   // request to ensure nanoapps receive CHRE_ERROR_FUNCTION_DISABLED responses.
306   // If both a resync and a setting change are pending, prioritize the resync.
307   // If the resync successfully completes, the PAL will be in the correct state
308   // and updatePlatformRequest will not begin a new request.
309   if (mSettingChangePending && !mPlatformRequestInProgress) {
310     updatePlatformRequest();
311     mSettingChangePending = false;
312   }
313 }
314 
dispatchPendingRequests()315 void BleRequestManager::dispatchPendingRequests() {
316   if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) {
317     uint8_t errorCode = CHRE_ERROR_NONE;
318     if (!bleSettingEnabled() && mRequests.isMaximalRequestEnabled()) {
319       errorCode = CHRE_ERROR_FUNCTION_DISABLED;
320     } else if (!controlPlatform()) {
321       errorCode = CHRE_ERROR;
322     }
323     if (errorCode != CHRE_ERROR_NONE) {
324       for (const BleRequest &req : mRequests.getRequests()) {
325         if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
326           handleAsyncResult(req.getInstanceId(), req.isEnabled(),
327                             false /* success */, errorCode);
328         }
329       }
330       mRequests.removeRequests(RequestStatus::PENDING_REQ);
331     }
332   }
333 }
334 
handleAsyncResult(uint16_t instanceId,bool enabled,bool success,uint8_t errorCode,bool forceUnregister)335 void BleRequestManager::handleAsyncResult(uint16_t instanceId, bool enabled,
336                                           bool success, uint8_t errorCode,
337                                           bool forceUnregister) {
338   uint8_t requestType = enabled ? CHRE_BLE_REQUEST_TYPE_START_SCAN
339                                 : CHRE_BLE_REQUEST_TYPE_STOP_SCAN;
340   postAsyncResultEventFatal(instanceId, requestType, success, errorCode);
341   handleNanoappEventRegistration(instanceId, enabled, success, forceUnregister);
342 }
343 
handleNanoappEventRegistration(uint16_t instanceId,bool enabled,bool success,bool forceUnregister)344 void BleRequestManager::handleNanoappEventRegistration(uint16_t instanceId,
345                                                        bool enabled,
346                                                        bool success,
347                                                        bool forceUnregister) {
348   Nanoapp *nanoapp =
349       EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
350           instanceId);
351   if (nanoapp != nullptr) {
352     if (success && enabled) {
353       nanoapp->registerForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
354     } else if (!enabled || forceUnregister) {
355       nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
356     }
357   }
358 }
359 
handleRequestStateResyncCallback()360 void BleRequestManager::handleRequestStateResyncCallback() {
361   auto callback = [](uint16_t /* eventType */, void * /* eventData */,
362                      void * /* extraData */) {
363     EventLoopManagerSingleton::get()
364         ->getBleRequestManager()
365         .handleRequestStateResyncCallbackSync();
366   };
367   EventLoopManagerSingleton::get()->deferCallback(
368       SystemCallbackType::BleRequestResyncEvent, nullptr /* data */, callback);
369 }
370 
handleRequestStateResyncCallbackSync()371 void BleRequestManager::handleRequestStateResyncCallbackSync() {
372   if (mPlatformRequestInProgress) {
373     mResyncPending = true;
374   } else {
375     updatePlatformRequest(true /* forceUpdate */);
376   }
377 }
378 
379 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
handleReadRssi(uint8_t errorCode,uint16_t connectionHandle,int8_t rssi)380 void BleRequestManager::handleReadRssi(uint8_t errorCode,
381                                        uint16_t connectionHandle, int8_t rssi) {
382   struct readRssiResponse {
383     uint8_t errorCode;
384     int8_t rssi;
385     uint16_t connectionHandle;
386   };
387 
388   auto callback = [](uint16_t /* eventType */, void *eventData,
389                      void * /* extraData */) {
390     readRssiResponse response = NestedDataPtr<readRssiResponse>(eventData);
391     EventLoopManagerSingleton::get()->getBleRequestManager().handleReadRssiSync(
392         response.errorCode, response.connectionHandle, response.rssi);
393   };
394 
395   EventLoopManagerSingleton::get()->deferCallback(
396       SystemCallbackType::BleReadRssiEvent,
397       NestedDataPtr<readRssiResponse>(
398           readRssiResponse{errorCode, rssi, connectionHandle}),
399       callback);
400 }
401 
handleReadRssiSync(uint8_t errorCode,uint16_t connectionHandle,int8_t rssi)402 void BleRequestManager::handleReadRssiSync(uint8_t errorCode,
403                                            uint16_t connectionHandle,
404                                            int8_t rssi) {
405   if (mPendingRssiRequests.empty()) {
406     FATAL_ERROR(
407         "Got unexpected handleReadRssi event without outstanding request");
408   }
409 
410   if (mPendingRssiRequests.front().connectionHandle != connectionHandle) {
411     FATAL_ERROR(
412         "Got readRssi event for mismatched connection handle (%d != %d)",
413         mPendingRssiRequests.front().connectionHandle, connectionHandle);
414   }
415 
416   resolvePendingRssiRequest(errorCode, rssi);
417   dispatchNextRssiRequestIfAny();
418 }
419 
resolvePendingRssiRequest(uint8_t errorCode,int8_t rssi)420 void BleRequestManager::resolvePendingRssiRequest(uint8_t errorCode,
421                                                   int8_t rssi) {
422   auto event = memoryAlloc<chreBleReadRssiEvent>();
423   if (event == nullptr) {
424     FATAL_ERROR("Failed to alloc BLE async result");
425   }
426 
427   event->result.cookie = mPendingRssiRequests.front().cookie;
428   event->result.success = (errorCode == CHRE_ERROR_NONE);
429   event->result.requestType = CHRE_BLE_REQUEST_TYPE_READ_RSSI;
430   event->result.errorCode = errorCode;
431   event->result.reserved = 0;
432   event->connectionHandle = mPendingRssiRequests.front().connectionHandle;
433   event->rssi = rssi;
434 
435   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
436       CHRE_EVENT_BLE_RSSI_READ, event, freeEventDataCallback,
437       mPendingRssiRequests.front().instanceId);
438 
439   mPendingRssiRequests.pop();
440 }
441 
dispatchNextRssiRequestIfAny()442 void BleRequestManager::dispatchNextRssiRequestIfAny() {
443   while (!mPendingRssiRequests.empty()) {
444     auto req = mPendingRssiRequests.front();
445     auto status = readRssi(req.connectionHandle);
446     if (status == CHRE_ERROR_NONE) {
447       // control flow resumes in the handleReadRssi() callback, on completion
448       return;
449     }
450     resolvePendingRssiRequest(status, 0x7F /* failure RSSI from BT spec */);
451   }
452 }
453 
readRssi(uint16_t connectionHandle)454 uint8_t BleRequestManager::readRssi(uint16_t connectionHandle) {
455   if (!bleSettingEnabled()) {
456     return CHRE_ERROR_FUNCTION_DISABLED;
457   }
458   auto success = mPlatformBle.readRssiAsync(connectionHandle);
459   if (success) {
460     return CHRE_ERROR_NONE;
461   } else {
462     return CHRE_ERROR;
463   }
464 }
465 #endif
466 
getScanStatus(struct chreBleScanStatus *)467 bool BleRequestManager::getScanStatus(struct chreBleScanStatus * /* status */) {
468   // TODO(b/266820139): Implement this
469   return false;
470 }
471 
onSettingChanged(Setting setting,bool)472 void BleRequestManager::onSettingChanged(Setting setting, bool /* state */) {
473   if (setting == Setting::BLE_AVAILABLE) {
474     if (mPlatformRequestInProgress) {
475       mSettingChangePending = true;
476     } else {
477       updatePlatformRequest();
478     }
479   }
480 }
481 
updatePlatformRequest(bool forceUpdate)482 void BleRequestManager::updatePlatformRequest(bool forceUpdate) {
483   bool desiredPlatformState =
484       bleSettingEnabled() && mRequests.isMaximalRequestEnabled();
485   bool updatePlatform = (forceUpdate || (desiredPlatformState !=
486                                          mActivePlatformRequest.isEnabled()));
487 
488   if (updatePlatform) {
489     if (controlPlatform()) {
490       addBleRequestLog(CHRE_INSTANCE_ID, desiredPlatformState,
491                        mRequests.getRequests().size(),
492                        true /* compliesWithBleSetting */);
493     } else {
494       FATAL_ERROR("Failed to send update BLE platform request");
495     }
496   }
497 }
498 
499 // TODO(b/290860901): require data & ~mask == 0
validateParams(const BleRequest & request)500 bool BleRequestManager::validateParams(const BleRequest &request) {
501   bool valid = true;
502   if (request.isEnabled()) {
503     for (const chreBleGenericFilter &filter : request.getGenericFilters()) {
504       if (!isValidAdType(filter.type)) {
505         valid = false;
506         break;
507       }
508       if (filter.len == 0 || filter.len > CHRE_BLE_DATA_LEN_MAX) {
509         valid = false;
510         break;
511       }
512     }
513   }
514   return valid;
515 }
516 
postAsyncResultEventFatal(uint16_t instanceId,uint8_t requestType,bool success,uint8_t errorCode)517 void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId,
518                                                   uint8_t requestType,
519                                                   bool success,
520                                                   uint8_t errorCode) {
521   chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
522   if (event == nullptr) {
523     FATAL_ERROR("Failed to alloc BLE async result");
524   } else {
525     event->requestType = requestType;
526     event->success = success;
527     event->errorCode = errorCode;
528     event->reserved = 0;
529 
530     EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
531         CHRE_EVENT_BLE_ASYNC_RESULT, event, freeEventDataCallback, instanceId);
532   }
533 }
534 
isValidAdType(uint8_t adType)535 bool BleRequestManager::isValidAdType(uint8_t adType) {
536   return adType == CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
537 }
538 
bleSettingEnabled()539 bool BleRequestManager::bleSettingEnabled() {
540   return EventLoopManagerSingleton::get()
541       ->getSettingManager()
542       .getSettingEnabled(Setting::BLE_AVAILABLE);
543 }
544 
logStateToBuffer(DebugDumpWrapper & debugDump) const545 void BleRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
546   debugDump.print("\nBLE:\n");
547   debugDump.print(" Active Platform Request:\n");
548   mActivePlatformRequest.logStateToBuffer(debugDump,
549                                           true /* isPlatformRequest */);
550   if (mPlatformRequestInProgress) {
551     debugDump.print(" Pending Platform Request:\n");
552     mPendingPlatformRequest.logStateToBuffer(debugDump,
553                                              true /* isPlatformRequest */);
554   }
555   debugDump.print(" Request Multiplexer:\n");
556   for (const BleRequest &req : mRequests.getRequests()) {
557     req.logStateToBuffer(debugDump);
558   }
559   debugDump.print(" Last %zu valid BLE requests:\n", mBleRequestLogs.size());
560   static_assert(kNumBleRequestLogs <= INT8_MAX,
561                 "kNumBleRequestLogs must be less than INT8_MAX.");
562   for (int8_t i = static_cast<int8_t>(mBleRequestLogs.size()) - 1; i >= 0;
563        i--) {
564     const auto &log = mBleRequestLogs[static_cast<size_t>(i)];
565     debugDump.print("  ts=%" PRIu64 " instanceId=%" PRIu32 " %s",
566                     log.timestamp.toRawNanoseconds(), log.instanceId,
567                     log.enable ? "enable" : "disable\n");
568     if (log.enable && log.compliesWithBleSetting) {
569       debugDump.print(" mode=%" PRIu8 " reportDelayMs=%" PRIu32
570                       " rssiThreshold=%" PRId8 " scanCount=%" PRIu8 "\n",
571                       static_cast<uint8_t>(log.mode), log.reportDelayMs,
572                       log.rssiThreshold, log.scanFilterCount);
573     } else if (log.enable) {
574       debugDump.print(" request did not comply with BLE setting\n");
575     }
576   }
577 }
578 
579 }  // namespace chre
580