diff options
Diffstat (limited to 'core/ble_request_manager.cc')
-rw-r--r-- | core/ble_request_manager.cc | 270 |
1 files changed, 208 insertions, 62 deletions
diff --git a/core/ble_request_manager.cc b/core/ble_request_manager.cc index 469b357a..0b1237f6 100644 --- a/core/ble_request_manager.cc +++ b/core/ble_request_manager.cc @@ -19,7 +19,9 @@ #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 { @@ -46,19 +48,20 @@ void BleRequestManager::handleExistingRequest(uint16_t instanceId, foundRequest->getRequestStatus() != RequestStatus::APPLIED) { handleAsyncResult(instanceId, foundRequest->isEnabled(), false /* success */, CHRE_ERROR_OBSOLETE_REQUEST, - true /* forceUnregister */); + foundRequest->getCookie(), true /* forceUnregister */); } } bool BleRequestManager::compliesWithBleSetting(uint16_t instanceId, bool enabled, bool hasExistingRequest, - size_t requestIndex) { + size_t requestIndex, + const void *cookie) { bool success = true; if (enabled && !bleSettingEnabled()) { success = false; handleAsyncResult(instanceId, enabled, false /* success */, - CHRE_ERROR_FUNCTION_DISABLED); + CHRE_ERROR_FUNCTION_DISABLED, cookie); if (hasExistingRequest) { bool requestChanged = false; mRequests.removeRequest(requestIndex, &requestChanged); @@ -85,18 +88,18 @@ bool BleRequestManager::updateRequests(BleRequest &&request, return success; } -bool BleRequestManager::startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode, - uint32_t reportDelayMs, - const struct chreBleScanFilter *filter) { +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, mode, reportDelayMs, - filter); + BleRequest request(nanoapp->getInstanceId(), true /* enable */, mode, + reportDelayMs, filter, cookie); return configure(std::move(request)); } -bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp) { +bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp, const void *cookie) { CHRE_ASSERT(nanoapp); - BleRequest request(nanoapp->getInstanceId(), false /* enable */); + BleRequest request(nanoapp->getInstanceId(), false /* enable */, cookie); return configure(std::move(request)); } @@ -112,7 +115,8 @@ uint32_t BleRequestManager::disableActiveScan(const Nanoapp *nanoapp) { return 0; } - BleRequest request(nanoapp->getInstanceId(), false /* enable */); + BleRequest request(nanoapp->getInstanceId(), false /* enable */, + nullptr /* cookie */); configure(std::move(request)); return 1; } @@ -141,6 +145,32 @@ bool BleRequestManager::readRssiAsync(Nanoapp *nanoapp, } #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) { @@ -165,8 +195,9 @@ bool BleRequestManager::configure(BleRequest &&request) { uint16_t instanceId = request.getInstanceId(); uint8_t enabled = request.isEnabled(); handleExistingRequest(instanceId, &hasExistingRequest, &requestIndex); - bool compliant = compliesWithBleSetting(instanceId, enabled, - hasExistingRequest, requestIndex); + bool compliant = + compliesWithBleSetting(instanceId, enabled, hasExistingRequest, + requestIndex, request.getCookie()); if (compliant) { success = updateRequests(std::move(request), hasExistingRequest, &requestChanged, &requestIndex); @@ -174,7 +205,7 @@ bool BleRequestManager::configure(BleRequest &&request) { if (!mPlatformRequestInProgress) { if (!requestChanged) { handleAsyncResult(instanceId, enabled, true /* success */, - CHRE_ERROR_NONE); + CHRE_ERROR_NONE, request.getCookie()); if (requestIndex < mRequests.getRequests().size()) { mRequests.getMutableRequests()[requestIndex].setRequestStatus( RequestStatus::APPLIED); @@ -202,17 +233,20 @@ bool BleRequestManager::controlPlatform() { bool success = false; const BleRequest &maxRequest = mRequests.getCurrentMaximalRequest(); bool enable = bleSettingEnabled() && maxRequest.isEnabled(); + if (enable) { - chreBleScanFilter filter = maxRequest.getScanFilter(); + chreBleScanFilterV1_9 filter = maxRequest.getScanFilter(); success = mPlatformBle.startScanAsync( maxRequest.getMode(), maxRequest.getReportDelayMs(), &filter); - mPendingPlatformRequest = - BleRequest(0, enable, maxRequest.getMode(), - maxRequest.getReportDelayMs(), &filter); + mPendingPlatformRequest = BleRequest( + 0 /* instanceId */, enable, maxRequest.getMode(), + maxRequest.getReportDelayMs(), &filter, nullptr /* cookie */); } else { success = mPlatformBle.stopScanAsync(); - mPendingPlatformRequest = BleRequest(0, enable); + mPendingPlatformRequest = + BleRequest(0 /* instanceId */, enable, nullptr /* cookie */); } + if (success) { for (BleRequest &req : mRequests.getMutableRequests()) { if (req.getRequestStatus() == RequestStatus::PENDING_REQ) { @@ -240,17 +274,21 @@ void BleRequestManager::freeAdvertisingEventCallback(uint16_t /* eventType */, 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 enable = NestedDataPtr<bool>(data); - uint8_t errorCode = NestedDataPtr<uint8_t>(extraData); + bool enableCb = NestedDataPtr<bool>(data); + uint8_t errorCodeCb = NestedDataPtr<uint8_t>(extraData); EventLoopManagerSingleton::get() ->getBleRequestManager() - .handlePlatformChangeSync(enable, errorCode); + .handlePlatformChangeSync(enableCb, errorCodeCb); }; EventLoopManagerSingleton::get()->deferCallback( @@ -272,7 +310,7 @@ void BleRequestManager::handlePlatformChangeSync(bool enable, for (BleRequest &req : mRequests.getMutableRequests()) { if (req.getRequestStatus() == RequestStatus::PENDING_RESP) { handleAsyncResult(req.getInstanceId(), req.isEnabled(), success, - errorCode); + errorCode, req.getCookie()); if (success) { req.setRequestStatus(RequestStatus::APPLIED); } @@ -288,56 +326,46 @@ void BleRequestManager::handlePlatformChangeSync(bool enable, mActivePlatformRequest = std::move(mPendingPlatformRequest); } - dispatchPendingRequests(); - - // Only clear mResyncPending if the request succeeded or after all pending - // requests are dispatched and a resync request can be issued with only the - // requests that were previously applied. - if (mResyncPending) { - if (success) { - mResyncPending = false; - } else if (!success && !mPlatformRequestInProgress) { - mResyncPending = false; - updatePlatformRequest(true /* forceUpdate */); - } + if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) { + dispatchPendingRequests(); + } else if (!success && mResyncPending) { + updatePlatformRequest(true /* forceUpdate */); } - // Finish dispatching pending requests before processing the setting change - // request to ensure nanoapps receive CHRE_ERROR_FUNCTION_DISABLED responses. - // If both a resync and a setting change are pending, prioritize the resync. - // If the resync successfully completes, the PAL will be in the correct state - // and updatePlatformRequest will not begin a new request. - if (mSettingChangePending && !mPlatformRequestInProgress) { + + if (!mPlatformRequestInProgress && mSettingChangePending) { updatePlatformRequest(); - mSettingChangePending = false; } + + mResyncPending = false; + mSettingChangePending = false; } void BleRequestManager::dispatchPendingRequests() { - if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) { - 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); - } + 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); } + 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); + postAsyncResultEventFatal(instanceId, requestType, success, errorCode, + cookie); handleNanoappEventRegistration(instanceId, enabled, success, forceUnregister); } @@ -464,6 +492,21 @@ uint8_t BleRequestManager::readRssi(uint16_t connectionHandle) { } #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; @@ -496,6 +539,106 @@ void BleRequestManager::updatePlatformRequest(bool forceUpdate) { } } +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; @@ -517,7 +660,8 @@ bool BleRequestManager::validateParams(const BleRequest &request) { void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId, uint8_t requestType, bool success, - uint8_t errorCode) { + uint8_t errorCode, + const void *cookie) { chreAsyncResult *event = memoryAlloc<chreAsyncResult>(); if (event == nullptr) { FATAL_ERROR("Failed to alloc BLE async result"); @@ -525,6 +669,7 @@ void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId, event->requestType = requestType; event->success = success; event->errorCode = errorCode; + event->cookie = cookie; event->reserved = 0; EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( @@ -566,10 +711,11 @@ void BleRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const { 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 "\n", - static_cast<uint8_t>(log.mode), log.reportDelayMs, - log.rssiThreshold, log.scanFilterCount); + 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"); } |