• 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/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         LOGE("Couldn't make copy of target list");
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     LOGE("Failed to allocate callback state for scan monitor state change");
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     LOGE("Failed to allocate callback state for wifi scan response");
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 bool WifiRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos,
261                                           size_t bufferSize) const {
262   bool success = debugDumpPrint(buffer, bufferPos, bufferSize, "\nWifi: "
263                                 "scan monitor %s\n", scanMonitorIsEnabled() ?
264                                 "enabled" : "disabled");
265 
266   success &= debugDumpPrint(buffer, bufferPos, bufferSize,
267                             " Wifi scan monitor enabled nanoapps:\n");
268   for (const auto& instanceId : mScanMonitorNanoapps) {
269     success &= debugDumpPrint(buffer, bufferPos, bufferSize,
270                               "  nanoappId=%" PRIu32 "\n", instanceId);
271   }
272 
273   if (mScanRequestingNanoappInstanceId.has_value()) {
274     success &= debugDumpPrint(buffer, bufferPos, bufferSize,
275                               " Wifi request pending nanoappId=%" PRIu32 "\n",
276                               mScanRequestingNanoappInstanceId.value());
277   }
278 
279   success &= debugDumpPrint(buffer, bufferPos, bufferSize,
280                             " Wifi transition queue:\n");
281   for (const auto& transition : mPendingScanMonitorRequests) {
282     success &= debugDumpPrint(buffer, bufferPos, bufferSize,
283                               "  enable=%s nanoappId=%" PRIu32 "\n",
284                               transition.enable ? "true" : "false",
285                               transition.nanoappInstanceId);
286   }
287 
288   return success;
289 }
290 
scanMonitorIsEnabled() const291 bool WifiRequestManager::scanMonitorIsEnabled() const {
292   return !mScanMonitorNanoapps.empty();
293 }
294 
nanoappHasScanMonitorRequest(uint32_t instanceId,size_t * nanoappIndex) const295 bool WifiRequestManager::nanoappHasScanMonitorRequest(
296     uint32_t instanceId, size_t *nanoappIndex) const {
297   size_t index = mScanMonitorNanoapps.find(instanceId);
298   bool hasScanMonitorRequest = (index != mScanMonitorNanoapps.size());
299   if (hasScanMonitorRequest && nanoappIndex != nullptr) {
300     *nanoappIndex = index;
301   }
302 
303   return hasScanMonitorRequest;
304 }
305 
scanMonitorIsInRequestedState(bool requestedState,bool nanoappHasRequest) const306 bool WifiRequestManager::scanMonitorIsInRequestedState(
307     bool requestedState, bool nanoappHasRequest) const {
308   return (requestedState == scanMonitorIsEnabled() || (!requestedState
309       && (!nanoappHasRequest || mScanMonitorNanoapps.size() > 1)));
310 }
311 
scanMonitorStateTransitionIsRequired(bool requestedState,bool nanoappHasRequest) const312 bool WifiRequestManager::scanMonitorStateTransitionIsRequired(
313     bool requestedState, bool nanoappHasRequest) const {
314   return ((requestedState && mScanMonitorNanoapps.empty())
315       || (!requestedState && nanoappHasRequest
316               && mScanMonitorNanoapps.size() == 1));
317 }
318 
addScanMonitorRequestToQueue(Nanoapp * nanoapp,bool enable,const void * cookie)319 bool WifiRequestManager::addScanMonitorRequestToQueue(Nanoapp *nanoapp,
320                                                       bool enable,
321                                                       const void *cookie) {
322   PendingScanMonitorRequest scanMonitorStateTransition;
323   scanMonitorStateTransition.nanoappInstanceId = nanoapp->getInstanceId();
324   scanMonitorStateTransition.cookie = cookie;
325   scanMonitorStateTransition.enable = enable;
326 
327   bool success = mPendingScanMonitorRequests.push(scanMonitorStateTransition);
328   if (!success) {
329     LOGW("Too many scan monitor state transitions");
330   }
331 
332   return success;
333 }
334 
updateNanoappScanMonitoringList(bool enable,uint32_t instanceId)335 bool WifiRequestManager::updateNanoappScanMonitoringList(bool enable,
336                                                          uint32_t instanceId) {
337   bool success = true;
338   Nanoapp *nanoapp = EventLoopManagerSingleton::get()->getEventLoop()
339       .findNanoappByInstanceId(instanceId);
340   if (nanoapp == nullptr) {
341     LOGW("Failed to update scan monitoring list for non-existent nanoapp");
342   } else {
343     size_t nanoappIndex;
344     bool hasExistingRequest = nanoappHasScanMonitorRequest(instanceId,
345                                                            &nanoappIndex);
346     if (enable) {
347       if (!hasExistingRequest) {
348         // The scan monitor was successfully enabled for this nanoapp and
349         // there is no existing request. Add it to the list of scan monitoring
350         // nanoapps.
351         success = mScanMonitorNanoapps.push_back(instanceId);
352         if (!success) {
353           LOGE("Failed to add nanoapp to the list of scan monitoring "
354                "nanoapps");
355         } else {
356           nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
357         }
358       }
359     } else {
360       if (!hasExistingRequest) {
361         success = false;
362         LOGE("Received a scan monitor state change for a non-existent nanoapp");
363       } else {
364         // The scan monitor was successfully disabled for a previously enabled
365         // nanoapp. Remove it from the list of scan monitoring nanoapps.
366         mScanMonitorNanoapps.erase(nanoappIndex);
367         nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
368       }
369     }
370   }
371 
372   return success;
373 }
374 
postScanMonitorAsyncResultEvent(uint32_t nanoappInstanceId,bool success,bool enable,uint8_t errorCode,const void * cookie)375 bool WifiRequestManager::postScanMonitorAsyncResultEvent(
376     uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
377     const void *cookie) {
378   // Allocate and post an event to the nanoapp requesting wifi.
379   bool eventPosted = false;
380   if (!success || updateNanoappScanMonitoringList(enable, nanoappInstanceId)) {
381     chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
382     if (event == nullptr) {
383       LOGE("Failed to allocate wifi scan monitor async result event");
384     } else {
385       event->requestType = CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR;
386       event->success = success;
387       event->errorCode = errorCode;
388       event->reserved = 0;
389       event->cookie = cookie;
390 
391       // Post the event.
392       eventPosted = EventLoopManagerSingleton::get()->getEventLoop()
393           .postEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
394                      kSystemInstanceId, nanoappInstanceId);
395       if (!eventPosted) {
396         memoryFree(event);
397       }
398     }
399   }
400 
401   return eventPosted;
402 }
403 
postScanMonitorAsyncResultEventFatal(uint32_t nanoappInstanceId,bool success,bool enable,uint8_t errorCode,const void * cookie)404 void WifiRequestManager::postScanMonitorAsyncResultEventFatal(
405     uint32_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
406     const void *cookie) {
407   if (!postScanMonitorAsyncResultEvent(nanoappInstanceId, success, enable,
408                                        errorCode, cookie)) {
409     FATAL_ERROR("Failed to send WiFi scan monitor async result event");
410   }
411 }
412 
postScanRequestAsyncResultEvent(uint32_t nanoappInstanceId,bool success,uint8_t errorCode,const void * cookie)413 bool WifiRequestManager::postScanRequestAsyncResultEvent(
414     uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
415     const void *cookie) {
416   bool eventPosted = false;
417   chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
418   if (event == nullptr) {
419     LOGE("Failed to allocate wifi scan request async result event");
420   } else {
421     event->requestType = CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN;
422     event->success = success;
423     event->errorCode = errorCode;
424     event->reserved = 0;
425     event->cookie = cookie;
426 
427     // Post the event.
428     eventPosted = EventLoopManagerSingleton::get()->getEventLoop()
429         .postEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
430                    kSystemInstanceId, nanoappInstanceId);
431   }
432 
433   return eventPosted;
434 }
435 
postScanRequestAsyncResultEventFatal(uint32_t nanoappInstanceId,bool success,uint8_t errorCode,const void * cookie)436 void WifiRequestManager::postScanRequestAsyncResultEventFatal(
437     uint32_t nanoappInstanceId, bool success, uint8_t errorCode,
438     const void *cookie) {
439   if (!postScanRequestAsyncResultEvent(nanoappInstanceId, success, errorCode,
440                                        cookie)) {
441     FATAL_ERROR("Failed to send WiFi scan request async result event");
442   }
443 }
444 
postScanEventFatal(chreWifiScanEvent * event)445 void WifiRequestManager::postScanEventFatal(chreWifiScanEvent *event) {
446   EventLoopManagerSingleton::get()->getEventLoop()
447       .postEvent(CHRE_EVENT_WIFI_SCAN_RESULT, event, freeWifiScanEventCallback);
448 }
449 
handleScanMonitorStateChangeSync(bool enabled,uint8_t errorCode)450 void WifiRequestManager::handleScanMonitorStateChangeSync(bool enabled,
451                                                           uint8_t errorCode) {
452   // Success is defined as having no errors ... in life ༼ つ ◕_◕ ༽つ
453   bool success = (errorCode == CHRE_ERROR_NONE);
454 
455   // TODO(b/62904616): re-enable this assertion
456   //CHRE_ASSERT_LOG(!mScanMonitorStateTransitions.empty(),
457   //                "handleScanMonitorStateChangeSync called with no transitions");
458   if (mPendingScanMonitorRequests.empty()) {
459     LOGE("WiFi PAL error: handleScanMonitorStateChangeSync called with no "
460          "transitions (enabled %d errorCode %" PRIu8 ")", enabled, errorCode);
461   }
462 
463   // Always check the front of the queue.
464   if (!mPendingScanMonitorRequests.empty()) {
465     const auto& stateTransition = mPendingScanMonitorRequests.front();
466     success &= (stateTransition.enable == enabled);
467     postScanMonitorAsyncResultEventFatal(stateTransition.nanoappInstanceId,
468                                          success, stateTransition.enable,
469                                          errorCode, stateTransition.cookie);
470     mPendingScanMonitorRequests.pop();
471   }
472 
473   while (!mPendingScanMonitorRequests.empty()) {
474     const auto& stateTransition = mPendingScanMonitorRequests.front();
475     bool hasScanMonitorRequest = nanoappHasScanMonitorRequest(
476         stateTransition.nanoappInstanceId);
477     if (scanMonitorIsInRequestedState(
478         stateTransition.enable, hasScanMonitorRequest)) {
479       // We are already in the target state so just post an event indicating
480       // success
481       postScanMonitorAsyncResultEventFatal(stateTransition.nanoappInstanceId,
482                                            success, stateTransition.enable,
483                                            errorCode, stateTransition.cookie);
484     } else if (scanMonitorStateTransitionIsRequired(
485         stateTransition.enable, hasScanMonitorRequest)) {
486       if (mPlatformWifi.configureScanMonitor(stateTransition.enable)) {
487         break;
488       } else {
489         postScanMonitorAsyncResultEventFatal(stateTransition.nanoappInstanceId,
490                                              false /* success */,
491                                              stateTransition.enable, CHRE_ERROR,
492                                              stateTransition.cookie);
493       }
494     } else {
495       CHRE_ASSERT_LOG(false, "Invalid scan monitor state");
496       break;
497     }
498 
499     mPendingScanMonitorRequests.pop();
500   }
501 }
502 
handleScanResponseSync(bool pending,uint8_t errorCode)503 void WifiRequestManager::handleScanResponseSync(bool pending,
504                                                 uint8_t errorCode) {
505   // TODO(b/65206783): re-enable this assertion
506   //CHRE_ASSERT_LOG(mScanRequestingNanoappInstanceId.has_value(),
507   //                "handleScanResponseSync called with no outstanding request");
508   if (!mScanRequestingNanoappInstanceId.has_value()) {
509     LOGE("handleScanResponseSync called with no outstanding request");
510   }
511 
512   // TODO: raise this to CHRE_ASSERT_LOG
513   if (!pending && errorCode == CHRE_ERROR_NONE) {
514     LOGE("Invalid wifi scan response");
515     errorCode = CHRE_ERROR;
516   }
517 
518   if (mScanRequestingNanoappInstanceId.has_value()) {
519     bool success = (pending && errorCode == CHRE_ERROR_NONE);
520     if (!success) {
521       LOGW("Wifi scan request failed: pending %d, errorCode %" PRIu8,
522            pending, errorCode);
523     }
524     postScanRequestAsyncResultEventFatal(*mScanRequestingNanoappInstanceId,
525                                          success, errorCode,
526                                          mScanRequestingNanoappCookie);
527 
528     // Set a flag to indicate that results may be pending.
529     mScanRequestResultsArePending = pending;
530 
531     if (pending) {
532       Nanoapp *nanoapp = EventLoopManagerSingleton::get()->getEventLoop()
533           .findNanoappByInstanceId(*mScanRequestingNanoappInstanceId);
534       if (nanoapp == nullptr) {
535         LOGW("Received WiFi scan response for unknown nanoapp");
536       } else {
537         nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
538       }
539     } else {
540       // If the scan results are not pending, clear the nanoapp instance ID.
541       // Otherwise, wait for the results to be delivered and then clear the
542       // instance ID.
543       mScanRequestingNanoappInstanceId.reset();
544     }
545   }
546 }
547 
postRangingAsyncResult(uint8_t errorCode)548 bool WifiRequestManager::postRangingAsyncResult(uint8_t errorCode) {
549   bool eventPosted = false;
550 
551   if (mPendingRangingRequests.empty()) {
552     LOGE("Unexpected ranging event callback");
553   } else {
554     auto *event = memoryAlloc<struct chreAsyncResult>();
555     if (event == nullptr) {
556       LOGE("Couldn't allocate ranging async result");
557     } else {
558       const PendingRangingRequest& req = mPendingRangingRequests.front();
559 
560       event->requestType = CHRE_WIFI_REQUEST_TYPE_RANGING;
561       event->success = (errorCode == CHRE_ERROR_NONE);
562       event->errorCode = errorCode;
563       event->reserved = 0;
564       event->cookie = req.cookie;
565 
566       eventPosted = EventLoopManagerSingleton::get()->getEventLoop().postEvent(
567           CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
568           kSystemInstanceId, req.nanoappInstanceId);
569       if (!eventPosted) {
570         memoryFree(event);
571       }
572     }
573   }
574 
575   return eventPosted;
576 }
577 
dispatchQueuedRangingRequest()578 bool WifiRequestManager::dispatchQueuedRangingRequest() {
579   const PendingRangingRequest& req = mPendingRangingRequests.front();
580   struct chreWifiRangingParams params = {};
581   params.targetListLen = static_cast<uint8_t>(req.targetList.size());
582   params.targetList = req.targetList.data();
583 
584   bool success = mPlatformWifi.requestRanging(&params);
585   if (!success) {
586     LOGE("Failed to issue queued ranging result");
587     postRangingAsyncResult(CHRE_ERROR);
588     mPendingRangingRequests.pop();
589   } else {
590     mRangingResponseTimeout = SystemTime::getMonotonicTime()
591         + Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
592   }
593 
594   return success;
595 }
596 
handleRangingEventSync(uint8_t errorCode,struct chreWifiRangingEvent * event)597 void WifiRequestManager::handleRangingEventSync(
598     uint8_t errorCode, struct chreWifiRangingEvent *event) {
599   if (postRangingAsyncResult(errorCode)) {
600     if (errorCode != CHRE_ERROR_NONE) {
601       LOGW("RTT ranging failed with error %d", errorCode);
602     } else {
603       EventLoopManagerSingleton::get()->getEventLoop().postEvent(
604           CHRE_EVENT_WIFI_RANGING_RESULT, event, freeWifiRangingEventCallback,
605           kSystemInstanceId, mPendingRangingRequests.front().nanoappInstanceId);
606     }
607     mPendingRangingRequests.pop();
608   }
609 
610   // If we have any pending requests, try issuing them to the platform until the
611   // first one succeeds
612   while (!mPendingRangingRequests.empty() && !dispatchQueuedRangingRequest());
613 }
614 
handleFreeWifiScanEvent(chreWifiScanEvent * scanEvent)615 void WifiRequestManager::handleFreeWifiScanEvent(chreWifiScanEvent *scanEvent) {
616   if (mScanRequestResultsArePending) {
617     // Reset the event distribution logic once an entire scan event has been
618     // received and processed by the nanoapp requesting the scan event.
619     mScanEventResultCountAccumulator += scanEvent->resultCount;
620     if (mScanEventResultCountAccumulator >= scanEvent->resultTotal) {
621       mScanEventResultCountAccumulator = 0;
622       mScanRequestResultsArePending = false;
623     }
624 
625     if (!mScanRequestResultsArePending
626         && mScanRequestingNanoappInstanceId.has_value()) {
627       Nanoapp *nanoapp = EventLoopManagerSingleton::get()->getEventLoop()
628           .findNanoappByInstanceId(*mScanRequestingNanoappInstanceId);
629       if (nanoapp == nullptr) {
630         LOGW("Attempted to unsubscribe unknown nanoapp from WiFi scan events");
631       } else if (!nanoappHasScanMonitorRequest(
632           *mScanRequestingNanoappInstanceId)) {
633         nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
634       }
635 
636       mScanRequestingNanoappInstanceId.reset();
637     }
638   }
639 
640   mPlatformWifi.releaseScanEvent(scanEvent);
641 }
642 
freeWifiScanEventCallback(uint16_t eventType,void * eventData)643 void WifiRequestManager::freeWifiScanEventCallback(uint16_t eventType,
644                                                    void *eventData) {
645   chreWifiScanEvent *scanEvent = static_cast<chreWifiScanEvent *>(eventData);
646   EventLoopManagerSingleton::get()->getWifiRequestManager()
647       .handleFreeWifiScanEvent(scanEvent);
648 }
649 
freeWifiRangingEventCallback(uint16_t eventType,void * eventData)650 void WifiRequestManager::freeWifiRangingEventCallback(uint16_t eventType,
651                                                       void *eventData) {
652   auto *event = static_cast<struct chreWifiRangingEvent *>(eventData);
653   EventLoopManagerSingleton::get()->getWifiRequestManager()
654       .mPlatformWifi.releaseRangingEvent(event);
655 }
656 
657 }  // namespace chre
658