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