aboutsummaryrefslogtreecommitdiff
path: root/core/ble_request_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'core/ble_request_manager.cc')
-rw-r--r--core/ble_request_manager.cc270
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");
}