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