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