• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cinttypes>
18 #include <cstddef>
19 #include <cstring>
20 
21 #include "chre/core/event_loop_manager.h"
22 #include "chre/core/settings.h"
23 #include "chre/core/wifi_request_manager.h"
24 #include "chre/platform/fatal_error.h"
25 #include "chre/platform/log.h"
26 #include "chre/platform/system_time.h"
27 #include "chre/util/system/debug_dump.h"
28 #include "chre_api/chre/version.h"
29 
30 namespace chre {
31 
WifiRequestManager()32 WifiRequestManager::WifiRequestManager() {
33   // Reserve space for at least one scan monitoring nanoapp. This ensures that
34   // the first asynchronous push_back will succeed. Future push_backs will be
35   // synchronous and failures will be returned to the client.
36   if (!mScanMonitorNanoapps.reserve(1)) {
37     FATAL_ERROR_OOM();
38   }
39 }
40 
init()41 void WifiRequestManager::init() {
42   mPlatformWifi.init();
43 }
44 
getCapabilities()45 uint32_t WifiRequestManager::getCapabilities() {
46   return mPlatformWifi.getCapabilities();
47 }
48 
configureScanMonitor(Nanoapp * nanoapp,bool enable,const void * cookie)49 bool WifiRequestManager::configureScanMonitor(Nanoapp *nanoapp, bool enable,
50                                               const void *cookie) {
51   CHRE_ASSERT(nanoapp);
52 
53   bool success = false;
54   uint32_t instanceId = nanoapp->getInstanceId();
55   bool hasScanMonitorRequest = nanoappHasScanMonitorRequest(instanceId);
56   if (!mPendingScanMonitorRequests.empty()) {
57     success = addScanMonitorRequestToQueue(nanoapp, enable, cookie);
58   } else if (scanMonitorIsInRequestedState(enable, hasScanMonitorRequest)) {
59     // The scan monitor is already in the requested state. A success event can
60     // be posted immediately.
61     success = postScanMonitorAsyncResultEvent(instanceId, true /* success */,
62                                               enable, CHRE_ERROR_NONE, cookie);
63   } else if (scanMonitorStateTransitionIsRequired(enable,
64                                                   hasScanMonitorRequest)) {
65     success = addScanMonitorRequestToQueue(nanoapp, enable, cookie);
66     if (success) {
67       success = mPlatformWifi.configureScanMonitor(enable);
68       if (!success) {
69         mPendingScanMonitorRequests.pop_back();
70         LOGE("Failed to enable the scan monitor for nanoapp instance %" PRIu32,
71              instanceId);
72       }
73     }
74   } else {
75     CHRE_ASSERT_LOG(false, "Invalid scan monitor configuration");
76   }
77 
78   return success;
79 }
80 
requestRanging(Nanoapp * nanoapp,const struct chreWifiRangingParams * params,const void * cookie)81 bool WifiRequestManager::requestRanging(
82     Nanoapp *nanoapp, const struct chreWifiRangingParams *params,
83     const void *cookie) {
84   CHRE_ASSERT(nanoapp);
85 
86   bool success = false;
87   if (!mPendingRangingRequests.emplace()) {
88     LOGE("Can't issue new RTT request; pending queue full");
89   } else {
90     PendingRangingRequest &req = mPendingRangingRequests.back();
91     req.nanoappInstanceId = nanoapp->getInstanceId();
92     req.cookie = cookie;
93 
94     if (mPendingRangingRequests.size() == 1) {
95       // First in line; dispatch request immediately
96       if (getSettingState(Setting::LOCATION) == SettingState::DISABLED) {
97         // Treat as success but post async failure per API.
98         success = true;
99         postRangingAsyncResult(CHRE_ERROR_FUNCTION_DISABLED);
100         mPendingRangingRequests.pop_back();
101       } else if (!mPlatformWifi.requestRanging(params)) {
102         LOGE("WiFi RTT request failed");
103         mPendingRangingRequests.pop_back();
104       } else {
105         success = true;
106         mRangingResponseTimeout =
107             SystemTime::getMonotonicTime() +
108             Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
109       }
110     } else {
111       // Dispatch request later, after prior requests finish
112       // TODO(b/65331248): use a timer to ensure the platform is meeting its
113       // contract
114       CHRE_ASSERT_LOG(SystemTime::getMonotonicTime() <= mRangingResponseTimeout,
115                       "WiFi platform didn't give callback in time");
116       success =
117           req.targetList.copy_array(params->targetList, params->targetListLen);
118       if (!success) {
119         LOG_OOM();
120         mPendingRangingRequests.pop_back();
121       }
122     }
123   }
124 
125   return success;
126 }
127 
requestScan(Nanoapp * nanoapp,const struct chreWifiScanParams * params,const void * cookie)128 bool WifiRequestManager::requestScan(Nanoapp *nanoapp,
129                                      const struct chreWifiScanParams *params,
130                                      const void *cookie) {
131   CHRE_ASSERT(nanoapp);
132 
133   // TODO(b/65331248): replace with a timer to actively check response timeout
134   bool timedOut =
135       (mScanRequestingNanoappInstanceId.has_value() &&
136        mLastScanRequestTime + Nanoseconds(CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS) <
137            SystemTime::getMonotonicTime());
138   if (timedOut) {
139     LOGE("Scan request async response timed out");
140     mScanRequestingNanoappInstanceId.reset();
141   }
142 
143   // Handle compatibility with nanoapps compiled against API v1.1, which doesn't
144   // include the radioChainPref parameter in chreWifiScanParams
145   struct chreWifiScanParams paramsCompat;
146   if (nanoapp->getTargetApiVersion() < CHRE_API_VERSION_1_2) {
147     memcpy(&paramsCompat, params, offsetof(chreWifiScanParams, radioChainPref));
148     paramsCompat.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
149     params = &paramsCompat;
150   }
151 
152   bool success = false;
153   if (mScanRequestingNanoappInstanceId.has_value()) {
154     LOGE("Active wifi scan request made while a request is in flight");
155   } else {
156     success = mPlatformWifi.requestScan(params);
157     if (!success) {
158       LOGE("Wifi scan request failed");
159     } else {
160       mScanRequestingNanoappInstanceId = nanoapp->getInstanceId();
161       mScanRequestingNanoappCookie = cookie;
162       mLastScanRequestTime = SystemTime::getMonotonicTime();
163     }
164   }
165 
166   if (success) {
167     addWifiScanRequestLog(nanoapp->getInstanceId(), params);
168   }
169 
170   return success;
171 }
172 
handleScanMonitorStateChange(bool enabled,uint8_t errorCode)173 void WifiRequestManager::handleScanMonitorStateChange(bool enabled,
174                                                       uint8_t errorCode) {
175   struct CallbackState {
176     bool enabled;
177     uint8_t errorCode;
178   };
179 
180   auto *cbState = memoryAlloc<CallbackState>();
181   if (cbState == nullptr) {
182     LOG_OOM();
183   } else {
184     cbState->enabled = enabled;
185     cbState->errorCode = errorCode;
186 
187     auto callback = [](uint16_t /* eventType */, void *eventData) {
188       auto *state = static_cast<CallbackState *>(eventData);
189       EventLoopManagerSingleton::get()
190           ->getWifiRequestManager()
191           .handleScanMonitorStateChangeSync(state->enabled, state->errorCode);
192       memoryFree(state);
193     };
194 
195     EventLoopManagerSingleton::get()->deferCallback(
196         SystemCallbackType::WifiScanMonitorStateChange, cbState, callback);
197   }
198 }
199 
handleScanResponse(bool pending,uint8_t errorCode)200 void WifiRequestManager::handleScanResponse(bool pending, uint8_t errorCode) {
201   struct CallbackState {
202     bool pending;
203     uint8_t errorCode;
204   };
205 
206   auto *cbState = memoryAlloc<CallbackState>();
207   if (cbState == nullptr) {
208     LOG_OOM();
209   } else {
210     cbState->pending = pending;
211     cbState->errorCode = errorCode;
212 
213     auto callback = [](uint16_t /* eventType */, void *eventData) {
214       auto *state = static_cast<CallbackState *>(eventData);
215       EventLoopManagerSingleton::get()
216           ->getWifiRequestManager()
217           .handleScanResponseSync(state->pending, state->errorCode);
218       memoryFree(state);
219     };
220 
221     EventLoopManagerSingleton::get()->deferCallback(
222         SystemCallbackType::WifiRequestScanResponse, cbState, callback);
223   }
224 }
225 
handleRangingEvent(uint8_t errorCode,struct chreWifiRangingEvent * event)226 void WifiRequestManager::handleRangingEvent(
227     uint8_t errorCode, struct chreWifiRangingEvent *event) {
228   // Use two different callbacks to avoid needing a temporary allocation to
229   // carry the error code into the event loop context
230   if (errorCode != CHRE_ERROR_NONE) {
231     // Enables passing the error code through the event data pointer to avoid
232     // allocating memory
233     union NestedErrorCode {
234       void *eventData;
235       uint8_t errorCode;
236     };
237 
238     auto errorCb = [](uint16_t /* eventType */, void *eventData) {
239       NestedErrorCode cbErrorCode;
240       cbErrorCode.eventData = eventData;
241       EventLoopManagerSingleton::get()
242           ->getWifiRequestManager()
243           .handleRangingEventSync(cbErrorCode.errorCode, nullptr);
244     };
245 
246     NestedErrorCode error = {};
247     error.errorCode = errorCode;
248     EventLoopManagerSingleton::get()->deferCallback(
249         SystemCallbackType::WifiHandleFailedRanging, error.eventData, errorCb);
250   } else {
251     auto successCb = [](uint16_t /* eventType */, void *eventData) {
252       auto *rttEvent = static_cast<struct chreWifiRangingEvent *>(eventData);
253       EventLoopManagerSingleton::get()
254           ->getWifiRequestManager()
255           .handleRangingEventSync(CHRE_ERROR_NONE, rttEvent);
256     };
257 
258     EventLoopManagerSingleton::get()->deferCallback(
259         SystemCallbackType::WifiHandleRangingEvent, event, successCb);
260   }
261 }
262 
handleScanEvent(chreWifiScanEvent * event)263 void WifiRequestManager::handleScanEvent(chreWifiScanEvent *event) {
264   auto callback = [](uint16_t eventType, void *eventData) {
265     chreWifiScanEvent *scanEvent = static_cast<chreWifiScanEvent *>(eventData);
266     EventLoopManagerSingleton::get()
267         ->getWifiRequestManager()
268         .postScanEventFatal(scanEvent);
269   };
270 
271   EventLoopManagerSingleton::get()->deferCallback(
272       SystemCallbackType::WifiHandleScanEvent, event, callback);
273 }
274 
logStateToBuffer(DebugDumpWrapper & debugDump) const275 void WifiRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
276   debugDump.print("\nWifi: scan monitor %s\n",
277                   scanMonitorIsEnabled() ? "enabled" : "disabled");
278 
279   if (scanMonitorIsEnabled()) {
280     debugDump.print(" Wifi scan monitor enabled nanoapps:\n");
281     for (const auto &instanceId : mScanMonitorNanoapps) {
282       debugDump.print("  nappId=%" PRIu32 "\n", instanceId);
283     }
284   }
285 
286   if (mScanRequestingNanoappInstanceId.has_value()) {
287     debugDump.print(" Wifi request pending nanoappId=%" PRIu32 "\n",
288                     mScanRequestingNanoappInstanceId.value());
289   }
290 
291   if (!mPendingScanMonitorRequests.empty()) {
292     debugDump.print(" Wifi transition queue:\n");
293     for (const auto &transition : mPendingScanMonitorRequests) {
294       debugDump.print("  enable=%s nappId=%" PRIu32 "\n",
295                       transition.enable ? "true" : "false",
296                       transition.nanoappInstanceId);
297     }
298   }
299 
300   debugDump.print(" Last %zu wifi scan requests:\n",
301                   mWifiScanRequestLogs.size());
302   static_assert(kNumWifiRequestLogs <= INT8_MAX,
303                 "kNumWifiRequestLogs must be <= INT8_MAX");
304   for (int8_t i = static_cast<int8_t>(mWifiScanRequestLogs.size()) - 1; i >= 0;
305        i--) {
306     const auto &log = mWifiScanRequestLogs[static_cast<size_t>(i)];
307     debugDump.print("  ts=%" PRIu64 " nappId=%" PRIu32 " scanType=%" PRIu8
308                     " maxScanAge(ms)=%" PRIu64 "\n",
309                     log.timestamp.toRawNanoseconds(), log.instanceId,
310                     log.scanType, log.maxScanAgeMs.getMilliseconds());
311   }
312 }
313 
scanMonitorIsEnabled() const314 bool WifiRequestManager::scanMonitorIsEnabled() const {
315   return !mScanMonitorNanoapps.empty();
316 }
317 
nanoappHasScanMonitorRequest(uint32_t instanceId,size_t * nanoappIndex) const318 bool WifiRequestManager::nanoappHasScanMonitorRequest(
319     uint32_t instanceId, size_t *nanoappIndex) const {
320   size_t index = mScanMonitorNanoapps.find(instanceId);
321   bool hasScanMonitorRequest = (index != mScanMonitorNanoapps.size());
322   if (hasScanMonitorRequest && nanoappIndex != nullptr) {
323     *nanoappIndex = index;
324   }
325 
326   return hasScanMonitorRequest;
327 }
328 
scanMonitorIsInRequestedState(bool requestedState,bool nanoappHasRequest) const329 bool WifiRequestManager::scanMonitorIsInRequestedState(
330     bool requestedState, bool nanoappHasRequest) const {
331   return (requestedState == scanMonitorIsEnabled() ||
332           (!requestedState &&
333            (!nanoappHasRequest || mScanMonitorNanoapps.size() > 1)));
334 }
335 
scanMonitorStateTransitionIsRequired(bool requestedState,bool nanoappHasRequest) const336 bool WifiRequestManager::scanMonitorStateTransitionIsRequired(
337     bool requestedState, bool nanoappHasRequest) const {
338   return ((requestedState && mScanMonitorNanoapps.empty()) ||
339           (!requestedState && nanoappHasRequest &&
340            mScanMonitorNanoapps.size() == 1));
341 }
342 
addScanMonitorRequestToQueue(Nanoapp * nanoapp,bool enable,const void * cookie)343 bool WifiRequestManager::addScanMonitorRequestToQueue(Nanoapp *nanoapp,
344                                                       bool enable,
345                                                       const void *cookie) {
346   PendingScanMonitorRequest scanMonitorStateTransition;
347   scanMonitorStateTransition.nanoappInstanceId = nanoapp->getInstanceId();
348   scanMonitorStateTransition.cookie = cookie;
349   scanMonitorStateTransition.enable = enable;
350 
351   bool success = mPendingScanMonitorRequests.push(scanMonitorStateTransition);
352   if (!success) {
353     LOGW("Too many scan monitor state transitions");
354   }
355 
356   return success;
357 }
358 
updateNanoappScanMonitoringList(bool enable,uint32_t instanceId)359 bool WifiRequestManager::updateNanoappScanMonitoringList(bool enable,
360                                                          uint32_t instanceId) {
361   bool success = true;
362   Nanoapp *nanoapp =
363       EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
364           instanceId);
365   if (nanoapp == nullptr) {
366     LOGW("Failed to update scan monitoring list for non-existent nanoapp");
367   } else {
368     size_t nanoappIndex;
369     bool hasExistingRequest =
370         nanoappHasScanMonitorRequest(instanceId, &nanoappIndex);
371     if (enable) {
372       if (!hasExistingRequest) {
373         // The scan monitor was successfully enabled for this nanoapp and
374         // there is no existing request. Add it to the list of scan monitoring
375         // nanoapps.
376         success = mScanMonitorNanoapps.push_back(instanceId);
377         if (!success) {
378           LOG_OOM();
379         } else {
380           nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
381         }
382       }
383     } else if (hasExistingRequest) {
384       // The scan monitor was successfully disabled for a previously enabled
385       // nanoapp. Remove it from the list of scan monitoring nanoapps.
386       mScanMonitorNanoapps.erase(nanoappIndex);
387       nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
388     }  // else disabling an inactive request, treat as success per the CHRE API.
389   }
390 
391   return success;
392 }
393 
postScanMonitorAsyncResultEvent(uint32_t nanoappInstanceId,bool success,bool enable,uint8_t errorCode,const void * cookie)394 bool WifiRequestManager::postScanMonitorAsyncResultEvent(
395     uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
396     const void *cookie) {
397   // Allocate and post an event to the nanoapp requesting wifi.
398   bool eventPosted = false;
399   if (!success || updateNanoappScanMonitoringList(enable, nanoappInstanceId)) {
400     chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
401     if (event == nullptr) {
402       LOG_OOM();
403     } else {
404       event->requestType = CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR;
405       event->success = success;
406       event->errorCode = errorCode;
407       event->reserved = 0;
408       event->cookie = cookie;
409 
410       // Post the event.
411       eventPosted =
412           EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
413               CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
414               nanoappInstanceId);
415       if (!eventPosted) {
416         memoryFree(event);
417       }
418     }
419   }
420 
421   return eventPosted;
422 }
423 
postScanMonitorAsyncResultEventFatal(uint32_t nanoappInstanceId,bool success,bool enable,uint8_t errorCode,const void * cookie)424 void WifiRequestManager::postScanMonitorAsyncResultEventFatal(
425     uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
426     const void *cookie) {
427   if (!postScanMonitorAsyncResultEvent(nanoappInstanceId, success, enable,
428                                        errorCode, cookie)) {
429     FATAL_ERROR("Failed to send WiFi scan monitor async result event");
430   }
431 }
432 
postScanRequestAsyncResultEvent(uint32_t nanoappInstanceId,bool success,uint8_t errorCode,const void * cookie)433 bool WifiRequestManager::postScanRequestAsyncResultEvent(
434     uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
435     const void *cookie) {
436   bool eventPosted = false;
437   chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
438   if (event == nullptr) {
439     LOG_OOM();
440   } else {
441     event->requestType = CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN;
442     event->success = success;
443     event->errorCode = errorCode;
444     event->reserved = 0;
445     event->cookie = cookie;
446 
447     // Post the event.
448     eventPosted =
449         EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
450             CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
451             nanoappInstanceId);
452   }
453 
454   return eventPosted;
455 }
456 
postScanRequestAsyncResultEventFatal(uint32_t nanoappInstanceId,bool success,uint8_t errorCode,const void * cookie)457 void WifiRequestManager::postScanRequestAsyncResultEventFatal(
458     uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
459     const void *cookie) {
460   if (!postScanRequestAsyncResultEvent(nanoappInstanceId, success, errorCode,
461                                        cookie)) {
462     FATAL_ERROR("Failed to send WiFi scan request async result event");
463   }
464 }
465 
postScanEventFatal(chreWifiScanEvent * event)466 void WifiRequestManager::postScanEventFatal(chreWifiScanEvent *event) {
467   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
468       CHRE_EVENT_WIFI_SCAN_RESULT, event, freeWifiScanEventCallback);
469 }
470 
handleScanMonitorStateChangeSync(bool enabled,uint8_t errorCode)471 void WifiRequestManager::handleScanMonitorStateChangeSync(bool enabled,
472                                                           uint8_t errorCode) {
473   // Success is defined as having no errors ... in life ༼ つ ◕_◕ ༽つ
474   bool success = (errorCode == CHRE_ERROR_NONE);
475 
476   // TODO(b/62904616): re-enable this assertion
477   // CHRE_ASSERT_LOG(!mScanMonitorStateTransitions.empty(),
478   //                "handleScanMonitorStateChangeSync called with no
479   //                transitions");
480   if (mPendingScanMonitorRequests.empty()) {
481     LOGE(
482         "WiFi PAL error: handleScanMonitorStateChangeSync called with no "
483         "transitions (enabled %d errorCode %" PRIu8 ")",
484         enabled, errorCode);
485   }
486 
487   // Always check the front of the queue.
488   if (!mPendingScanMonitorRequests.empty()) {
489     const auto &stateTransition = mPendingScanMonitorRequests.front();
490     success &= (stateTransition.enable == enabled);
491     postScanMonitorAsyncResultEventFatal(stateTransition.nanoappInstanceId,
492                                          success, stateTransition.enable,
493                                          errorCode, stateTransition.cookie);
494     mPendingScanMonitorRequests.pop();
495   }
496 
497   while (!mPendingScanMonitorRequests.empty()) {
498     const auto &stateTransition = mPendingScanMonitorRequests.front();
499     bool hasScanMonitorRequest =
500         nanoappHasScanMonitorRequest(stateTransition.nanoappInstanceId);
501     if (scanMonitorIsInRequestedState(stateTransition.enable,
502                                       hasScanMonitorRequest)) {
503       // We are already in the target state so just post an event indicating
504       // success
505       postScanMonitorAsyncResultEventFatal(
506           stateTransition.nanoappInstanceId, true /* success */,
507           stateTransition.enable, CHRE_ERROR_NONE, stateTransition.cookie);
508     } else if (scanMonitorStateTransitionIsRequired(stateTransition.enable,
509                                                     hasScanMonitorRequest)) {
510       if (mPlatformWifi.configureScanMonitor(stateTransition.enable)) {
511         break;
512       } else {
513         postScanMonitorAsyncResultEventFatal(
514             stateTransition.nanoappInstanceId, false /* success */,
515             stateTransition.enable, CHRE_ERROR, stateTransition.cookie);
516       }
517     } else {
518       CHRE_ASSERT_LOG(false, "Invalid scan monitor state");
519       break;
520     }
521 
522     mPendingScanMonitorRequests.pop();
523   }
524 }
525 
handleScanResponseSync(bool pending,uint8_t errorCode)526 void WifiRequestManager::handleScanResponseSync(bool pending,
527                                                 uint8_t errorCode) {
528   // TODO(b/65206783): re-enable this assertion
529   // CHRE_ASSERT_LOG(mScanRequestingNanoappInstanceId.has_value(),
530   //                "handleScanResponseSync called with no outstanding
531   //                request");
532   if (!mScanRequestingNanoappInstanceId.has_value()) {
533     LOGE("handleScanResponseSync called with no outstanding request");
534   }
535 
536   // TODO: raise this to CHRE_ASSERT_LOG
537   if (!pending && errorCode == CHRE_ERROR_NONE) {
538     LOGE("Invalid wifi scan response");
539     errorCode = CHRE_ERROR;
540   }
541 
542   if (mScanRequestingNanoappInstanceId.has_value()) {
543     bool success = (pending && errorCode == CHRE_ERROR_NONE);
544     if (!success) {
545       LOGW("Wifi scan request failed: pending %d, errorCode %" PRIu8, pending,
546            errorCode);
547     }
548     postScanRequestAsyncResultEventFatal(*mScanRequestingNanoappInstanceId,
549                                          success, errorCode,
550                                          mScanRequestingNanoappCookie);
551 
552     // Set a flag to indicate that results may be pending.
553     mScanRequestResultsArePending = pending;
554 
555     if (pending) {
556       Nanoapp *nanoapp =
557           EventLoopManagerSingleton::get()
558               ->getEventLoop()
559               .findNanoappByInstanceId(*mScanRequestingNanoappInstanceId);
560       if (nanoapp == nullptr) {
561         LOGW("Received WiFi scan response for unknown nanoapp");
562       } else {
563         nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
564       }
565     } else {
566       // If the scan results are not pending, clear the nanoapp instance ID.
567       // Otherwise, wait for the results to be delivered and then clear the
568       // instance ID.
569       mScanRequestingNanoappInstanceId.reset();
570     }
571   }
572 }
573 
postRangingAsyncResult(uint8_t errorCode)574 bool WifiRequestManager::postRangingAsyncResult(uint8_t errorCode) {
575   bool eventPosted = false;
576 
577   if (mPendingRangingRequests.empty()) {
578     LOGE("Unexpected ranging event callback");
579   } else {
580     auto *event = memoryAlloc<struct chreAsyncResult>();
581     if (event == nullptr) {
582       LOG_OOM();
583     } else {
584       const PendingRangingRequest &req = mPendingRangingRequests.front();
585 
586       event->requestType = CHRE_WIFI_REQUEST_TYPE_RANGING;
587       event->success = (errorCode == CHRE_ERROR_NONE);
588       event->errorCode = errorCode;
589       event->reserved = 0;
590       event->cookie = req.cookie;
591 
592       eventPosted =
593           EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
594               CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
595               req.nanoappInstanceId);
596       if (!eventPosted) {
597         memoryFree(event);
598       }
599     }
600   }
601 
602   return eventPosted;
603 }
604 
dispatchQueuedRangingRequest()605 bool WifiRequestManager::dispatchQueuedRangingRequest() {
606   const PendingRangingRequest &req = mPendingRangingRequests.front();
607   struct chreWifiRangingParams params = {};
608   params.targetListLen = static_cast<uint8_t>(req.targetList.size());
609   params.targetList = req.targetList.data();
610 
611   bool success = false;
612   if (getSettingState(Setting::LOCATION) == SettingState::DISABLED) {
613     postRangingAsyncResult(CHRE_ERROR_FUNCTION_DISABLED);
614     mPendingRangingRequests.pop();
615   } else if (!mPlatformWifi.requestRanging(&params)) {
616     LOGE("Failed to issue queued ranging result");
617     postRangingAsyncResult(CHRE_ERROR);
618     mPendingRangingRequests.pop();
619   } else {
620     success = true;
621     mRangingResponseTimeout = SystemTime::getMonotonicTime() +
622                               Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
623   }
624 
625   return success;
626 }
627 
handleRangingEventSync(uint8_t errorCode,struct chreWifiRangingEvent * event)628 void WifiRequestManager::handleRangingEventSync(
629     uint8_t errorCode, struct chreWifiRangingEvent *event) {
630   if (getSettingState(Setting::LOCATION) == SettingState::DISABLED) {
631     errorCode = CHRE_ERROR_FUNCTION_DISABLED;
632   }
633 
634   if (postRangingAsyncResult(errorCode)) {
635     if (errorCode != CHRE_ERROR_NONE) {
636       LOGW("RTT ranging failed with error %d", errorCode);
637       if (event != nullptr) {
638         freeWifiRangingEventCallback(CHRE_EVENT_WIFI_RANGING_RESULT, event);
639       }
640     } else {
641       EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
642           CHRE_EVENT_WIFI_RANGING_RESULT, event, freeWifiRangingEventCallback,
643           mPendingRangingRequests.front().nanoappInstanceId);
644     }
645     mPendingRangingRequests.pop();
646   }
647 
648   // If we have any pending requests, try issuing them to the platform until the
649   // first one succeeds
650   while (!mPendingRangingRequests.empty() && !dispatchQueuedRangingRequest())
651     ;
652 }
653 
handleFreeWifiScanEvent(chreWifiScanEvent * scanEvent)654 void WifiRequestManager::handleFreeWifiScanEvent(chreWifiScanEvent *scanEvent) {
655   if (mScanRequestResultsArePending) {
656     // Reset the event distribution logic once an entire scan event has been
657     // received and processed by the nanoapp requesting the scan event.
658     mScanEventResultCountAccumulator += scanEvent->resultCount;
659     if (mScanEventResultCountAccumulator >= scanEvent->resultTotal) {
660       mScanEventResultCountAccumulator = 0;
661       mScanRequestResultsArePending = false;
662     }
663 
664     if (!mScanRequestResultsArePending &&
665         mScanRequestingNanoappInstanceId.has_value()) {
666       Nanoapp *nanoapp =
667           EventLoopManagerSingleton::get()
668               ->getEventLoop()
669               .findNanoappByInstanceId(*mScanRequestingNanoappInstanceId);
670       if (nanoapp == nullptr) {
671         LOGW("Attempted to unsubscribe unknown nanoapp from WiFi scan events");
672       } else if (!nanoappHasScanMonitorRequest(
673                      *mScanRequestingNanoappInstanceId)) {
674         nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
675       }
676 
677       mScanRequestingNanoappInstanceId.reset();
678     }
679   }
680 
681   mPlatformWifi.releaseScanEvent(scanEvent);
682 }
683 
addWifiScanRequestLog(uint32_t nanoappInstanceId,const chreWifiScanParams * params)684 void WifiRequestManager::addWifiScanRequestLog(
685     uint32_t nanoappInstanceId, const chreWifiScanParams *params) {
686   mWifiScanRequestLogs.kick_push(
687       WifiScanRequestLog(SystemTime::getMonotonicTime(), nanoappInstanceId,
688                          static_cast<chreWifiScanType>(params->scanType),
689                          static_cast<Milliseconds>(params->maxScanAgeMs)));
690 }
691 
freeWifiScanEventCallback(uint16_t eventType,void * eventData)692 void WifiRequestManager::freeWifiScanEventCallback(uint16_t eventType,
693                                                    void *eventData) {
694   chreWifiScanEvent *scanEvent = static_cast<chreWifiScanEvent *>(eventData);
695   EventLoopManagerSingleton::get()
696       ->getWifiRequestManager()
697       .handleFreeWifiScanEvent(scanEvent);
698 }
699 
freeWifiRangingEventCallback(uint16_t eventType,void * eventData)700 void WifiRequestManager::freeWifiRangingEventCallback(uint16_t eventType,
701                                                       void *eventData) {
702   auto *event = static_cast<struct chreWifiRangingEvent *>(eventData);
703   EventLoopManagerSingleton::get()
704       ->getWifiRequestManager()
705       .mPlatformWifi.releaseRangingEvent(event);
706 }
707 
708 }  // namespace chre
709