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