| /* |
| * 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 <cstdint> |
| #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" |
| #include "include/chre/core/event_loop_common.h" |
| #include "include/chre/core/wifi_request_manager.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; |
| uint16_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 %" PRIu16, |
| instanceId); |
| } |
| } |
| } else { |
| CHRE_ASSERT_LOG(false, "Invalid scan monitor configuration"); |
| } |
| |
| return success; |
| } |
| |
| uint32_t WifiRequestManager::disableAllSubscriptions(Nanoapp *nanoapp) { |
| uint32_t numSubscriptionsDisabled = 0; |
| |
| // Disable active scan monitoring. |
| if (nanoappHasScanMonitorRequest(nanoapp->getInstanceId()) || |
| nanoappHasPendingScanMonitorRequest(nanoapp->getInstanceId())) { |
| numSubscriptionsDisabled++; |
| configureScanMonitor(nanoapp, false /*enabled*/, nullptr /*cookie*/); |
| } |
| |
| // Disable active NAN subscriptions. |
| for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) { |
| if (mNanoappSubscriptions[i].nanoappInstanceId == |
| nanoapp->getInstanceId()) { |
| numSubscriptionsDisabled++; |
| nanSubscribeCancel(nanoapp, mNanoappSubscriptions[i].subscriptionId); |
| } |
| } |
| |
| return numSubscriptionsDisabled; |
| } |
| |
| bool WifiRequestManager::requestRangingByType(RangingType type, |
| const void *rangingParams) { |
| bool success = false; |
| if (type == RangingType::WIFI_AP) { |
| auto *params = |
| static_cast<const struct chreWifiRangingParams *>(rangingParams); |
| success = mPlatformWifi.requestRanging(params); |
| } else { |
| auto *params = |
| static_cast<const struct chreWifiNanRangingParams *>(rangingParams); |
| success = mPlatformWifi.requestNanRanging(params); |
| } |
| return success; |
| } |
| |
| bool WifiRequestManager::updateRangingRequest(RangingType type, |
| PendingRangingRequest &request, |
| const void *rangingParams) { |
| bool success = false; |
| if (type == RangingType::WIFI_AP) { |
| auto *params = |
| static_cast<const struct chreWifiRangingParams *>(rangingParams); |
| success = request.targetList.copy_array(params->targetList, |
| params->targetListLen); |
| } else { |
| auto *params = |
| static_cast<const struct chreWifiNanRangingParams *>(rangingParams); |
| std::memcpy(request.nanRangingParams.macAddress, params->macAddress, |
| CHRE_WIFI_BSSID_LEN); |
| success = true; |
| } |
| return success; |
| } |
| |
| bool WifiRequestManager::sendRangingRequest(PendingRangingRequest &request) { |
| bool success = false; |
| if (request.type == RangingType::WIFI_AP) { |
| struct chreWifiRangingParams params = {}; |
| params.targetListLen = static_cast<uint8_t>(request.targetList.size()); |
| params.targetList = request.targetList.data(); |
| success = mPlatformWifi.requestRanging(¶ms); |
| } else { |
| struct chreWifiNanRangingParams params; |
| std::memcpy(params.macAddress, request.nanRangingParams.macAddress, |
| CHRE_WIFI_BSSID_LEN); |
| success = mPlatformWifi.requestNanRanging(¶ms); |
| } |
| return success; |
| } |
| |
| bool WifiRequestManager::requestRanging(RangingType rangingType, |
| Nanoapp *nanoapp, |
| const void *rangingParams, |
| const void *cookie) { |
| CHRE_ASSERT(nanoapp); |
| CHRE_ASSERT(rangingParams); |
| |
| 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 (!areRequiredSettingsEnabled()) { |
| // Treat as success but post async failure per API. |
| success = true; |
| postRangingAsyncResult(CHRE_ERROR_FUNCTION_DISABLED); |
| mPendingRangingRequests.pop_back(); |
| } else if (!requestRangingByType(rangingType, rangingParams)) { |
| LOGE("WiFi ranging request of type %d failed", |
| static_cast<int>(rangingType)); |
| 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 = updateRangingRequest(rangingType, req, rangingParams); |
| 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 by 0x%" PRIx64 |
| " while a request by 0x%" PRIx64 " is in flight", |
| nanoapp->getAppId(), |
| EventLoopManagerSingleton::get() |
| ->getEventLoop() |
| .findNanoappByInstanceId(mScanRequestingNanoappInstanceId.value()) |
| ->getAppId()); |
| } else if (!EventLoopManagerSingleton::get() |
| ->getSettingManager() |
| .getSettingEnabled(Setting::WIFI_AVAILABLE)) { |
| // 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::handleNanServiceIdentifierEventSync( |
| uint8_t errorCode, uint32_t subscriptionId) { |
| if (!mPendingNanSubscribeRequests.empty()) { |
| auto &req = mPendingNanSubscribeRequests.front(); |
| chreWifiNanIdentifierEvent *event = |
| memoryAlloc<chreWifiNanIdentifierEvent>(); |
| |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->id = subscriptionId; |
| event->result.requestType = CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE; |
| event->result.success = (errorCode == CHRE_ERROR_NONE); |
| event->result.errorCode = errorCode; |
| event->result.cookie = req.cookie; |
| |
| if (errorCode == CHRE_ERROR_NONE) { |
| // It is assumed that the NAN discovery engine guarantees a unique ID |
| // for each subscription - avoid redundant checks on uniqueness here. |
| if (!mNanoappSubscriptions.push_back(NanoappNanSubscriptions( |
| req.nanoappInstanceId, subscriptionId))) { |
| LOG_OOM(); |
| // Even though the subscription request was able to successfully |
| // obtain an ID, CHRE ran out of memory and couldn't store the |
| // instance ID - subscription ID pair. Indicate this in the event |
| // result. |
| // TODO(b/204226580): Cancel the subscription if we run out of |
| // memory. |
| event->result.errorCode = CHRE_ERROR_NO_MEMORY; |
| } |
| } |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event, freeEventDataCallback, |
| req.nanoappInstanceId); |
| } |
| |
| mPendingNanSubscribeRequests.pop(); |
| dispatchQueuedNanSubscribeRequestWithRetry(); |
| } else { |
| LOGE("Received a NAN identifier event with no pending request!"); |
| } |
| } |
| |
| void WifiRequestManager::handleNanServiceIdentifierEvent( |
| uint8_t errorCode, uint32_t subscriptionId) { |
| auto callback = [](uint16_t /*type*/, void *data, void *extraData) { |
| uint8_t errorCode = NestedDataPtr<uint8_t>(data); |
| uint32_t subscriptionId = NestedDataPtr<uint32_t>(extraData); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .handleNanServiceIdentifierEventSync(errorCode, subscriptionId); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::WifiNanServiceIdEvent, |
| NestedDataPtr<uint8_t>(errorCode), callback, |
| NestedDataPtr<uint32_t>(subscriptionId)); |
| } |
| |
| bool WifiRequestManager::getNappIdFromSubscriptionId( |
| uint32_t subscriptionId, uint16_t *nanoappInstanceId) { |
| bool success = false; |
| for (auto &sub : mNanoappSubscriptions) { |
| if (sub.subscriptionId == subscriptionId) { |
| *nanoappInstanceId = sub.nanoappInstanceId; |
| success = true; |
| break; |
| } |
| } |
| return success; |
| } |
| |
| void WifiRequestManager::handleNanServiceDiscoveryEventSync( |
| struct chreWifiNanDiscoveryEvent *event) { |
| CHRE_ASSERT(event != nullptr); |
| uint16_t nanoappInstanceId; |
| if (getNappIdFromSubscriptionId(event->subscribeId, &nanoappInstanceId)) { |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event, |
| freeNanDiscoveryEventCallback, nanoappInstanceId); |
| } else { |
| LOGE("Failed to find a nanoapp owning subscription ID %" PRIu32, |
| event->subscribeId); |
| } |
| } |
| |
| void WifiRequestManager::handleNanServiceDiscoveryEvent( |
| struct chreWifiNanDiscoveryEvent *event) { |
| auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) { |
| auto *event = static_cast<chreWifiNanDiscoveryEvent *>(data); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .handleNanServiceDiscoveryEventSync(event); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::WifiNanServiceDiscoveryEvent, event, callback); |
| } |
| |
| void WifiRequestManager::handleNanServiceLostEventSync(uint32_t subscriptionId, |
| uint32_t publisherId) { |
| uint16_t nanoappInstanceId; |
| if (getNappIdFromSubscriptionId(subscriptionId, &nanoappInstanceId)) { |
| chreWifiNanSessionLostEvent *event = |
| memoryAlloc<chreWifiNanSessionLostEvent>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->id = subscriptionId; |
| event->peerId = publisherId; |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_NAN_SESSION_LOST, event, freeEventDataCallback, |
| nanoappInstanceId); |
| } |
| } else { |
| LOGE("Failed to find a nanoapp owning subscription ID %" PRIu32, |
| subscriptionId); |
| } |
| } |
| |
| void WifiRequestManager::handleNanServiceLostEvent(uint32_t subscriptionId, |
| uint32_t publisherId) { |
| auto callback = [](uint16_t /*type*/, void *data, void *extraData) { |
| auto subscriptionId = NestedDataPtr<uint32_t>(data); |
| auto publisherId = NestedDataPtr<uint32_t>(extraData); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .handleNanServiceLostEventSync(subscriptionId, publisherId); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::WifiNanServiceSessionLostEvent, |
| NestedDataPtr<uint32_t>(subscriptionId), callback, |
| NestedDataPtr<uint32_t>(publisherId)); |
| } |
| |
| void WifiRequestManager::handleNanServiceTerminatedEventSync( |
| uint8_t errorCode, uint32_t subscriptionId) { |
| uint16_t nanoappInstanceId; |
| if (getNappIdFromSubscriptionId(subscriptionId, &nanoappInstanceId)) { |
| chreWifiNanSessionTerminatedEvent *event = |
| memoryAlloc<chreWifiNanSessionTerminatedEvent>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->id = subscriptionId; |
| event->reason = errorCode; |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED, event, freeEventDataCallback, |
| nanoappInstanceId); |
| } |
| } else { |
| LOGE("Failed to find a nanoapp owning subscription ID %" PRIu32, |
| subscriptionId); |
| } |
| } |
| |
| void WifiRequestManager::handleNanServiceSubscriptionCanceledEventSync( |
| uint8_t errorCode, uint32_t subscriptionId) { |
| for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) { |
| if (mNanoappSubscriptions[i].subscriptionId == subscriptionId) { |
| if (errorCode != CHRE_ERROR_NONE) { |
| LOGE("Subscription %" PRIu32 " cancelation error: %" PRIu8, |
| subscriptionId, errorCode); |
| } |
| mNanoappSubscriptions.erase(i); |
| break; |
| } |
| } |
| } |
| |
| void WifiRequestManager::handleNanServiceTerminatedEvent( |
| uint8_t errorCode, uint32_t subscriptionId) { |
| auto callback = [](uint16_t /*type*/, void *data, void *extraData) { |
| auto errorCode = NestedDataPtr<uint8_t>(data); |
| auto subscriptionId = NestedDataPtr<uint32_t>(extraData); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .handleNanServiceTerminatedEventSync(errorCode, subscriptionId); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::WifiNanServiceTerminatedEvent, |
| NestedDataPtr<uint8_t>(errorCode), callback, |
| NestedDataPtr<uint32_t>(subscriptionId)); |
| } |
| |
| void WifiRequestManager::handleNanServiceSubscriptionCanceledEvent( |
| uint8_t errorCode, uint32_t subscriptionId) { |
| auto callback = [](uint16_t /*type*/, void *data, void *extraData) { |
| auto errorCode = NestedDataPtr<uint8_t>(data); |
| auto subscriptionId = NestedDataPtr<uint32_t>(extraData); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .handleNanServiceSubscriptionCanceledEventSync(errorCode, |
| subscriptionId); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::WifiNanServiceTerminatedEvent, |
| NestedDataPtr<uint8_t>(errorCode), callback, |
| NestedDataPtr<uint32_t>(subscriptionId)); |
| } |
| |
| 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 (uint16_t instanceId : mScanMonitorNanoapps) { |
| debugDump.print(" nappId=%" PRIu16 "\n", instanceId); |
| } |
| } |
| |
| if (mScanRequestingNanoappInstanceId.has_value()) { |
| debugDump.print(" Wifi request pending nanoappId=%" PRIu16 "\n", |
| mScanRequestingNanoappInstanceId.value()); |
| } |
| |
| if (!mPendingScanMonitorRequests.empty()) { |
| debugDump.print(" Wifi transition queue:\n"); |
| for (const auto &transition : mPendingScanMonitorRequests) { |
| debugDump.print(" enable=%s nappId=%" PRIu16 "\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=%" PRIu16 " scanType=%" PRIu8 |
| " maxScanAge(ms)=%" PRIu64 "\n", |
| log.timestamp.toRawNanoseconds(), log.instanceId, |
| log.scanType, log.maxScanAgeMs.getMilliseconds()); |
| } |
| |
| debugDump.print(" Last scan event @ %" PRIu64 " ms\n", |
| mLastScanEventTime.getMilliseconds()); |
| |
| debugDump.print(" API error distribution (error-code indexed):\n"); |
| debugDump.print(" Scan monitor:\n"); |
| debugDump.logErrorHistogram(mScanMonitorErrorHistogram, |
| ARRAY_SIZE(mScanMonitorErrorHistogram)); |
| debugDump.print(" Active Scan:\n"); |
| debugDump.logErrorHistogram(mActiveScanErrorHistogram, |
| ARRAY_SIZE(mActiveScanErrorHistogram)); |
| |
| if (!mNanoappSubscriptions.empty()) { |
| debugDump.print(" Active NAN service subscriptions:\n"); |
| for (const auto &sub : mNanoappSubscriptions) { |
| debugDump.print(" nappID=%" PRIu16 " sub ID=%" PRIu32 "\n", |
| sub.nanoappInstanceId, sub.subscriptionId); |
| } |
| } |
| |
| if (!mPendingNanSubscribeRequests.empty()) { |
| debugDump.print(" Pending NAN service subscriptions:\n"); |
| for (const auto &req : mPendingNanSubscribeRequests) { |
| debugDump.print(" nappID=%" PRIu16 " (type %" PRIu8 ") to svc: %s\n", |
| req.nanoappInstanceId, req.type, req.service.data()); |
| } |
| } |
| } |
| |
| bool WifiRequestManager::scanMonitorIsEnabled() const { |
| return !mScanMonitorNanoapps.empty(); |
| } |
| |
| bool WifiRequestManager::nanoappHasScanMonitorRequest( |
| uint16_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::nanoappHasPendingScanMonitorRequest( |
| uint16_t instanceId) const { |
| const int numRequests = static_cast<int>(mPendingScanMonitorRequests.size()); |
| for (int i = numRequests - 1; i >= 0; i--) { |
| const PendingScanMonitorRequest &request = |
| mPendingScanMonitorRequests[static_cast<size_t>(i)]; |
| // The last pending request determines the state of the scan monitoring. |
| if (request.nanoappInstanceId == instanceId) { |
| return request.enable; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool WifiRequestManager::updateNanoappScanMonitoringList(bool enable, |
| uint16_t instanceId) { |
| bool success = true; |
| Nanoapp *nanoapp = |
| EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId( |
| instanceId); |
| size_t nanoappIndex; |
| bool hasExistingRequest = |
| nanoappHasScanMonitorRequest(instanceId, &nanoappIndex); |
| |
| if (nanoapp == nullptr) { |
| // When the scan monitoring is disabled from inside nanoappEnd() or when |
| // CHRE cleanup the subscription automatically it is possible that the |
| // current method is called after the nanoapp is unloaded. In such a case |
| // we still want to remove the nanoapp from mScanMonitorNanoapps. |
| if (!enable && hasExistingRequest) { |
| mScanMonitorNanoapps.erase(nanoappIndex); |
| } else { |
| LOGW("Failed to update scan monitoring list for non-existent nanoapp"); |
| } |
| } else { |
| 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( |
| uint16_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; |
| |
| mScanMonitorErrorHistogram[errorCode]++; |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback, |
| nanoappInstanceId); |
| eventPosted = true; |
| } |
| } |
| |
| return eventPosted; |
| } |
| |
| void WifiRequestManager::postScanMonitorAsyncResultEventFatal( |
| uint16_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( |
| uint16_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; |
| |
| mActiveScanErrorHistogram[errorCode]++; |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback, |
| nanoappInstanceId); |
| eventPosted = true; |
| } |
| |
| return eventPosted; |
| } |
| |
| void WifiRequestManager::postScanRequestAsyncResultEventFatal( |
| uint16_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::postNanAsyncResultEvent(uint16_t nanoappInstanceId, |
| uint8_t requestType, |
| bool success, |
| uint8_t errorCode, |
| const void *cookie) { |
| chreAsyncResult *event = memoryAlloc<chreAsyncResult>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->requestType = requestType; |
| event->cookie = cookie; |
| event->errorCode = errorCode; |
| event->success = success; |
| |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback, |
| nanoappInstanceId); |
| } |
| } |
| 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() { |
| bool success = false; |
| uint8_t asyncError = CHRE_ERROR_NONE; |
| PendingRangingRequest &req = mPendingRangingRequests.front(); |
| |
| if (!areRequiredSettingsEnabled()) { |
| asyncError = CHRE_ERROR_FUNCTION_DISABLED; |
| } else if (!sendRangingRequest(req)) { |
| asyncError = CHRE_ERROR; |
| } else { |
| success = true; |
| mRangingResponseTimeout = SystemTime::getMonotonicTime() + |
| Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS); |
| } |
| |
| if (asyncError != CHRE_ERROR_NONE) { |
| postRangingAsyncResult(asyncError); |
| mPendingRangingRequests.pop(); |
| } |
| |
| return success; |
| } |
| |
| bool WifiRequestManager::dispatchQueuedNanSubscribeRequest() { |
| bool success = false; |
| |
| if (!mPendingNanSubscribeRequests.empty()) { |
| uint8_t asyncError = CHRE_ERROR_NONE; |
| const auto &req = mPendingNanSubscribeRequests.front(); |
| struct chreWifiNanSubscribeConfig config = {}; |
| buildNanSubscribeConfigFromRequest(req, &config); |
| |
| if (!areRequiredSettingsEnabled()) { |
| asyncError = CHRE_ERROR_FUNCTION_DISABLED; |
| } else if (!mPlatformWifi.nanSubscribe(&config)) { |
| asyncError = CHRE_ERROR; |
| } |
| |
| if (asyncError != CHRE_ERROR_NONE) { |
| postNanAsyncResultEvent(req.nanoappInstanceId, |
| CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE, |
| false /*success*/, asyncError, req.cookie); |
| mPendingNanSubscribeRequests.pop(); |
| } else { |
| success = true; |
| } |
| } |
| return success; |
| } |
| |
| void WifiRequestManager::dispatchQueuedNanSubscribeRequestWithRetry() { |
| while (!mPendingNanSubscribeRequests.empty() && |
| !dispatchQueuedNanSubscribeRequest()) |
| ; |
| } |
| |
| void WifiRequestManager::handleRangingEventSync( |
| uint8_t errorCode, struct chreWifiRangingEvent *event) { |
| if (!areRequiredSettingsEnabled()) { |
| 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( |
| uint16_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); |
| } |
| |
| void WifiRequestManager::freeNanDiscoveryEventCallback(uint16_t /* eventType */, |
| void *eventData) { |
| auto *event = static_cast<struct chreWifiNanDiscoveryEvent *>(eventData); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .mPlatformWifi.releaseNanDiscoveryEvent(event); |
| } |
| |
| bool WifiRequestManager::nanSubscribe( |
| Nanoapp *nanoapp, const struct chreWifiNanSubscribeConfig *config, |
| const void *cookie) { |
| CHRE_ASSERT(nanoapp); |
| |
| bool success = false; |
| |
| if (!areRequiredSettingsEnabled()) { |
| success = true; |
| postNanAsyncResultEvent( |
| nanoapp->getInstanceId(), CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE, |
| false /*success*/, CHRE_ERROR_FUNCTION_DISABLED, cookie); |
| } else { |
| if (!mPendingNanSubscribeRequests.emplace()) { |
| LOG_OOM(); |
| } else { |
| auto &req = mPendingNanSubscribeRequests.back(); |
| req.nanoappInstanceId = nanoapp->getInstanceId(); |
| req.cookie = cookie; |
| if (!copyNanSubscribeConfigToRequest(req, config)) { |
| LOG_OOM(); |
| } |
| |
| if (mNanIsAvailable) { |
| if (mPendingNanSubscribeRequests.size() == 1) { |
| // First in line; dispatch request immediately. |
| success = mPlatformWifi.nanSubscribe(config); |
| if (!success) { |
| mPendingNanSubscribeRequests.pop_back(); |
| } |
| } else { |
| success = true; |
| } |
| } else { |
| success = true; |
| sendNanConfiguration(true /*enable*/); |
| } |
| } |
| } |
| return success; |
| } |
| |
| bool WifiRequestManager::nanSubscribeCancel(Nanoapp *nanoapp, |
| uint32_t subscriptionId) { |
| bool success = false; |
| for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) { |
| if (mNanoappSubscriptions[i].subscriptionId == subscriptionId && |
| mNanoappSubscriptions[i].nanoappInstanceId == |
| nanoapp->getInstanceId()) { |
| success = mPlatformWifi.nanSubscribeCancel(subscriptionId); |
| break; |
| } |
| } |
| |
| if (!success) { |
| LOGE("Failed to cancel subscription %" PRIu32 " for napp %" PRIu16, |
| subscriptionId, nanoapp->getInstanceId()); |
| } |
| |
| return success; |
| } |
| |
| bool WifiRequestManager::copyNanSubscribeConfigToRequest( |
| PendingNanSubscribeRequest &req, |
| const struct chreWifiNanSubscribeConfig *config) { |
| bool success = false; |
| req.type = config->subscribeType; |
| |
| if (req.service.copy_array(config->service, |
| std::strlen(config->service) + 1) && |
| req.serviceSpecificInfo.copy_array(config->serviceSpecificInfo, |
| config->serviceSpecificInfoSize) && |
| req.matchFilter.copy_array(config->matchFilter, |
| config->matchFilterLength)) { |
| success = true; |
| } else { |
| LOG_OOM(); |
| } |
| |
| return success; |
| } |
| |
| void WifiRequestManager::buildNanSubscribeConfigFromRequest( |
| const PendingNanSubscribeRequest &req, |
| struct chreWifiNanSubscribeConfig *config) { |
| config->subscribeType = req.type; |
| config->service = req.service.data(); |
| config->serviceSpecificInfo = req.serviceSpecificInfo.data(); |
| config->serviceSpecificInfoSize = |
| static_cast<uint32_t>(req.serviceSpecificInfo.size()); |
| config->matchFilter = req.matchFilter.data(); |
| config->matchFilterLength = static_cast<uint32_t>(req.matchFilter.size()); |
| } |
| |
| inline bool WifiRequestManager::areRequiredSettingsEnabled() { |
| SettingManager &settingManager = |
| EventLoopManagerSingleton::get()->getSettingManager(); |
| return settingManager.getSettingEnabled(Setting::LOCATION) && |
| settingManager.getSettingEnabled(Setting::WIFI_AVAILABLE); |
| } |
| |
| void WifiRequestManager::cancelNanSubscriptionsAndInformNanoapps() { |
| for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) { |
| chreWifiNanSessionTerminatedEvent *event = |
| memoryAlloc<chreWifiNanSessionTerminatedEvent>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| } else { |
| event->id = mNanoappSubscriptions[i].subscriptionId; |
| event->reason = CHRE_ERROR_FUNCTION_DISABLED; |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED, event, freeEventDataCallback, |
| mNanoappSubscriptions[i].nanoappInstanceId); |
| } |
| } |
| mNanoappSubscriptions.clear(); |
| } |
| |
| void WifiRequestManager::cancelNanPendingRequestsAndInformNanoapps() { |
| for (size_t i = 0; i < mPendingNanSubscribeRequests.size(); ++i) { |
| auto &req = mPendingNanSubscribeRequests[i]; |
| chreAsyncResult *event = memoryAlloc<chreAsyncResult>(); |
| if (event == nullptr) { |
| LOG_OOM(); |
| break; |
| } else { |
| event->requestType = CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE; |
| event->success = false; |
| event->errorCode = CHRE_ERROR_FUNCTION_DISABLED; |
| event->cookie = req.cookie; |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback, |
| req.nanoappInstanceId); |
| } |
| } |
| mPendingNanSubscribeRequests.clear(); |
| } |
| |
| void WifiRequestManager::handleNanAvailabilitySync(bool available) { |
| PendingNanConfigType nanState = |
| available ? PendingNanConfigType::ENABLE : PendingNanConfigType::DISABLE; |
| mNanIsAvailable = available; |
| |
| if (nanState == mNanConfigRequestToHostPendingType) { |
| mNanConfigRequestToHostPending = false; |
| mNanConfigRequestToHostPendingType = PendingNanConfigType::UNKNOWN; |
| } |
| |
| if (available) { |
| dispatchQueuedNanSubscribeRequestWithRetry(); |
| } else { |
| cancelNanPendingRequestsAndInformNanoapps(); |
| cancelNanSubscriptionsAndInformNanoapps(); |
| } |
| } |
| |
| void WifiRequestManager::updateNanAvailability(bool available) { |
| auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) { |
| bool cbAvail = NestedDataPtr<bool>(data); |
| EventLoopManagerSingleton::get() |
| ->getWifiRequestManager() |
| .handleNanAvailabilitySync(cbAvail); |
| }; |
| |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::WifiNanAvailabilityEvent, |
| NestedDataPtr<bool>(available), callback); |
| } |
| |
| void WifiRequestManager::sendNanConfiguration(bool enable) { |
| PendingNanConfigType requiredState = |
| enable ? PendingNanConfigType::ENABLE : PendingNanConfigType::DISABLE; |
| if (!mNanConfigRequestToHostPending || |
| (mNanConfigRequestToHostPendingType != requiredState)) { |
| mNanConfigRequestToHostPending = true; |
| mNanConfigRequestToHostPendingType = requiredState; |
| EventLoopManagerSingleton::get() |
| ->getHostCommsManager() |
| .sendNanConfiguration(enable); |
| } |
| } |
| |
| void WifiRequestManager::onSettingChanged(Setting setting, bool enabled) { |
| if ((setting == Setting::WIFI_AVAILABLE) && !enabled) { |
| cancelNanPendingRequestsAndInformNanoapps(); |
| cancelNanSubscriptionsAndInformNanoapps(); |
| } |
| } |
| |
| } // namespace chre |