681 lines
25 KiB
C++
681 lines
25 KiB
C++
/*
|
|
* Copyright (C) 2016 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 <cinttypes>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
|
|
#include "chre/core/event_loop_manager.h"
|
|
#include "chre/core/settings.h"
|
|
#include "chre/core/wifi_request_manager.h"
|
|
#include "chre/platform/fatal_error.h"
|
|
#include "chre/platform/log.h"
|
|
#include "chre/platform/system_time.h"
|
|
#include "chre/util/nested_data_ptr.h"
|
|
#include "chre/util/system/debug_dump.h"
|
|
#include "chre_api/chre/version.h"
|
|
|
|
namespace chre {
|
|
|
|
WifiRequestManager::WifiRequestManager() {
|
|
// Reserve space for at least one scan monitoring nanoapp. This ensures that
|
|
// the first asynchronous push_back will succeed. Future push_backs will be
|
|
// synchronous and failures will be returned to the client.
|
|
if (!mScanMonitorNanoapps.reserve(1)) {
|
|
FATAL_ERROR_OOM();
|
|
}
|
|
}
|
|
|
|
void WifiRequestManager::init() {
|
|
mPlatformWifi.init();
|
|
}
|
|
|
|
uint32_t WifiRequestManager::getCapabilities() {
|
|
return mPlatformWifi.getCapabilities();
|
|
}
|
|
|
|
bool WifiRequestManager::configureScanMonitor(Nanoapp *nanoapp, bool enable,
|
|
const void *cookie) {
|
|
CHRE_ASSERT(nanoapp);
|
|
|
|
bool success = false;
|
|
uint32_t instanceId = nanoapp->getInstanceId();
|
|
bool hasScanMonitorRequest = nanoappHasScanMonitorRequest(instanceId);
|
|
if (!mPendingScanMonitorRequests.empty()) {
|
|
success = addScanMonitorRequestToQueue(nanoapp, enable, cookie);
|
|
} else if (scanMonitorIsInRequestedState(enable, hasScanMonitorRequest)) {
|
|
// The scan monitor is already in the requested state. A success event can
|
|
// be posted immediately.
|
|
success = postScanMonitorAsyncResultEvent(instanceId, true /* success */,
|
|
enable, CHRE_ERROR_NONE, cookie);
|
|
} else if (scanMonitorStateTransitionIsRequired(enable,
|
|
hasScanMonitorRequest)) {
|
|
success = addScanMonitorRequestToQueue(nanoapp, enable, cookie);
|
|
if (success) {
|
|
success = mPlatformWifi.configureScanMonitor(enable);
|
|
if (!success) {
|
|
mPendingScanMonitorRequests.pop_back();
|
|
LOGE("Failed to enable the scan monitor for nanoapp instance %" PRIu32,
|
|
instanceId);
|
|
}
|
|
}
|
|
} else {
|
|
CHRE_ASSERT_LOG(false, "Invalid scan monitor configuration");
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool WifiRequestManager::requestRanging(
|
|
Nanoapp *nanoapp, const struct chreWifiRangingParams *params,
|
|
const void *cookie) {
|
|
CHRE_ASSERT(nanoapp);
|
|
|
|
bool success = false;
|
|
if (!mPendingRangingRequests.emplace()) {
|
|
LOGE("Can't issue new RTT request; pending queue full");
|
|
} else {
|
|
PendingRangingRequest &req = mPendingRangingRequests.back();
|
|
req.nanoappInstanceId = nanoapp->getInstanceId();
|
|
req.cookie = cookie;
|
|
|
|
if (mPendingRangingRequests.size() == 1) {
|
|
// First in line; dispatch request immediately
|
|
if (getSettingState(Setting::LOCATION) == SettingState::DISABLED) {
|
|
// Treat as success but post async failure per API.
|
|
success = true;
|
|
postRangingAsyncResult(CHRE_ERROR_FUNCTION_DISABLED);
|
|
mPendingRangingRequests.pop_back();
|
|
} else if (!mPlatformWifi.requestRanging(params)) {
|
|
LOGE("WiFi RTT request failed");
|
|
mPendingRangingRequests.pop_back();
|
|
} else {
|
|
success = true;
|
|
mRangingResponseTimeout =
|
|
SystemTime::getMonotonicTime() +
|
|
Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
|
|
}
|
|
} else {
|
|
// Dispatch request later, after prior requests finish
|
|
// TODO(b/65331248): use a timer to ensure the platform is meeting its
|
|
// contract
|
|
CHRE_ASSERT_LOG(SystemTime::getMonotonicTime() <= mRangingResponseTimeout,
|
|
"WiFi platform didn't give callback in time");
|
|
success =
|
|
req.targetList.copy_array(params->targetList, params->targetListLen);
|
|
if (!success) {
|
|
LOG_OOM();
|
|
mPendingRangingRequests.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool WifiRequestManager::requestScan(Nanoapp *nanoapp,
|
|
const struct chreWifiScanParams *params,
|
|
const void *cookie) {
|
|
CHRE_ASSERT(nanoapp);
|
|
|
|
// TODO(b/65331248): replace with a timer to actively check response timeout
|
|
bool timedOut =
|
|
(mScanRequestingNanoappInstanceId.has_value() &&
|
|
mLastScanRequestTime + Nanoseconds(CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS) <
|
|
SystemTime::getMonotonicTime());
|
|
if (timedOut) {
|
|
LOGE("Scan request async response timed out");
|
|
mScanRequestingNanoappInstanceId.reset();
|
|
}
|
|
|
|
// Handle compatibility with nanoapps compiled against API v1.1, which doesn't
|
|
// include the radioChainPref parameter in chreWifiScanParams
|
|
struct chreWifiScanParams paramsCompat;
|
|
if (nanoapp->getTargetApiVersion() < CHRE_API_VERSION_1_2) {
|
|
memcpy(¶msCompat, params, offsetof(chreWifiScanParams, radioChainPref));
|
|
paramsCompat.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
|
|
params = ¶msCompat;
|
|
}
|
|
|
|
bool success = false;
|
|
if (mScanRequestingNanoappInstanceId.has_value()) {
|
|
LOGE("Active wifi scan request made while a request is in flight");
|
|
} else if (getSettingState(Setting::WIFI_AVAILABLE) ==
|
|
SettingState::DISABLED) {
|
|
// Treat as success, but send an async failure per API contract.
|
|
success = true;
|
|
handleScanResponse(false /* pending */, CHRE_ERROR_FUNCTION_DISABLED);
|
|
} else {
|
|
success = mPlatformWifi.requestScan(params);
|
|
if (!success) {
|
|
LOGE("Wifi scan request failed");
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
mScanRequestingNanoappInstanceId = nanoapp->getInstanceId();
|
|
mScanRequestingNanoappCookie = cookie;
|
|
mLastScanRequestTime = SystemTime::getMonotonicTime();
|
|
addWifiScanRequestLog(nanoapp->getInstanceId(), params);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void WifiRequestManager::handleScanMonitorStateChange(bool enabled,
|
|
uint8_t errorCode) {
|
|
struct CallbackState {
|
|
bool enabled;
|
|
uint8_t errorCode;
|
|
};
|
|
|
|
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
|
|
CallbackState cbState = NestedDataPtr<CallbackState>(data);
|
|
EventLoopManagerSingleton::get()
|
|
->getWifiRequestManager()
|
|
.handleScanMonitorStateChangeSync(cbState.enabled, cbState.errorCode);
|
|
};
|
|
|
|
CallbackState cbState = {};
|
|
cbState.enabled = enabled;
|
|
cbState.errorCode = errorCode;
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::WifiScanMonitorStateChange,
|
|
NestedDataPtr<CallbackState>(cbState), callback);
|
|
}
|
|
|
|
void WifiRequestManager::handleScanResponse(bool pending, uint8_t errorCode) {
|
|
struct CallbackState {
|
|
bool pending;
|
|
uint8_t errorCode;
|
|
};
|
|
|
|
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
|
|
CallbackState cbState = NestedDataPtr<CallbackState>(data);
|
|
EventLoopManagerSingleton::get()
|
|
->getWifiRequestManager()
|
|
.handleScanResponseSync(cbState.pending, cbState.errorCode);
|
|
};
|
|
|
|
CallbackState cbState = {};
|
|
cbState.pending = pending;
|
|
cbState.errorCode = errorCode;
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::WifiRequestScanResponse,
|
|
NestedDataPtr<CallbackState>(cbState), callback);
|
|
}
|
|
|
|
void WifiRequestManager::handleRangingEvent(
|
|
uint8_t errorCode, struct chreWifiRangingEvent *event) {
|
|
auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
|
|
uint8_t cbErrorCode = NestedDataPtr<uint8_t>(extraData);
|
|
EventLoopManagerSingleton::get()
|
|
->getWifiRequestManager()
|
|
.handleRangingEventSync(
|
|
cbErrorCode, static_cast<struct chreWifiRangingEvent *>(data));
|
|
};
|
|
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::WifiHandleRangingEvent, event, callback,
|
|
NestedDataPtr<uint8_t>(errorCode));
|
|
}
|
|
|
|
void WifiRequestManager::handleScanEvent(struct chreWifiScanEvent *event) {
|
|
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
|
|
auto *scanEvent = static_cast<struct chreWifiScanEvent *>(data);
|
|
EventLoopManagerSingleton::get()
|
|
->getWifiRequestManager()
|
|
.postScanEventFatal(scanEvent);
|
|
};
|
|
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::WifiHandleScanEvent, event, callback);
|
|
}
|
|
|
|
void WifiRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
|
|
debugDump.print("\nWifi: scan monitor %s\n",
|
|
scanMonitorIsEnabled() ? "enabled" : "disabled");
|
|
|
|
if (scanMonitorIsEnabled()) {
|
|
debugDump.print(" Wifi scan monitor enabled nanoapps:\n");
|
|
for (uint32_t instanceId : mScanMonitorNanoapps) {
|
|
debugDump.print(" nappId=%" PRIu32 "\n", instanceId);
|
|
}
|
|
}
|
|
|
|
if (mScanRequestingNanoappInstanceId.has_value()) {
|
|
debugDump.print(" Wifi request pending nanoappId=%" PRIu32 "\n",
|
|
mScanRequestingNanoappInstanceId.value());
|
|
}
|
|
|
|
if (!mPendingScanMonitorRequests.empty()) {
|
|
debugDump.print(" Wifi transition queue:\n");
|
|
for (const auto &transition : mPendingScanMonitorRequests) {
|
|
debugDump.print(" enable=%s nappId=%" PRIu32 "\n",
|
|
transition.enable ? "true" : "false",
|
|
transition.nanoappInstanceId);
|
|
}
|
|
}
|
|
|
|
debugDump.print(" Last %zu wifi scan requests:\n",
|
|
mWifiScanRequestLogs.size());
|
|
static_assert(kNumWifiRequestLogs <= INT8_MAX,
|
|
"kNumWifiRequestLogs must be <= INT8_MAX");
|
|
for (int8_t i = static_cast<int8_t>(mWifiScanRequestLogs.size()) - 1; i >= 0;
|
|
i--) {
|
|
const auto &log = mWifiScanRequestLogs[static_cast<size_t>(i)];
|
|
debugDump.print(" ts=%" PRIu64 " nappId=%" PRIu32 " scanType=%" PRIu8
|
|
" maxScanAge(ms)=%" PRIu64 "\n",
|
|
log.timestamp.toRawNanoseconds(), log.instanceId,
|
|
log.scanType, log.maxScanAgeMs.getMilliseconds());
|
|
}
|
|
|
|
debugDump.print(" Last scan event @ %" PRIu64 " ms",
|
|
mLastScanEventTime.getMilliseconds());
|
|
}
|
|
|
|
bool WifiRequestManager::scanMonitorIsEnabled() const {
|
|
return !mScanMonitorNanoapps.empty();
|
|
}
|
|
|
|
bool WifiRequestManager::nanoappHasScanMonitorRequest(
|
|
uint32_t instanceId, size_t *nanoappIndex) const {
|
|
size_t index = mScanMonitorNanoapps.find(instanceId);
|
|
bool hasScanMonitorRequest = (index != mScanMonitorNanoapps.size());
|
|
if (hasScanMonitorRequest && nanoappIndex != nullptr) {
|
|
*nanoappIndex = index;
|
|
}
|
|
|
|
return hasScanMonitorRequest;
|
|
}
|
|
|
|
bool WifiRequestManager::scanMonitorIsInRequestedState(
|
|
bool requestedState, bool nanoappHasRequest) const {
|
|
return (requestedState == scanMonitorIsEnabled() ||
|
|
(!requestedState &&
|
|
(!nanoappHasRequest || mScanMonitorNanoapps.size() > 1)));
|
|
}
|
|
|
|
bool WifiRequestManager::scanMonitorStateTransitionIsRequired(
|
|
bool requestedState, bool nanoappHasRequest) const {
|
|
return ((requestedState && mScanMonitorNanoapps.empty()) ||
|
|
(!requestedState && nanoappHasRequest &&
|
|
mScanMonitorNanoapps.size() == 1));
|
|
}
|
|
|
|
bool WifiRequestManager::addScanMonitorRequestToQueue(Nanoapp *nanoapp,
|
|
bool enable,
|
|
const void *cookie) {
|
|
PendingScanMonitorRequest scanMonitorStateTransition;
|
|
scanMonitorStateTransition.nanoappInstanceId = nanoapp->getInstanceId();
|
|
scanMonitorStateTransition.cookie = cookie;
|
|
scanMonitorStateTransition.enable = enable;
|
|
|
|
bool success = mPendingScanMonitorRequests.push(scanMonitorStateTransition);
|
|
if (!success) {
|
|
LOGW("Too many scan monitor state transitions");
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool WifiRequestManager::updateNanoappScanMonitoringList(bool enable,
|
|
uint32_t instanceId) {
|
|
bool success = true;
|
|
Nanoapp *nanoapp =
|
|
EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
|
|
instanceId);
|
|
if (nanoapp == nullptr) {
|
|
LOGW("Failed to update scan monitoring list for non-existent nanoapp");
|
|
} else {
|
|
size_t nanoappIndex;
|
|
bool hasExistingRequest =
|
|
nanoappHasScanMonitorRequest(instanceId, &nanoappIndex);
|
|
if (enable) {
|
|
if (!hasExistingRequest) {
|
|
// The scan monitor was successfully enabled for this nanoapp and
|
|
// there is no existing request. Add it to the list of scan monitoring
|
|
// nanoapps.
|
|
success = mScanMonitorNanoapps.push_back(instanceId);
|
|
if (!success) {
|
|
LOG_OOM();
|
|
} else {
|
|
nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
|
|
}
|
|
}
|
|
} else if (hasExistingRequest) {
|
|
// The scan monitor was successfully disabled for a previously enabled
|
|
// nanoapp. Remove it from the list of scan monitoring nanoapps.
|
|
mScanMonitorNanoapps.erase(nanoappIndex);
|
|
nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
|
|
} // else disabling an inactive request, treat as success per the CHRE API.
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool WifiRequestManager::postScanMonitorAsyncResultEvent(
|
|
uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
|
|
const void *cookie) {
|
|
// Allocate and post an event to the nanoapp requesting wifi.
|
|
bool eventPosted = false;
|
|
if (!success || updateNanoappScanMonitoringList(enable, nanoappInstanceId)) {
|
|
chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
|
|
if (event == nullptr) {
|
|
LOG_OOM();
|
|
} else {
|
|
event->requestType = CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR;
|
|
event->success = success;
|
|
event->errorCode = errorCode;
|
|
event->reserved = 0;
|
|
event->cookie = cookie;
|
|
|
|
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
|
|
CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
|
|
nanoappInstanceId);
|
|
eventPosted = true;
|
|
}
|
|
}
|
|
|
|
return eventPosted;
|
|
}
|
|
|
|
void WifiRequestManager::postScanMonitorAsyncResultEventFatal(
|
|
uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
|
|
const void *cookie) {
|
|
if (!postScanMonitorAsyncResultEvent(nanoappInstanceId, success, enable,
|
|
errorCode, cookie)) {
|
|
FATAL_ERROR("Failed to send WiFi scan monitor async result event");
|
|
}
|
|
}
|
|
|
|
bool WifiRequestManager::postScanRequestAsyncResultEvent(
|
|
uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
|
|
const void *cookie) {
|
|
// TODO: the body of this function can be extracted to a common helper for use
|
|
// across this function, postScanMonitorAsyncResultEvent,
|
|
// postRangingAsyncResult, and GnssSession::postAsyncResultEvent
|
|
bool eventPosted = false;
|
|
chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
|
|
if (event == nullptr) {
|
|
LOG_OOM();
|
|
} else {
|
|
event->requestType = CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN;
|
|
event->success = success;
|
|
event->errorCode = errorCode;
|
|
event->reserved = 0;
|
|
event->cookie = cookie;
|
|
|
|
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
|
|
CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
|
|
nanoappInstanceId);
|
|
eventPosted = true;
|
|
}
|
|
|
|
return eventPosted;
|
|
}
|
|
|
|
void WifiRequestManager::postScanRequestAsyncResultEventFatal(
|
|
uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
|
|
const void *cookie) {
|
|
if (!postScanRequestAsyncResultEvent(nanoappInstanceId, success, errorCode,
|
|
cookie)) {
|
|
FATAL_ERROR("Failed to send WiFi scan request async result event");
|
|
}
|
|
}
|
|
|
|
void WifiRequestManager::postScanEventFatal(chreWifiScanEvent *event) {
|
|
mLastScanEventTime = Milliseconds(SystemTime::getMonotonicTime());
|
|
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
|
|
CHRE_EVENT_WIFI_SCAN_RESULT, event, freeWifiScanEventCallback);
|
|
}
|
|
|
|
void WifiRequestManager::handleScanMonitorStateChangeSync(bool enabled,
|
|
uint8_t errorCode) {
|
|
// Success is defined as having no errors ... in life ༼ つ ◕_◕ ༽つ
|
|
bool success = (errorCode == CHRE_ERROR_NONE);
|
|
|
|
// TODO(b/62904616): re-enable this assertion
|
|
// CHRE_ASSERT_LOG(!mScanMonitorStateTransitions.empty(),
|
|
// "handleScanMonitorStateChangeSync called with no
|
|
// transitions");
|
|
if (mPendingScanMonitorRequests.empty()) {
|
|
LOGE(
|
|
"WiFi PAL error: handleScanMonitorStateChangeSync called with no "
|
|
"transitions (enabled %d errorCode %" PRIu8 ")",
|
|
enabled, errorCode);
|
|
}
|
|
|
|
// Always check the front of the queue.
|
|
if (!mPendingScanMonitorRequests.empty()) {
|
|
const auto &stateTransition = mPendingScanMonitorRequests.front();
|
|
success &= (stateTransition.enable == enabled);
|
|
postScanMonitorAsyncResultEventFatal(stateTransition.nanoappInstanceId,
|
|
success, stateTransition.enable,
|
|
errorCode, stateTransition.cookie);
|
|
mPendingScanMonitorRequests.pop();
|
|
}
|
|
|
|
while (!mPendingScanMonitorRequests.empty()) {
|
|
const auto &stateTransition = mPendingScanMonitorRequests.front();
|
|
bool hasScanMonitorRequest =
|
|
nanoappHasScanMonitorRequest(stateTransition.nanoappInstanceId);
|
|
if (scanMonitorIsInRequestedState(stateTransition.enable,
|
|
hasScanMonitorRequest)) {
|
|
// We are already in the target state so just post an event indicating
|
|
// success
|
|
postScanMonitorAsyncResultEventFatal(
|
|
stateTransition.nanoappInstanceId, true /* success */,
|
|
stateTransition.enable, CHRE_ERROR_NONE, stateTransition.cookie);
|
|
} else if (scanMonitorStateTransitionIsRequired(stateTransition.enable,
|
|
hasScanMonitorRequest)) {
|
|
if (mPlatformWifi.configureScanMonitor(stateTransition.enable)) {
|
|
break;
|
|
} else {
|
|
postScanMonitorAsyncResultEventFatal(
|
|
stateTransition.nanoappInstanceId, false /* success */,
|
|
stateTransition.enable, CHRE_ERROR, stateTransition.cookie);
|
|
}
|
|
} else {
|
|
CHRE_ASSERT_LOG(false, "Invalid scan monitor state");
|
|
break;
|
|
}
|
|
|
|
mPendingScanMonitorRequests.pop();
|
|
}
|
|
}
|
|
|
|
void WifiRequestManager::handleScanResponseSync(bool pending,
|
|
uint8_t errorCode) {
|
|
// TODO(b/65206783): re-enable this assertion
|
|
// CHRE_ASSERT_LOG(mScanRequestingNanoappInstanceId.has_value(),
|
|
// "handleScanResponseSync called with no outstanding
|
|
// request");
|
|
if (!mScanRequestingNanoappInstanceId.has_value()) {
|
|
LOGE("handleScanResponseSync called with no outstanding request");
|
|
}
|
|
|
|
// TODO: raise this to CHRE_ASSERT_LOG
|
|
if (!pending && errorCode == CHRE_ERROR_NONE) {
|
|
LOGE("Invalid wifi scan response");
|
|
errorCode = CHRE_ERROR;
|
|
}
|
|
|
|
if (mScanRequestingNanoappInstanceId.has_value()) {
|
|
bool success = (pending && errorCode == CHRE_ERROR_NONE);
|
|
if (!success) {
|
|
LOGW("Wifi scan request failed: pending %d, errorCode %" PRIu8, pending,
|
|
errorCode);
|
|
}
|
|
postScanRequestAsyncResultEventFatal(*mScanRequestingNanoappInstanceId,
|
|
success, errorCode,
|
|
mScanRequestingNanoappCookie);
|
|
|
|
// Set a flag to indicate that results may be pending.
|
|
mScanRequestResultsArePending = pending;
|
|
|
|
if (pending) {
|
|
Nanoapp *nanoapp =
|
|
EventLoopManagerSingleton::get()
|
|
->getEventLoop()
|
|
.findNanoappByInstanceId(*mScanRequestingNanoappInstanceId);
|
|
if (nanoapp == nullptr) {
|
|
LOGW("Received WiFi scan response for unknown nanoapp");
|
|
} else {
|
|
nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
|
|
}
|
|
} else {
|
|
// If the scan results are not pending, clear the nanoapp instance ID.
|
|
// Otherwise, wait for the results to be delivered and then clear the
|
|
// instance ID.
|
|
mScanRequestingNanoappInstanceId.reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool WifiRequestManager::postRangingAsyncResult(uint8_t errorCode) {
|
|
bool eventPosted = false;
|
|
|
|
if (mPendingRangingRequests.empty()) {
|
|
LOGE("Unexpected ranging event callback");
|
|
} else {
|
|
auto *event = memoryAlloc<struct chreAsyncResult>();
|
|
if (event == nullptr) {
|
|
LOG_OOM();
|
|
} else {
|
|
const PendingRangingRequest &req = mPendingRangingRequests.front();
|
|
|
|
event->requestType = CHRE_WIFI_REQUEST_TYPE_RANGING;
|
|
event->success = (errorCode == CHRE_ERROR_NONE);
|
|
event->errorCode = errorCode;
|
|
event->reserved = 0;
|
|
event->cookie = req.cookie;
|
|
|
|
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
|
|
CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
|
|
req.nanoappInstanceId);
|
|
eventPosted = true;
|
|
}
|
|
}
|
|
|
|
return eventPosted;
|
|
}
|
|
|
|
bool WifiRequestManager::dispatchQueuedRangingRequest() {
|
|
const PendingRangingRequest &req = mPendingRangingRequests.front();
|
|
struct chreWifiRangingParams params = {};
|
|
params.targetListLen = static_cast<uint8_t>(req.targetList.size());
|
|
params.targetList = req.targetList.data();
|
|
|
|
bool success = false;
|
|
if (getSettingState(Setting::LOCATION) == SettingState::DISABLED) {
|
|
postRangingAsyncResult(CHRE_ERROR_FUNCTION_DISABLED);
|
|
mPendingRangingRequests.pop();
|
|
} else if (!mPlatformWifi.requestRanging(¶ms)) {
|
|
LOGE("Failed to issue queued ranging result");
|
|
postRangingAsyncResult(CHRE_ERROR);
|
|
mPendingRangingRequests.pop();
|
|
} else {
|
|
success = true;
|
|
mRangingResponseTimeout = SystemTime::getMonotonicTime() +
|
|
Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void WifiRequestManager::handleRangingEventSync(
|
|
uint8_t errorCode, struct chreWifiRangingEvent *event) {
|
|
if (getSettingState(Setting::LOCATION) == SettingState::DISABLED) {
|
|
errorCode = CHRE_ERROR_FUNCTION_DISABLED;
|
|
}
|
|
|
|
if (postRangingAsyncResult(errorCode)) {
|
|
if (errorCode != CHRE_ERROR_NONE) {
|
|
LOGW("RTT ranging failed with error %d", errorCode);
|
|
if (event != nullptr) {
|
|
freeWifiRangingEventCallback(CHRE_EVENT_WIFI_RANGING_RESULT, event);
|
|
}
|
|
} else {
|
|
EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
|
|
CHRE_EVENT_WIFI_RANGING_RESULT, event, freeWifiRangingEventCallback,
|
|
mPendingRangingRequests.front().nanoappInstanceId);
|
|
}
|
|
mPendingRangingRequests.pop();
|
|
}
|
|
|
|
// If we have any pending requests, try issuing them to the platform until the
|
|
// first one succeeds
|
|
while (!mPendingRangingRequests.empty() && !dispatchQueuedRangingRequest())
|
|
;
|
|
}
|
|
|
|
void WifiRequestManager::handleFreeWifiScanEvent(chreWifiScanEvent *scanEvent) {
|
|
if (mScanRequestResultsArePending) {
|
|
// Reset the event distribution logic once an entire scan event has been
|
|
// received and processed by the nanoapp requesting the scan event.
|
|
mScanEventResultCountAccumulator += scanEvent->resultCount;
|
|
if (mScanEventResultCountAccumulator >= scanEvent->resultTotal) {
|
|
mScanEventResultCountAccumulator = 0;
|
|
mScanRequestResultsArePending = false;
|
|
}
|
|
|
|
if (!mScanRequestResultsArePending &&
|
|
mScanRequestingNanoappInstanceId.has_value()) {
|
|
Nanoapp *nanoapp =
|
|
EventLoopManagerSingleton::get()
|
|
->getEventLoop()
|
|
.findNanoappByInstanceId(*mScanRequestingNanoappInstanceId);
|
|
if (nanoapp == nullptr) {
|
|
LOGW("Attempted to unsubscribe unknown nanoapp from WiFi scan events");
|
|
} else if (!nanoappHasScanMonitorRequest(
|
|
*mScanRequestingNanoappInstanceId)) {
|
|
nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
|
|
}
|
|
|
|
mScanRequestingNanoappInstanceId.reset();
|
|
}
|
|
}
|
|
|
|
mPlatformWifi.releaseScanEvent(scanEvent);
|
|
}
|
|
|
|
void WifiRequestManager::addWifiScanRequestLog(
|
|
uint32_t nanoappInstanceId, const chreWifiScanParams *params) {
|
|
mWifiScanRequestLogs.kick_push(
|
|
WifiScanRequestLog(SystemTime::getMonotonicTime(), nanoappInstanceId,
|
|
static_cast<chreWifiScanType>(params->scanType),
|
|
static_cast<Milliseconds>(params->maxScanAgeMs)));
|
|
}
|
|
|
|
void WifiRequestManager::freeWifiScanEventCallback(uint16_t /* eventType */,
|
|
void *eventData) {
|
|
auto *scanEvent = static_cast<struct chreWifiScanEvent *>(eventData);
|
|
EventLoopManagerSingleton::get()
|
|
->getWifiRequestManager()
|
|
.handleFreeWifiScanEvent(scanEvent);
|
|
}
|
|
|
|
void WifiRequestManager::freeWifiRangingEventCallback(uint16_t /* eventType */,
|
|
void *eventData) {
|
|
auto *event = static_cast<struct chreWifiRangingEvent *>(eventData);
|
|
EventLoopManagerSingleton::get()
|
|
->getWifiRequestManager()
|
|
.mPlatformWifi.releaseRangingEvent(event);
|
|
}
|
|
|
|
} // namespace chre
|