blob: 0b1237f6957a61e6cfc67d309941f22e49888d45 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "chre/core/ble_request_manager.h"
#include "chre/core/event_loop_manager.h"
#include "chre/platform/fatal_error.h"
#include "chre/platform/log.h"
#include "chre/util/fixed_size_vector.h"
#include "chre/util/nested_data_ptr.h"
#include "chre/util/system/ble_util.h"
#include "chre/util/system/event_callbacks.h"
namespace chre {
void BleRequestManager::init() {
mPlatformBle.init();
}
uint32_t BleRequestManager::getCapabilities() {
return mPlatformBle.getCapabilities();
}
uint32_t BleRequestManager::getFilterCapabilities() {
return mPlatformBle.getFilterCapabilities();
}
void BleRequestManager::handleExistingRequest(uint16_t instanceId,
bool *hasExistingRequest,
size_t *requestIndex) {
const BleRequest *foundRequest =
mRequests.findRequest(instanceId, requestIndex);
*hasExistingRequest = (foundRequest != nullptr);
if (foundRequest != nullptr &&
foundRequest->getRequestStatus() != RequestStatus::APPLIED) {
handleAsyncResult(instanceId, foundRequest->isEnabled(),
false /* success */, CHRE_ERROR_OBSOLETE_REQUEST,
foundRequest->getCookie(), true /* forceUnregister */);
}
}
bool BleRequestManager::compliesWithBleSetting(uint16_t instanceId,
bool enabled,
bool hasExistingRequest,
size_t requestIndex,
const void *cookie) {
bool success = true;
if (enabled && !bleSettingEnabled()) {
success = false;
handleAsyncResult(instanceId, enabled, false /* success */,
CHRE_ERROR_FUNCTION_DISABLED, cookie);
if (hasExistingRequest) {
bool requestChanged = false;
mRequests.removeRequest(requestIndex, &requestChanged);
}
}
return success;
}
bool BleRequestManager::updateRequests(BleRequest &&request,
bool hasExistingRequest,
bool *requestChanged,
size_t *requestIndex) {
bool success = true;
if (hasExistingRequest) {
mRequests.updateRequest(*requestIndex, std::move(request), requestChanged);
} else if (request.isEnabled()) {
success =
mRequests.addRequest(std::move(request), requestIndex, requestChanged);
} else {
// Already disabled requests shouldn't result in work for the PAL.
*requestChanged = false;
*requestIndex = mRequests.getRequests().size();
}
return success;
}
bool BleRequestManager::startScanAsync(
Nanoapp *nanoapp, chreBleScanMode mode, uint32_t reportDelayMs,
const struct chreBleScanFilterV1_9 *filter, const void *cookie) {
CHRE_ASSERT(nanoapp);
BleRequest request(nanoapp->getInstanceId(), true /* enable */, mode,
reportDelayMs, filter, cookie);
return configure(std::move(request));
}
bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp, const void *cookie) {
CHRE_ASSERT(nanoapp);
BleRequest request(nanoapp->getInstanceId(), false /* enable */, cookie);
return configure(std::move(request));
}
uint32_t BleRequestManager::disableActiveScan(const Nanoapp *nanoapp) {
CHRE_ASSERT(nanoapp);
size_t requestIndex;
const BleRequest *foundRequest =
mRequests.findRequest(nanoapp->getInstanceId(), &requestIndex);
if (foundRequest == nullptr || !foundRequest->isEnabled()) {
// No active request found.
return 0;
}
BleRequest request(nanoapp->getInstanceId(), false /* enable */,
nullptr /* cookie */);
configure(std::move(request));
return 1;
}
#ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
bool BleRequestManager::readRssiAsync(Nanoapp *nanoapp,
uint16_t connectionHandle,
const void *cookie) {
CHRE_ASSERT(nanoapp);
if (mPendingRssiRequests.full()) {
LOG_OOM();
return false;
}
if (mPendingRssiRequests.empty()) {
// no previous request existed, so issue this one immediately to get
// an early exit if we get a failure
auto status = readRssi(connectionHandle);
if (status != CHRE_ERROR_NONE) {
return false;
}
}
// it's pending, so report the result asynchronously
mPendingRssiRequests.push(
BleReadRssiRequest{nanoapp->getInstanceId(), connectionHandle, cookie});
return true;
}
#endif
bool BleRequestManager::flushAsync(Nanoapp *nanoapp, const void *cookie) {
CHRE_ASSERT(nanoapp);
bool supportsFlush =
getCapabilities() & CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING;
if (!supportsFlush) {
return false;
}
bool success = false;
const BleRequest *foundRequest =
mRequests.findRequest(nanoapp->getInstanceId(), nullptr);
if (foundRequest == nullptr) {
LOGE("Nanoapp with instance ID: %" PRIu16
" does not have an existing BLE request and cannot flush",
nanoapp->getInstanceId());
} else if (mFlushRequestQueue.full()) {
LOG_OOM();
} else {
mFlushRequestQueue.emplace(nanoapp->getInstanceId(), cookie);
success = processFlushRequests();
}
return success;
}
void BleRequestManager::addBleRequestLog(uint32_t instanceId, bool enabled,
size_t requestIndex,
bool compliesWithBleSetting) {
BleRequestLog log(SystemTime::getMonotonicTime(), instanceId, enabled,
compliesWithBleSetting);
if (enabled) {
if (instanceId == CHRE_INSTANCE_ID) {
log.populateRequestData(mRequests.getCurrentMaximalRequest());
} else if (compliesWithBleSetting) {
log.populateRequestData(mRequests.getRequests()[requestIndex]);
}
}
mBleRequestLogs.kick_push(log);
}
bool BleRequestManager::configure(BleRequest &&request) {
bool success = validateParams(request);
if (success) {
bool requestChanged = false;
size_t requestIndex = 0;
bool hasExistingRequest = false;
uint16_t instanceId = request.getInstanceId();
uint8_t enabled = request.isEnabled();
handleExistingRequest(instanceId, &hasExistingRequest, &requestIndex);
bool compliant =
compliesWithBleSetting(instanceId, enabled, hasExistingRequest,
requestIndex, request.getCookie());
if (compliant) {
success = updateRequests(std::move(request), hasExistingRequest,
&requestChanged, &requestIndex);
if (success) {
if (!mPlatformRequestInProgress) {
if (!requestChanged) {
handleAsyncResult(instanceId, enabled, true /* success */,
CHRE_ERROR_NONE, request.getCookie());
if (requestIndex < mRequests.getRequests().size()) {
mRequests.getMutableRequests()[requestIndex].setRequestStatus(
RequestStatus::APPLIED);
}
} else {
success = controlPlatform();
if (!success) {
handleNanoappEventRegistration(instanceId, enabled,
false /* success */,
true /* forceUnregister */);
mRequests.removeRequest(requestIndex, &requestChanged);
}
}
}
}
}
if (success) {
addBleRequestLog(instanceId, enabled, requestIndex, compliant);
}
}
return success;
}
bool BleRequestManager::controlPlatform() {
bool success = false;
const BleRequest &maxRequest = mRequests.getCurrentMaximalRequest();
bool enable = bleSettingEnabled() && maxRequest.isEnabled();
if (enable) {
chreBleScanFilterV1_9 filter = maxRequest.getScanFilter();
success = mPlatformBle.startScanAsync(
maxRequest.getMode(), maxRequest.getReportDelayMs(), &filter);
mPendingPlatformRequest = BleRequest(
0 /* instanceId */, enable, maxRequest.getMode(),
maxRequest.getReportDelayMs(), &filter, nullptr /* cookie */);
} else {
success = mPlatformBle.stopScanAsync();
mPendingPlatformRequest =
BleRequest(0 /* instanceId */, enable, nullptr /* cookie */);
}
if (success) {
for (BleRequest &req : mRequests.getMutableRequests()) {
if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
req.setRequestStatus(RequestStatus::PENDING_RESP);
}
}
mPlatformRequestInProgress = true;
}
return success;
}
void BleRequestManager::handleFreeAdvertisingEvent(
struct chreBleAdvertisementEvent *event) {
mPlatformBle.releaseAdvertisingEvent(event);
}
void BleRequestManager::freeAdvertisingEventCallback(uint16_t /* eventType */,
void *eventData) {
auto event = static_cast<chreBleAdvertisementEvent *>(eventData);
EventLoopManagerSingleton::get()
->getBleRequestManager()
.handleFreeAdvertisingEvent(event);
}
void BleRequestManager::handleAdvertisementEvent(
struct chreBleAdvertisementEvent *event) {
for (uint16_t i = 0; i < event->numReports; i++) {
populateLegacyAdvertisingReportFields(
const_cast<chreBleAdvertisingReport &>(event->reports[i]));
}
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
CHRE_EVENT_BLE_ADVERTISEMENT, event, freeAdvertisingEventCallback);
}
void BleRequestManager::handlePlatformChange(bool enable, uint8_t errorCode) {
auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
bool enableCb = NestedDataPtr<bool>(data);
uint8_t errorCodeCb = NestedDataPtr<uint8_t>(extraData);
EventLoopManagerSingleton::get()
->getBleRequestManager()
.handlePlatformChangeSync(enableCb, errorCodeCb);
};
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::BleScanResponse, NestedDataPtr<bool>(enable),
callback, NestedDataPtr<uint8_t>(errorCode));
}
void BleRequestManager::handlePlatformChangeSync(bool enable,
uint8_t errorCode) {
bool success = (errorCode == CHRE_ERROR_NONE);
// Requests to disable BLE scans should always succeed
if (!mPendingPlatformRequest.isEnabled() && enable) {
errorCode = CHRE_ERROR;
success = false;
CHRE_ASSERT_LOG(false, "Unable to stop BLE scan");
}
mPlatformRequestInProgress = false;
for (BleRequest &req : mRequests.getMutableRequests()) {
if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
errorCode, req.getCookie());
if (success) {
req.setRequestStatus(RequestStatus::APPLIED);
}
}
}
if (!success) {
mRequests.removeRequests(RequestStatus::PENDING_RESP);
} else {
// No need to waste memory for requests that have no effect on the overall
// maximal request.
mRequests.removeDisabledRequests();
mActivePlatformRequest = std::move(mPendingPlatformRequest);
}
if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) {
dispatchPendingRequests();
} else if (!success && mResyncPending) {
updatePlatformRequest(true /* forceUpdate */);
}
if (!mPlatformRequestInProgress && mSettingChangePending) {
updatePlatformRequest();
}
mResyncPending = false;
mSettingChangePending = false;
}
void BleRequestManager::dispatchPendingRequests() {
uint8_t errorCode = CHRE_ERROR_NONE;
if (!bleSettingEnabled() && mRequests.isMaximalRequestEnabled()) {
errorCode = CHRE_ERROR_FUNCTION_DISABLED;
} else if (!controlPlatform()) {
errorCode = CHRE_ERROR;
}
if (errorCode != CHRE_ERROR_NONE) {
for (const BleRequest &req : mRequests.getRequests()) {
if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
handleAsyncResult(req.getInstanceId(), req.isEnabled(),
false /* success */, errorCode, req.getCookie());
}
}
mRequests.removeRequests(RequestStatus::PENDING_REQ);
}
}
void BleRequestManager::handleAsyncResult(uint16_t instanceId, bool enabled,
bool success, uint8_t errorCode,
const void *cookie,
bool forceUnregister) {
uint8_t requestType = enabled ? CHRE_BLE_REQUEST_TYPE_START_SCAN
: CHRE_BLE_REQUEST_TYPE_STOP_SCAN;
postAsyncResultEventFatal(instanceId, requestType, success, errorCode,
cookie);
handleNanoappEventRegistration(instanceId, enabled, success, forceUnregister);
}
void BleRequestManager::handleNanoappEventRegistration(uint16_t instanceId,
bool enabled,
bool success,
bool forceUnregister) {
Nanoapp *nanoapp =
EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
instanceId);
if (nanoapp != nullptr) {
if (success && enabled) {
nanoapp->registerForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
} else if (!enabled || forceUnregister) {
nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
}
}
}
void BleRequestManager::handleRequestStateResyncCallback() {
auto callback = [](uint16_t /* eventType */, void * /* eventData */,
void * /* extraData */) {
EventLoopManagerSingleton::get()
->getBleRequestManager()
.handleRequestStateResyncCallbackSync();
};
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::BleRequestResyncEvent, nullptr /* data */, callback);
}
void BleRequestManager::handleRequestStateResyncCallbackSync() {
if (mPlatformRequestInProgress) {
mResyncPending = true;
} else {
updatePlatformRequest(true /* forceUpdate */);
}
}
#ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
void BleRequestManager::handleReadRssi(uint8_t errorCode,
uint16_t connectionHandle, int8_t rssi) {
struct readRssiResponse {
uint8_t errorCode;
int8_t rssi;
uint16_t connectionHandle;
};
auto callback = [](uint16_t /* eventType */, void *eventData,
void * /* extraData */) {
readRssiResponse response = NestedDataPtr<readRssiResponse>(eventData);
EventLoopManagerSingleton::get()->getBleRequestManager().handleReadRssiSync(
response.errorCode, response.connectionHandle, response.rssi);
};
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::BleReadRssiEvent,
NestedDataPtr<readRssiResponse>(
readRssiResponse{errorCode, rssi, connectionHandle}),
callback);
}
void BleRequestManager::handleReadRssiSync(uint8_t errorCode,
uint16_t connectionHandle,
int8_t rssi) {
if (mPendingRssiRequests.empty()) {
FATAL_ERROR(
"Got unexpected handleReadRssi event without outstanding request");
}
if (mPendingRssiRequests.front().connectionHandle != connectionHandle) {
FATAL_ERROR(
"Got readRssi event for mismatched connection handle (%d != %d)",
mPendingRssiRequests.front().connectionHandle, connectionHandle);
}
resolvePendingRssiRequest(errorCode, rssi);
dispatchNextRssiRequestIfAny();
}
void BleRequestManager::resolvePendingRssiRequest(uint8_t errorCode,
int8_t rssi) {
auto event = memoryAlloc<chreBleReadRssiEvent>();
if (event == nullptr) {
FATAL_ERROR("Failed to alloc BLE async result");
}
event->result.cookie = mPendingRssiRequests.front().cookie;
event->result.success = (errorCode == CHRE_ERROR_NONE);
event->result.requestType = CHRE_BLE_REQUEST_TYPE_READ_RSSI;
event->result.errorCode = errorCode;
event->result.reserved = 0;
event->connectionHandle = mPendingRssiRequests.front().connectionHandle;
event->rssi = rssi;
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
CHRE_EVENT_BLE_RSSI_READ, event, freeEventDataCallback,
mPendingRssiRequests.front().instanceId);
mPendingRssiRequests.pop();
}
void BleRequestManager::dispatchNextRssiRequestIfAny() {
while (!mPendingRssiRequests.empty()) {
auto req = mPendingRssiRequests.front();
auto status = readRssi(req.connectionHandle);
if (status == CHRE_ERROR_NONE) {
// control flow resumes in the handleReadRssi() callback, on completion
return;
}
resolvePendingRssiRequest(status, 0x7F /* failure RSSI from BT spec */);
}
}
uint8_t BleRequestManager::readRssi(uint16_t connectionHandle) {
if (!bleSettingEnabled()) {
return CHRE_ERROR_FUNCTION_DISABLED;
}
auto success = mPlatformBle.readRssiAsync(connectionHandle);
if (success) {
return CHRE_ERROR_NONE;
} else {
return CHRE_ERROR;
}
}
#endif
void BleRequestManager::handleFlushComplete(uint8_t errorCode) {
if (mFlushRequestTimerHandle != CHRE_TIMER_INVALID) {
EventLoopManagerSingleton::get()->cancelDelayedCallback(
mFlushRequestTimerHandle);
mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
}
handleFlushCompleteInternal(errorCode);
}
void BleRequestManager::handleFlushCompleteTimeout() {
mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
handleFlushCompleteInternal(CHRE_ERROR_TIMEOUT);
}
bool BleRequestManager::getScanStatus(struct chreBleScanStatus * /* status */) {
// TODO(b/266820139): Implement this
return false;
}
void BleRequestManager::onSettingChanged(Setting setting, bool /* state */) {
if (setting == Setting::BLE_AVAILABLE) {
if (mPlatformRequestInProgress) {
mSettingChangePending = true;
} else {
updatePlatformRequest();
}
}
}
void BleRequestManager::updatePlatformRequest(bool forceUpdate) {
bool desiredPlatformState =
bleSettingEnabled() && mRequests.isMaximalRequestEnabled();
bool updatePlatform = (forceUpdate || (desiredPlatformState !=
mActivePlatformRequest.isEnabled()));
if (updatePlatform) {
if (controlPlatform()) {
addBleRequestLog(CHRE_INSTANCE_ID, desiredPlatformState,
mRequests.getRequests().size(),
true /* compliesWithBleSetting */);
} else {
FATAL_ERROR("Failed to send update BLE platform request");
}
}
}
void BleRequestManager::handleFlushCompleteInternal(uint8_t errorCode) {
auto callback = [](uint16_t /* type */, void *data, void * /* extraData */) {
uint8_t cbErrorCode = NestedDataPtr<uint8_t>(data);
EventLoopManagerSingleton::get()
->getBleRequestManager()
.handleFlushCompleteSync(cbErrorCode);
};
if (!EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::BleFlushComplete,
NestedDataPtr<uint8_t>(errorCode), callback)) {
FATAL_ERROR("Unable to defer flush complete callback");
}
}
void BleRequestManager::handleFlushCompleteSync(uint8_t errorCode) {
if (mFlushRequestQueue.empty() || !mFlushRequestQueue.front().isActive) {
LOGE(
"handleFlushCompleteSync was called, but there is no active flush "
"request");
return;
}
FlushRequest &flushRequest = mFlushRequestQueue.front();
sendFlushCompleteEventOrDie(flushRequest, errorCode);
mFlushRequestQueue.pop();
processFlushRequests();
}
uint8_t BleRequestManager::doFlushRequest() {
CHRE_ASSERT(!mFlushRequestQueue.empty());
FlushRequest &flushRequest = mFlushRequestQueue.front();
if (flushRequest.isActive) {
return CHRE_ERROR_NONE;
}
Nanoseconds now = SystemTime::getMonotonicTime();
uint8_t errorCode = CHRE_ERROR_NONE;
if (now >= flushRequest.deadlineTimestamp) {
LOGE("BLE flush request for nanoapp with instance ID: %" PRIu16
" failed: deadline exceeded",
flushRequest.nanoappInstanceId);
errorCode = CHRE_ERROR_TIMEOUT;
} else {
auto timeoutCallback = [](uint16_t /* type */, void * /* data */,
void * /* extraData */) {
EventLoopManagerSingleton::get()
->getBleRequestManager()
.handleFlushCompleteTimeout();
};
mFlushRequestTimerHandle =
EventLoopManagerSingleton::get()->setDelayedCallback(
SystemCallbackType::BleFlushTimeout, nullptr, timeoutCallback,
flushRequest.deadlineTimestamp - now);
if (!mPlatformBle.flushAsync()) {
LOGE("Could not request flush from BLE platform");
errorCode = CHRE_ERROR;
EventLoopManagerSingleton::get()->cancelDelayedCallback(
mFlushRequestTimerHandle);
mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
} else {
flushRequest.isActive = true;
}
}
return errorCode;
}
void BleRequestManager::sendFlushCompleteEventOrDie(
const FlushRequest &flushRequest, uint8_t errorCode) {
chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
if (event == nullptr) {
FATAL_ERROR("Unable to allocate chreAsyncResult");
}
event->requestType = CHRE_BLE_REQUEST_TYPE_FLUSH;
event->success = errorCode == CHRE_ERROR_NONE;
event->errorCode = errorCode;
event->reserved = 0;
event->cookie = flushRequest.cookie;
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
CHRE_EVENT_BLE_FLUSH_COMPLETE, event, freeEventDataCallback,
flushRequest.nanoappInstanceId);
}
bool BleRequestManager::processFlushRequests() {
while (!mFlushRequestQueue.empty()) {
uint8_t errorCode = doFlushRequest();
if (errorCode == CHRE_ERROR_NONE) {
return true;
}
sendFlushCompleteEventOrDie(mFlushRequestQueue.front(), errorCode);
mFlushRequestQueue.pop();
}
return false;
}
// TODO(b/290860901): require data & ~mask == 0
bool BleRequestManager::validateParams(const BleRequest &request) {
bool valid = true;
if (request.isEnabled()) {
for (const chreBleGenericFilter &filter : request.getGenericFilters()) {
if (!isValidAdType(filter.type)) {
valid = false;
break;
}
if (filter.len == 0 || filter.len > CHRE_BLE_DATA_LEN_MAX) {
valid = false;
break;
}
}
}
return valid;
}
void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId,
uint8_t requestType,
bool success,
uint8_t errorCode,
const void *cookie) {
chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
if (event == nullptr) {
FATAL_ERROR("Failed to alloc BLE async result");
} else {
event->requestType = requestType;
event->success = success;
event->errorCode = errorCode;
event->cookie = cookie;
event->reserved = 0;
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
CHRE_EVENT_BLE_ASYNC_RESULT, event, freeEventDataCallback, instanceId);
}
}
bool BleRequestManager::isValidAdType(uint8_t adType) {
return adType == CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
}
bool BleRequestManager::bleSettingEnabled() {
return EventLoopManagerSingleton::get()
->getSettingManager()
.getSettingEnabled(Setting::BLE_AVAILABLE);
}
void BleRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
debugDump.print("\nBLE:\n");
debugDump.print(" Active Platform Request:\n");
mActivePlatformRequest.logStateToBuffer(debugDump,
true /* isPlatformRequest */);
if (mPlatformRequestInProgress) {
debugDump.print(" Pending Platform Request:\n");
mPendingPlatformRequest.logStateToBuffer(debugDump,
true /* isPlatformRequest */);
}
debugDump.print(" Request Multiplexer:\n");
for (const BleRequest &req : mRequests.getRequests()) {
req.logStateToBuffer(debugDump);
}
debugDump.print(" Last %zu valid BLE requests:\n", mBleRequestLogs.size());
static_assert(kNumBleRequestLogs <= INT8_MAX,
"kNumBleRequestLogs must be less than INT8_MAX.");
for (int8_t i = static_cast<int8_t>(mBleRequestLogs.size()) - 1; i >= 0;
i--) {
const auto &log = mBleRequestLogs[static_cast<size_t>(i)];
debugDump.print(" ts=%" PRIu64 " instanceId=%" PRIu32 " %s",
log.timestamp.toRawNanoseconds(), log.instanceId,
log.enable ? "enable" : "disable\n");
if (log.enable && log.compliesWithBleSetting) {
debugDump.print(
" mode=%" PRIu8 " reportDelayMs=%" PRIu32 " rssiThreshold=%" PRId8
" scanCount=%" PRIu8 " broadcasterAddressCount=%" PRIu8 "\n",
static_cast<uint8_t>(log.mode), log.reportDelayMs, log.rssiThreshold,
log.scanFilterCount, log.broadcasterFilterCount);
} else if (log.enable) {
debugDump.print(" request did not comply with BLE setting\n");
}
}
}
} // namespace chre