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(¶msCompat, params, offsetof(chreWifiScanParams, radioChainPref));
149 paramsCompat.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
150 params = ¶msCompat;
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(¶ms)) {
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