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 #ifdef CHRE_WIFI_SUPPORT_ENABLED
18
19 #include "chre/core/wifi_request_manager.h"
20
21 #include <cinttypes>
22 #include <cstddef>
23 #include <cstdint>
24 #include <cstring>
25
26 #include "chre/core/event_loop_manager.h"
27 #include "chre/core/settings.h"
28 #include "chre/core/system_health_monitor.h"
29 #include "chre/platform/fatal_error.h"
30 #include "chre/platform/log.h"
31 #include "chre/platform/system_time.h"
32 #include "chre/util/enum.h"
33 #include "chre/util/nested_data_ptr.h"
34 #include "chre/util/system/debug_dump.h"
35 #include "chre/util/system/event_callbacks.h"
36 #include "chre_api/chre/version.h"
37
38 // The default timeout values can be overwritten to lower the runtime
39 // for tests. Timeout values cannot be overwritten with a bigger value.
40 #ifdef CHRE_TEST_ASYNC_RESULT_TIMEOUT_NS
41 static_assert(CHRE_TEST_ASYNC_RESULT_TIMEOUT_NS <=
42 CHRE_ASYNC_RESULT_TIMEOUT_NS);
43 #undef CHRE_ASYNC_RESULT_TIMEOUT_NS
44 #define CHRE_ASYNC_RESULT_TIMEOUT_NS CHRE_TEST_ASYNC_RESULT_TIMEOUT_NS
45 #endif
46
47 #ifdef CHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS
48 static_assert(CHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS <=
49 CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
50 #undef CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS
51 #define CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS \
52 CHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS
53 #endif
54
55 #ifdef CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS
56 static_assert(CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS <=
57 CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
58 #undef CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS
59 #define CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS
60 #endif
61
62 namespace chre {
63
64 WifiRequestManager::DebugLogEntry
forScanRequest(uint16_t nanoappInstanceId,const chreWifiScanParams & scanParams,bool syncResult)65 WifiRequestManager::DebugLogEntry::forScanRequest(
66 uint16_t nanoappInstanceId, const chreWifiScanParams &scanParams,
67 bool syncResult) {
68 DebugLogEntry entry;
69 entry.timestamp = SystemTime::getMonotonicTime();
70 entry.logType = WifiScanLogType::SCAN_REQUEST;
71 entry.scanRequest.nanoappInstanceId = nanoappInstanceId;
72 entry.scanRequest.maxScanAgeMs =
73 (scanParams.maxScanAgeMs > UINT16_MAX)
74 ? UINT16_MAX
75 : static_cast<uint16_t>(scanParams.maxScanAgeMs);
76 entry.scanRequest.scanType = scanParams.scanType;
77 entry.scanRequest.radioChainPref = scanParams.radioChainPref;
78 entry.scanRequest.channelSet = scanParams.channelSet;
79 entry.scanRequest.syncResult = syncResult;
80 return entry;
81 }
82
83 WifiRequestManager::DebugLogEntry
forScanResponse(uint16_t nanoappInstanceId,bool pending,uint8_t errorCode)84 WifiRequestManager::DebugLogEntry::forScanResponse(uint16_t nanoappInstanceId,
85 bool pending,
86 uint8_t errorCode) {
87 DebugLogEntry entry;
88 entry.timestamp = SystemTime::getMonotonicTime();
89 entry.logType = WifiScanLogType::SCAN_RESPONSE;
90 entry.scanResponse.nanoappInstanceId = nanoappInstanceId;
91 entry.scanResponse.pending = pending;
92 entry.scanResponse.errorCode = errorCode;
93 return entry;
94 }
95
96 WifiRequestManager::DebugLogEntry
forScanEvent(const chreWifiScanEvent & scanEvent)97 WifiRequestManager::DebugLogEntry::forScanEvent(
98 const chreWifiScanEvent &scanEvent) {
99 DebugLogEntry entry;
100 entry.timestamp = SystemTime::getMonotonicTime();
101 entry.logType = WifiScanLogType::SCAN_EVENT;
102 entry.scanEvent.resultCount = scanEvent.resultCount;
103 entry.scanEvent.resultTotal = scanEvent.resultTotal;
104 entry.scanEvent.eventIndex = scanEvent.eventIndex;
105 entry.scanEvent.scanType = scanEvent.scanType;
106 return entry;
107 }
108
109 WifiRequestManager::DebugLogEntry
forScanMonitorRequest(uint16_t nanoappInstanceId,bool enable,bool syncResult)110 WifiRequestManager::DebugLogEntry::forScanMonitorRequest(
111 uint16_t nanoappInstanceId, bool enable, bool syncResult) {
112 DebugLogEntry entry;
113 entry.timestamp = SystemTime::getMonotonicTime();
114 entry.logType = WifiScanLogType::SCAN_MONITOR_REQUEST;
115 entry.scanMonitorRequest.nanoappInstanceId = nanoappInstanceId;
116 entry.scanMonitorRequest.enable = enable;
117 entry.scanMonitorRequest.syncResult = syncResult;
118 return entry;
119 }
120
121 WifiRequestManager::DebugLogEntry
forScanMonitorResult(uint16_t nanoappInstanceId,bool enabled,uint8_t errorCode)122 WifiRequestManager::DebugLogEntry::forScanMonitorResult(
123 uint16_t nanoappInstanceId, bool enabled, uint8_t errorCode) {
124 DebugLogEntry entry;
125 entry.timestamp = SystemTime::getMonotonicTime();
126 entry.logType = WifiScanLogType::SCAN_MONITOR_RESULT;
127 entry.scanMonitorResult.nanoappInstanceId = nanoappInstanceId;
128 entry.scanMonitorResult.enabled = enabled;
129 entry.scanMonitorResult.errorCode = errorCode;
130 return entry;
131 }
132
WifiRequestManager()133 WifiRequestManager::WifiRequestManager() {
134 // Reserve space for at least one scan monitoring nanoapp. This ensures that
135 // the first asynchronous push_back will succeed. Future push_backs will be
136 // synchronous and failures will be returned to the client.
137 if (!mScanMonitorNanoapps.reserve(1)) {
138 FATAL_ERROR_OOM();
139 }
140 }
141
init()142 void WifiRequestManager::init() {
143 mPlatformWifi.init();
144 }
145
getCapabilities()146 uint32_t WifiRequestManager::getCapabilities() {
147 return mPlatformWifi.getCapabilities();
148 }
149
dispatchQueuedConfigureScanMonitorRequests()150 void WifiRequestManager::dispatchQueuedConfigureScanMonitorRequests() {
151 while (!mPendingScanMonitorRequests.empty()) {
152 const auto &stateTransition = mPendingScanMonitorRequests.front();
153 bool hasScanMonitorRequest =
154 nanoappHasScanMonitorRequest(stateTransition.nanoappInstanceId);
155 if (scanMonitorIsInRequestedState(stateTransition.enable,
156 hasScanMonitorRequest)) {
157 // We are already in the target state so just post an event indicating
158 // success
159 postScanMonitorAsyncResultEventFatal(
160 stateTransition.nanoappInstanceId, true /* success */,
161 stateTransition.enable, CHRE_ERROR_NONE, stateTransition.cookie);
162 } else if (scanMonitorStateTransitionIsRequired(stateTransition.enable,
163 hasScanMonitorRequest)) {
164 bool syncResult =
165 mPlatformWifi.configureScanMonitor(stateTransition.enable);
166 addDebugLog(DebugLogEntry::forScanMonitorRequest(
167 stateTransition.nanoappInstanceId, stateTransition.enable,
168 syncResult));
169 if (!syncResult) {
170 postScanMonitorAsyncResultEventFatal(
171 stateTransition.nanoappInstanceId, false /* success */,
172 stateTransition.enable, CHRE_ERROR, stateTransition.cookie);
173 } else {
174 mConfigureScanMonitorTimeoutHandle = setConfigureScanMonitorTimer();
175 break;
176 }
177 } else {
178 CHRE_ASSERT_LOG(false, "Invalid scan monitor state");
179 }
180 mPendingScanMonitorRequests.pop();
181 }
182 }
183
handleConfigureScanMonitorTimeout()184 void WifiRequestManager::handleConfigureScanMonitorTimeout() {
185 if (mPendingScanMonitorRequests.empty()) {
186 LOGE("Configure Scan Monitor timer timedout with no pending request.");
187 } else {
188 EventLoopManagerSingleton::get()->getSystemHealthMonitor().onFailure(
189 HealthCheckId::WifiConfigureScanMonitorTimeout);
190 mPendingScanMonitorRequests.pop();
191
192 dispatchQueuedConfigureScanMonitorRequests();
193 }
194 }
195
setConfigureScanMonitorTimer()196 TimerHandle WifiRequestManager::setConfigureScanMonitorTimer() {
197 auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) {
198 EventLoopManagerSingleton::get()
199 ->getWifiRequestManager()
200 .handleConfigureScanMonitorTimeout();
201 };
202
203 return EventLoopManagerSingleton::get()->setDelayedCallback(
204 SystemCallbackType::RequestTimeoutEvent, nullptr, callback,
205 Nanoseconds(CHRE_ASYNC_RESULT_TIMEOUT_NS));
206 }
207
configureScanMonitor(Nanoapp * nanoapp,bool enable,const void * cookie)208 bool WifiRequestManager::configureScanMonitor(Nanoapp *nanoapp, bool enable,
209 const void *cookie) {
210 CHRE_ASSERT(nanoapp);
211
212 bool success = false;
213 uint16_t instanceId = nanoapp->getInstanceId();
214 bool hasScanMonitorRequest = nanoappHasScanMonitorRequest(instanceId);
215 if (!mPendingScanMonitorRequests.empty()) {
216 success = addScanMonitorRequestToQueue(nanoapp, enable, cookie);
217 } else if (scanMonitorIsInRequestedState(enable, hasScanMonitorRequest)) {
218 // The scan monitor is already in the requested state. A success event can
219 // be posted immediately.
220 success = postScanMonitorAsyncResultEvent(instanceId, true /* success */,
221 enable, CHRE_ERROR_NONE, cookie);
222 } else if (scanMonitorStateTransitionIsRequired(enable,
223 hasScanMonitorRequest)) {
224 success = addScanMonitorRequestToQueue(nanoapp, enable, cookie);
225 if (success) {
226 success = mPlatformWifi.configureScanMonitor(enable);
227 addDebugLog(
228 DebugLogEntry::forScanMonitorRequest(instanceId, enable, success));
229 if (!success) {
230 mPendingScanMonitorRequests.pop_back();
231 LOGE("Failed to enable the scan monitor for nanoapp instance %" PRIu16,
232 instanceId);
233 } else {
234 mConfigureScanMonitorTimeoutHandle = setConfigureScanMonitorTimer();
235 }
236 }
237 } else {
238 CHRE_ASSERT_LOG(false, "Invalid scan monitor configuration");
239 }
240
241 return success;
242 }
243
disableAllSubscriptions(Nanoapp * nanoapp)244 uint32_t WifiRequestManager::disableAllSubscriptions(Nanoapp *nanoapp) {
245 uint32_t numSubscriptionsDisabled = 0;
246
247 // Disable active scan monitoring.
248 if (nanoappHasScanMonitorRequest(nanoapp->getInstanceId()) ||
249 nanoappHasPendingScanMonitorRequest(nanoapp->getInstanceId())) {
250 numSubscriptionsDisabled++;
251 configureScanMonitor(nanoapp, false /*enabled*/, nullptr /*cookie*/);
252 }
253
254 // Disable active NAN subscriptions.
255 for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) {
256 if (mNanoappSubscriptions[i].nanoappInstanceId ==
257 nanoapp->getInstanceId()) {
258 numSubscriptionsDisabled++;
259 nanSubscribeCancel(nanoapp, mNanoappSubscriptions[i].subscriptionId);
260 }
261 }
262
263 return numSubscriptionsDisabled;
264 }
265
requestRangingByType(RangingType type,const void * rangingParams)266 bool WifiRequestManager::requestRangingByType(RangingType type,
267 const void *rangingParams) {
268 bool success = false;
269 if (type == RangingType::WIFI_AP) {
270 auto *params =
271 static_cast<const struct chreWifiRangingParams *>(rangingParams);
272 success = mPlatformWifi.requestRanging(params);
273 } else {
274 auto *params =
275 static_cast<const struct chreWifiNanRangingParams *>(rangingParams);
276 success = mPlatformWifi.requestNanRanging(params);
277 }
278 if (success) {
279 mRequestRangingTimeoutHandle = setRangingRequestTimer();
280 }
281 return success;
282 }
283
updateRangingRequest(RangingType type,PendingRangingRequest & request,const void * rangingParams)284 bool WifiRequestManager::updateRangingRequest(RangingType type,
285 PendingRangingRequest &request,
286 const void *rangingParams) {
287 bool success = false;
288 if (type == RangingType::WIFI_AP) {
289 auto *params =
290 static_cast<const struct chreWifiRangingParams *>(rangingParams);
291 success = request.targetList.copy_array(params->targetList,
292 params->targetListLen);
293 } else {
294 auto *params =
295 static_cast<const struct chreWifiNanRangingParams *>(rangingParams);
296 std::memcpy(request.nanRangingParams.macAddress, params->macAddress,
297 CHRE_WIFI_BSSID_LEN);
298 success = true;
299 }
300 return success;
301 }
302
sendRangingRequest(PendingRangingRequest & request)303 bool WifiRequestManager::sendRangingRequest(PendingRangingRequest &request) {
304 bool success = false;
305
306 if (request.type == RangingType::WIFI_AP) {
307 struct chreWifiRangingParams params = {};
308 params.targetListLen = static_cast<uint8_t>(request.targetList.size());
309 params.targetList = request.targetList.data();
310 success = mPlatformWifi.requestRanging(¶ms);
311 } else {
312 struct chreWifiNanRangingParams params;
313 std::memcpy(params.macAddress, request.nanRangingParams.macAddress,
314 CHRE_WIFI_BSSID_LEN);
315 success = mPlatformWifi.requestNanRanging(¶ms);
316 }
317 if (success) {
318 mRequestRangingTimeoutHandle = setRangingRequestTimer();
319 }
320 return success;
321 }
322
handleRangingRequestTimeout()323 void WifiRequestManager::handleRangingRequestTimeout() {
324 if (mPendingRangingRequests.empty()) {
325 LOGE("Request ranging timer timedout with no pending request.");
326 } else {
327 EventLoopManagerSingleton::get()->getSystemHealthMonitor().onFailure(
328 HealthCheckId::WifiRequestRangingTimeout);
329 mPendingRangingRequests.pop();
330 while (!mPendingRangingRequests.empty() && !dispatchQueuedRangingRequest())
331 ;
332 }
333 }
334
setRangingRequestTimer()335 TimerHandle WifiRequestManager::setRangingRequestTimer() {
336 auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) {
337 EventLoopManagerSingleton::get()
338 ->getWifiRequestManager()
339 .handleRangingRequestTimeout();
340 };
341
342 return EventLoopManagerSingleton::get()->setDelayedCallback(
343 SystemCallbackType::RequestTimeoutEvent, nullptr, callback,
344 Nanoseconds(CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS));
345 }
346
requestRanging(RangingType rangingType,Nanoapp * nanoapp,const void * rangingParams,const void * cookie)347 bool WifiRequestManager::requestRanging(RangingType rangingType,
348 Nanoapp *nanoapp,
349 const void *rangingParams,
350 const void *cookie) {
351 CHRE_ASSERT(nanoapp);
352 CHRE_ASSERT(rangingParams);
353
354 bool success = false;
355 if (!mPendingRangingRequests.emplace()) {
356 LOGE("Can't issue new RTT request; pending queue full");
357 } else {
358 PendingRangingRequest &req = mPendingRangingRequests.back();
359 req.nanoappInstanceId = nanoapp->getInstanceId();
360 req.cookie = cookie;
361 if (mPendingRangingRequests.size() == 1) {
362 // First in line; dispatch request immediately
363 if (!areRequiredSettingsEnabled()) {
364 // Treat as success but post async failure per API.
365 success = true;
366 postRangingAsyncResult(CHRE_ERROR_FUNCTION_DISABLED);
367 mPendingRangingRequests.pop_back();
368 } else if (!requestRangingByType(rangingType, rangingParams)) {
369 LOGE("WiFi ranging request of type %d failed",
370 static_cast<int>(rangingType));
371 mPendingRangingRequests.pop_back();
372 } else {
373 success = true;
374 }
375 } else {
376 success = updateRangingRequest(rangingType, req, rangingParams);
377 if (!success) {
378 LOG_OOM();
379 mPendingRangingRequests.pop_back();
380 }
381 }
382 }
383 return success;
384 }
385
handleScanRequestTimeout()386 void WifiRequestManager::handleScanRequestTimeout() {
387 mScanRequestTimeoutHandle = CHRE_TIMER_INVALID;
388 if (mPendingScanRequests.empty()) {
389 LOGE("Scan Request timer timedout with no pending request.");
390 } else {
391 EventLoopManagerSingleton::get()->getSystemHealthMonitor().onFailure(
392 HealthCheckId::WifiScanResponseTimeout);
393 // Reset the scan accumulator logic to prevent interference with the next
394 // scan request.
395 resetScanEventResultCountAccumulator();
396 mPendingScanRequests.pop();
397 dispatchQueuedScanRequests(true /* postAsyncResult */);
398 }
399 }
400
setScanRequestTimer()401 TimerHandle WifiRequestManager::setScanRequestTimer() {
402 CHRE_ASSERT(mScanRequestTimeoutHandle == CHRE_TIMER_INVALID);
403
404 auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) {
405 EventLoopManagerSingleton::get()
406 ->getWifiRequestManager()
407 .handleScanRequestTimeout();
408 };
409
410 return EventLoopManagerSingleton::get()->setDelayedCallback(
411 SystemCallbackType::RequestTimeoutEvent, nullptr, callback,
412 Nanoseconds(CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS));
413 }
414
cancelScanRequestTimer()415 void WifiRequestManager::cancelScanRequestTimer() {
416 if (mScanRequestTimeoutHandle != CHRE_TIMER_INVALID) {
417 EventLoopManagerSingleton::get()->cancelDelayedCallback(
418 mScanRequestTimeoutHandle);
419 mScanRequestTimeoutHandle = CHRE_TIMER_INVALID;
420 }
421 }
422
nanoappHasPendingScanRequest(uint16_t instanceId) const423 bool WifiRequestManager::nanoappHasPendingScanRequest(
424 uint16_t instanceId) const {
425 for (const auto &scanRequest : mPendingScanRequests) {
426 if (scanRequest.nanoappInstanceId == instanceId) {
427 return true;
428 }
429 }
430 return false;
431 }
432
requestScan(Nanoapp * nanoapp,const struct chreWifiScanParams * params,const void * cookie)433 bool WifiRequestManager::requestScan(Nanoapp *nanoapp,
434 const struct chreWifiScanParams *params,
435 const void *cookie) {
436 CHRE_ASSERT(nanoapp);
437
438 // Handle compatibility with nanoapps compiled against API v1.1, which doesn't
439 // include the radioChainPref parameter in chreWifiScanParams
440 struct chreWifiScanParams paramsCompat;
441 if (nanoapp->getTargetApiVersion() < CHRE_API_VERSION_1_2) {
442 memcpy(¶msCompat, params, offsetof(chreWifiScanParams, radioChainPref));
443 paramsCompat.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
444 params = ¶msCompat;
445 }
446
447 bool success = false;
448 uint16_t nanoappInstanceId = nanoapp->getInstanceId();
449 if (nanoappHasPendingScanRequest(nanoappInstanceId)) {
450 LOGE("Can't issue new scan request: nanoapp: %" PRIx64
451 " already has a pending request",
452 nanoapp->getAppId());
453 } else if (!mPendingScanRequests.emplace(nanoappInstanceId, cookie, params)) {
454 LOG_OOM();
455 } else if (!EventLoopManagerSingleton::get()
456 ->getSettingManager()
457 .getSettingEnabled(Setting::WIFI_AVAILABLE)) {
458 // Treat as success, but send an async failure per API contract.
459 success = true;
460 handleScanResponse(false /* pending */, CHRE_ERROR_FUNCTION_DISABLED);
461 } else {
462 if (mPendingScanRequests.size() == 1) {
463 success = dispatchQueuedScanRequests(false /* postAsyncResult */);
464 } else {
465 success = true;
466 }
467 }
468
469 return success;
470 }
471
handleScanMonitorStateChange(bool enabled,uint8_t errorCode)472 void WifiRequestManager::handleScanMonitorStateChange(bool enabled,
473 uint8_t errorCode) {
474 EventLoopManagerSingleton::get()->cancelDelayedCallback(
475 mConfigureScanMonitorTimeoutHandle);
476 struct CallbackState {
477 bool enabled;
478 uint8_t errorCode;
479 };
480
481 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
482 CallbackState cbState = NestedDataPtr<CallbackState>(data);
483 EventLoopManagerSingleton::get()
484 ->getWifiRequestManager()
485 .handleScanMonitorStateChangeSync(cbState.enabled, cbState.errorCode);
486 };
487
488 CallbackState cbState = {};
489 cbState.enabled = enabled;
490 cbState.errorCode = errorCode;
491 EventLoopManagerSingleton::get()->deferCallback(
492 SystemCallbackType::WifiScanMonitorStateChange,
493 NestedDataPtr<CallbackState>(cbState), callback);
494 }
495
handleScanResponse(bool pending,uint8_t errorCode)496 void WifiRequestManager::handleScanResponse(bool pending, uint8_t errorCode) {
497 struct CallbackState {
498 bool pending;
499 uint8_t errorCode;
500 };
501
502 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
503 CallbackState cbState = NestedDataPtr<CallbackState>(data);
504 EventLoopManagerSingleton::get()
505 ->getWifiRequestManager()
506 .handleScanResponseSync(cbState.pending, cbState.errorCode);
507 };
508
509 CallbackState cbState = {};
510 cbState.pending = pending;
511 cbState.errorCode = errorCode;
512 EventLoopManagerSingleton::get()->deferCallback(
513 SystemCallbackType::WifiRequestScanResponse,
514 NestedDataPtr<CallbackState>(cbState), callback);
515 }
516
handleRangingEvent(uint8_t errorCode,struct chreWifiRangingEvent * event)517 void WifiRequestManager::handleRangingEvent(
518 uint8_t errorCode, struct chreWifiRangingEvent *event) {
519 EventLoopManagerSingleton::get()->cancelDelayedCallback(
520 mRequestRangingTimeoutHandle);
521 auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
522 uint8_t cbErrorCode = NestedDataPtr<uint8_t>(extraData);
523 EventLoopManagerSingleton::get()
524 ->getWifiRequestManager()
525 .handleRangingEventSync(
526 cbErrorCode, static_cast<struct chreWifiRangingEvent *>(data));
527 };
528
529 EventLoopManagerSingleton::get()->deferCallback(
530 SystemCallbackType::WifiHandleRangingEvent, event, callback,
531 NestedDataPtr<uint8_t>(errorCode));
532 }
533
handleScanEvent(struct chreWifiScanEvent * event)534 void WifiRequestManager::handleScanEvent(struct chreWifiScanEvent *event) {
535 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
536 auto *scanEvent = static_cast<struct chreWifiScanEvent *>(data);
537 EventLoopManagerSingleton::get()
538 ->getWifiRequestManager()
539 .postScanEventFatal(scanEvent);
540 };
541
542 EventLoopManagerSingleton::get()->deferCallback(
543 SystemCallbackType::WifiHandleScanEvent, event, callback);
544 }
545
handleNanServiceIdentifierEventSync(uint8_t errorCode,uint32_t subscriptionId)546 void WifiRequestManager::handleNanServiceIdentifierEventSync(
547 uint8_t errorCode, uint32_t subscriptionId) {
548 if (!mPendingNanSubscribeRequests.empty()) {
549 auto &req = mPendingNanSubscribeRequests.front();
550 chreWifiNanIdentifierEvent *event =
551 memoryAlloc<chreWifiNanIdentifierEvent>();
552
553 if (event == nullptr) {
554 LOG_OOM();
555 } else {
556 event->id = subscriptionId;
557 event->result.requestType = CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE;
558 event->result.success = (errorCode == CHRE_ERROR_NONE);
559 event->result.errorCode = errorCode;
560 event->result.cookie = req.cookie;
561
562 if (errorCode == CHRE_ERROR_NONE) {
563 // It is assumed that the NAN discovery engine guarantees a unique ID
564 // for each subscription - avoid redundant checks on uniqueness here.
565 if (!mNanoappSubscriptions.push_back(NanoappNanSubscriptions(
566 req.nanoappInstanceId, subscriptionId))) {
567 LOG_OOM();
568 // Even though the subscription request was able to successfully
569 // obtain an ID, CHRE ran out of memory and couldn't store the
570 // instance ID - subscription ID pair. Indicate this in the event
571 // result.
572 // TODO(b/204226580): Cancel the subscription if we run out of
573 // memory.
574 event->result.errorCode = CHRE_ERROR_NO_MEMORY;
575 }
576 }
577
578 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
579 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event, freeEventDataCallback,
580 req.nanoappInstanceId);
581 }
582
583 mPendingNanSubscribeRequests.pop();
584 dispatchQueuedNanSubscribeRequestWithRetry();
585 } else {
586 LOGE("Received a NAN identifier event with no pending request!");
587 }
588 }
589
handleNanServiceIdentifierEvent(uint8_t errorCode,uint32_t subscriptionId)590 void WifiRequestManager::handleNanServiceIdentifierEvent(
591 uint8_t errorCode, uint32_t subscriptionId) {
592 auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
593 uint8_t errorCode = NestedDataPtr<uint8_t>(data);
594 uint32_t subscriptionId = NestedDataPtr<uint32_t>(extraData);
595 EventLoopManagerSingleton::get()
596 ->getWifiRequestManager()
597 .handleNanServiceIdentifierEventSync(errorCode, subscriptionId);
598 };
599
600 EventLoopManagerSingleton::get()->deferCallback(
601 SystemCallbackType::WifiNanServiceIdEvent,
602 NestedDataPtr<uint8_t>(errorCode), callback,
603 NestedDataPtr<uint32_t>(subscriptionId));
604 }
605
getNappIdFromSubscriptionId(uint32_t subscriptionId,uint16_t * nanoappInstanceId)606 bool WifiRequestManager::getNappIdFromSubscriptionId(
607 uint32_t subscriptionId, uint16_t *nanoappInstanceId) {
608 bool success = false;
609 for (auto &sub : mNanoappSubscriptions) {
610 if (sub.subscriptionId == subscriptionId) {
611 *nanoappInstanceId = sub.nanoappInstanceId;
612 success = true;
613 break;
614 }
615 }
616 return success;
617 }
618
handleNanServiceDiscoveryEventSync(struct chreWifiNanDiscoveryEvent * event)619 void WifiRequestManager::handleNanServiceDiscoveryEventSync(
620 struct chreWifiNanDiscoveryEvent *event) {
621 CHRE_ASSERT(event != nullptr);
622 uint16_t nanoappInstanceId;
623 if (getNappIdFromSubscriptionId(event->subscribeId, &nanoappInstanceId)) {
624 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
625 CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event,
626 freeNanDiscoveryEventCallback, nanoappInstanceId);
627 } else {
628 LOGE("Failed to find a nanoapp owning subscription ID %" PRIu32,
629 event->subscribeId);
630 }
631 }
632
handleNanServiceDiscoveryEvent(struct chreWifiNanDiscoveryEvent * event)633 void WifiRequestManager::handleNanServiceDiscoveryEvent(
634 struct chreWifiNanDiscoveryEvent *event) {
635 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
636 auto *event = static_cast<chreWifiNanDiscoveryEvent *>(data);
637 EventLoopManagerSingleton::get()
638 ->getWifiRequestManager()
639 .handleNanServiceDiscoveryEventSync(event);
640 };
641
642 EventLoopManagerSingleton::get()->deferCallback(
643 SystemCallbackType::WifiNanServiceDiscoveryEvent, event, callback);
644 }
645
handleNanServiceLostEventSync(uint32_t subscriptionId,uint32_t publisherId)646 void WifiRequestManager::handleNanServiceLostEventSync(uint32_t subscriptionId,
647 uint32_t publisherId) {
648 uint16_t nanoappInstanceId;
649 if (getNappIdFromSubscriptionId(subscriptionId, &nanoappInstanceId)) {
650 chreWifiNanSessionLostEvent *event =
651 memoryAlloc<chreWifiNanSessionLostEvent>();
652 if (event == nullptr) {
653 LOG_OOM();
654 } else {
655 event->id = subscriptionId;
656 event->peerId = publisherId;
657 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
658 CHRE_EVENT_WIFI_NAN_SESSION_LOST, event, freeEventDataCallback,
659 nanoappInstanceId);
660 }
661 } else {
662 LOGE("Failed to find a nanoapp owning subscription ID %" PRIu32,
663 subscriptionId);
664 }
665 }
666
handleNanServiceLostEvent(uint32_t subscriptionId,uint32_t publisherId)667 void WifiRequestManager::handleNanServiceLostEvent(uint32_t subscriptionId,
668 uint32_t publisherId) {
669 auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
670 auto subscriptionId = NestedDataPtr<uint32_t>(data);
671 auto publisherId = NestedDataPtr<uint32_t>(extraData);
672 EventLoopManagerSingleton::get()
673 ->getWifiRequestManager()
674 .handleNanServiceLostEventSync(subscriptionId, publisherId);
675 };
676
677 EventLoopManagerSingleton::get()->deferCallback(
678 SystemCallbackType::WifiNanServiceSessionLostEvent,
679 NestedDataPtr<uint32_t>(subscriptionId), callback,
680 NestedDataPtr<uint32_t>(publisherId));
681 }
682
handleNanServiceTerminatedEventSync(uint8_t errorCode,uint32_t subscriptionId)683 void WifiRequestManager::handleNanServiceTerminatedEventSync(
684 uint8_t errorCode, uint32_t subscriptionId) {
685 uint16_t nanoappInstanceId;
686 if (getNappIdFromSubscriptionId(subscriptionId, &nanoappInstanceId)) {
687 chreWifiNanSessionTerminatedEvent *event =
688 memoryAlloc<chreWifiNanSessionTerminatedEvent>();
689 if (event == nullptr) {
690 LOG_OOM();
691 } else {
692 event->id = subscriptionId;
693 event->reason = errorCode;
694 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
695 CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED, event, freeEventDataCallback,
696 nanoappInstanceId);
697 }
698 } else {
699 LOGE("Failed to find a nanoapp owning subscription ID %" PRIu32,
700 subscriptionId);
701 }
702 }
703
handleNanServiceSubscriptionCanceledEventSync(uint8_t errorCode,uint32_t subscriptionId)704 void WifiRequestManager::handleNanServiceSubscriptionCanceledEventSync(
705 uint8_t errorCode, uint32_t subscriptionId) {
706 for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) {
707 if (mNanoappSubscriptions[i].subscriptionId == subscriptionId) {
708 if (errorCode != CHRE_ERROR_NONE) {
709 LOGE("Subscription %" PRIu32 " cancelation error: %" PRIu8,
710 subscriptionId, errorCode);
711 }
712 mNanoappSubscriptions.erase(i);
713 break;
714 }
715 }
716 }
717
handleNanServiceTerminatedEvent(uint8_t errorCode,uint32_t subscriptionId)718 void WifiRequestManager::handleNanServiceTerminatedEvent(
719 uint8_t errorCode, uint32_t subscriptionId) {
720 auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
721 auto errorCode = NestedDataPtr<uint8_t>(data);
722 auto subscriptionId = NestedDataPtr<uint32_t>(extraData);
723 EventLoopManagerSingleton::get()
724 ->getWifiRequestManager()
725 .handleNanServiceTerminatedEventSync(errorCode, subscriptionId);
726 };
727
728 EventLoopManagerSingleton::get()->deferCallback(
729 SystemCallbackType::WifiNanServiceTerminatedEvent,
730 NestedDataPtr<uint8_t>(errorCode), callback,
731 NestedDataPtr<uint32_t>(subscriptionId));
732 }
733
handleNanServiceSubscriptionCanceledEvent(uint8_t errorCode,uint32_t subscriptionId)734 void WifiRequestManager::handleNanServiceSubscriptionCanceledEvent(
735 uint8_t errorCode, uint32_t subscriptionId) {
736 auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
737 auto errorCode = NestedDataPtr<uint8_t>(data);
738 auto subscriptionId = NestedDataPtr<uint32_t>(extraData);
739 EventLoopManagerSingleton::get()
740 ->getWifiRequestManager()
741 .handleNanServiceSubscriptionCanceledEventSync(errorCode,
742 subscriptionId);
743 };
744
745 EventLoopManagerSingleton::get()->deferCallback(
746 SystemCallbackType::WifiNanServiceTerminatedEvent,
747 NestedDataPtr<uint8_t>(errorCode), callback,
748 NestedDataPtr<uint32_t>(subscriptionId));
749 }
750
dumpDebugLog(const DebugLogEntry & log,DebugDumpWrapper & debugDump) const751 void WifiRequestManager::dumpDebugLog(const DebugLogEntry &log,
752 DebugDumpWrapper &debugDump) const {
753 debugDump.print(" ts=%" PRIu64 " ", log.timestamp.toRawNanoseconds());
754 switch (log.logType) {
755 case WifiScanLogType::SCAN_REQUEST:
756 debugDump.print("scanReq: nappId=%" PRIu16 " scanType=%" PRIu8
757 " maxScanAge(ms)=%" PRIu16 " radioChainPref=%" PRIu8
758 " channelSet=%" PRIu8 " syncResult=%d\n",
759 log.scanRequest.nanoappInstanceId,
760 log.scanRequest.scanType,
761 log.scanRequest.maxScanAgeMs,
762 log.scanRequest.radioChainPref,
763 log.scanRequest.channelSet,
764 log.scanRequest.syncResult);
765 break;
766 case WifiScanLogType::SCAN_RESPONSE:
767 debugDump.print("scanRsp: nappId=%" PRIu16 " pending=%" PRIu8
768 " errorCode=%" PRIu8 "\n",
769 log.scanResponse.nanoappInstanceId,
770 log.scanResponse.pending,
771 log.scanResponse.errorCode);
772 break;
773 case WifiScanLogType::SCAN_EVENT:
774 debugDump.print("scanEvt: resultCount=%" PRIu8 " resultTotal=%" PRIu8
775 " eventIndex=%" PRIu8 " scanType=%" PRIu8 "\n",
776 log.scanEvent.resultCount,
777 log.scanEvent.resultTotal,
778 log.scanEvent.eventIndex,
779 log.scanEvent.scanType);
780 break;
781 case WifiScanLogType::SCAN_MONITOR_REQUEST:
782 debugDump.print("scanMonReq: nappId=%" PRIu16 " enable=%" PRIu8
783 " syncResult=%" PRIu8 "\n",
784 log.scanMonitorRequest.nanoappInstanceId,
785 log.scanMonitorRequest.enable,
786 log.scanMonitorRequest.syncResult);
787 break;
788 case WifiScanLogType::SCAN_MONITOR_RESULT:
789 debugDump.print("scanMonRes: nappId=%" PRIu16 " enabled=%" PRIu8
790 " errorCode=%" PRIu8 "\n",
791 log.scanMonitorResult.nanoappInstanceId,
792 log.scanMonitorResult.enabled,
793 log.scanMonitorResult.errorCode);
794 break;
795 default:
796 debugDump.print("unknown log type %" PRIu8 "\n", asBaseType(log.logType));
797 }
798 }
799
logStateToBuffer(DebugDumpWrapper & debugDump) const800 void WifiRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
801 debugDump.print("\nWIFI:\n");
802 debugDump.print(" Scan monitor: %s\n",
803 scanMonitorIsEnabled() ? "enabled" : "disabled");
804
805 if (scanMonitorIsEnabled()) {
806 debugDump.print(" Scan monitor nanoapps:\n");
807 for (uint16_t instanceId : mScanMonitorNanoapps) {
808 debugDump.print(" nappId=%" PRIu16 "\n", instanceId);
809 }
810 }
811
812 if (!mPendingScanRequests.empty()) {
813 debugDump.print(" Pending scan requests:\n");
814 for (const auto &request : mPendingScanRequests) {
815 debugDump.print(" nappId=%" PRIu16 "\n", request.nanoappInstanceId);
816 }
817 }
818
819 if (!mPendingScanMonitorRequests.empty()) {
820 debugDump.print(" Pending scan monitor requests:\n");
821 for (const auto &transition : mPendingScanMonitorRequests) {
822 debugDump.print(" enable=%s nappId=%" PRIu16 "\n",
823 transition.enable ? "true" : "false",
824 transition.nanoappInstanceId);
825 }
826 }
827
828 size_t i = mDebugLogs.size();
829 debugDump.print(" Last %zu debug entries:\n", i);
830 while (i-- > 0) {
831 dumpDebugLog(mDebugLogs[i], debugDump);
832 }
833
834 debugDump.print(" API error distribution (error-code indexed):\n");
835 debugDump.print(" Scan monitor:\n");
836 debugDump.logErrorHistogram(mScanMonitorErrorHistogram,
837 ARRAY_SIZE(mScanMonitorErrorHistogram));
838 debugDump.print(" Active Scan:\n");
839 debugDump.logErrorHistogram(mActiveScanErrorHistogram,
840 ARRAY_SIZE(mActiveScanErrorHistogram));
841
842 if (!mNanoappSubscriptions.empty()) {
843 debugDump.print(" Active NAN service subscriptions:\n");
844 for (const auto &sub : mNanoappSubscriptions) {
845 debugDump.print(" nappID=%" PRIu16 " sub ID=%" PRIu32 "\n",
846 sub.nanoappInstanceId, sub.subscriptionId);
847 }
848 }
849
850 if (!mPendingNanSubscribeRequests.empty()) {
851 debugDump.print(" Pending NAN service subscriptions:\n");
852 for (const auto &req : mPendingNanSubscribeRequests) {
853 debugDump.print(" nappID=%" PRIu16 " (type %" PRIu8 ") to svc: %s\n",
854 req.nanoappInstanceId, req.type, req.service.data());
855 }
856 }
857 }
858
scanMonitorIsEnabled() const859 bool WifiRequestManager::scanMonitorIsEnabled() const {
860 return !mScanMonitorNanoapps.empty();
861 }
862
nanoappHasScanMonitorRequest(uint16_t instanceId,size_t * nanoappIndex) const863 bool WifiRequestManager::nanoappHasScanMonitorRequest(
864 uint16_t instanceId, size_t *nanoappIndex) const {
865 size_t index = mScanMonitorNanoapps.find(instanceId);
866 bool hasScanMonitorRequest = (index != mScanMonitorNanoapps.size());
867 if (hasScanMonitorRequest && nanoappIndex != nullptr) {
868 *nanoappIndex = index;
869 }
870
871 return hasScanMonitorRequest;
872 }
873
scanMonitorIsInRequestedState(bool requestedState,bool nanoappHasRequest) const874 bool WifiRequestManager::scanMonitorIsInRequestedState(
875 bool requestedState, bool nanoappHasRequest) const {
876 return (requestedState == scanMonitorIsEnabled() ||
877 (!requestedState &&
878 (!nanoappHasRequest || mScanMonitorNanoapps.size() > 1)));
879 }
880
scanMonitorStateTransitionIsRequired(bool requestedState,bool nanoappHasRequest) const881 bool WifiRequestManager::scanMonitorStateTransitionIsRequired(
882 bool requestedState, bool nanoappHasRequest) const {
883 return ((requestedState && mScanMonitorNanoapps.empty()) ||
884 (!requestedState && nanoappHasRequest &&
885 mScanMonitorNanoapps.size() == 1));
886 }
887
addScanMonitorRequestToQueue(Nanoapp * nanoapp,bool enable,const void * cookie)888 bool WifiRequestManager::addScanMonitorRequestToQueue(Nanoapp *nanoapp,
889 bool enable,
890 const void *cookie) {
891 PendingScanMonitorRequest scanMonitorStateTransition;
892 scanMonitorStateTransition.nanoappInstanceId = nanoapp->getInstanceId();
893 scanMonitorStateTransition.cookie = cookie;
894 scanMonitorStateTransition.enable = enable;
895
896 bool success = mPendingScanMonitorRequests.push(scanMonitorStateTransition);
897 if (!success) {
898 LOGW("Too many scan monitor state transitions");
899 }
900
901 return success;
902 }
903
nanoappHasPendingScanMonitorRequest(uint16_t instanceId) const904 bool WifiRequestManager::nanoappHasPendingScanMonitorRequest(
905 uint16_t instanceId) const {
906 const int numRequests = static_cast<int>(mPendingScanMonitorRequests.size());
907 for (int i = numRequests - 1; i >= 0; i--) {
908 const PendingScanMonitorRequest &request =
909 mPendingScanMonitorRequests[static_cast<size_t>(i)];
910 // The last pending request determines the state of the scan monitoring.
911 if (request.nanoappInstanceId == instanceId) {
912 return request.enable;
913 }
914 }
915
916 return false;
917 }
918
updateNanoappScanMonitoringList(bool enable,uint16_t instanceId)919 bool WifiRequestManager::updateNanoappScanMonitoringList(bool enable,
920 uint16_t instanceId) {
921 bool success = true;
922 Nanoapp *nanoapp =
923 EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
924 instanceId);
925 size_t nanoappIndex;
926 bool hasExistingRequest =
927 nanoappHasScanMonitorRequest(instanceId, &nanoappIndex);
928
929 if (nanoapp == nullptr) {
930 // When the scan monitoring is disabled from inside nanoappEnd() or when
931 // CHRE cleanup the subscription automatically it is possible that the
932 // current method is called after the nanoapp is unloaded. In such a case
933 // we still want to remove the nanoapp from mScanMonitorNanoapps.
934 if (!enable && hasExistingRequest) {
935 mScanMonitorNanoapps.erase(nanoappIndex);
936 } else {
937 LOGW("Failed to update scan monitoring list for non-existent nanoapp");
938 }
939 } else {
940 if (enable) {
941 if (!hasExistingRequest) {
942 // The scan monitor was successfully enabled for this nanoapp and
943 // there is no existing request. Add it to the list of scan monitoring
944 // nanoapps.
945 success = mScanMonitorNanoapps.push_back(instanceId);
946 if (!success) {
947 LOG_OOM();
948 } else {
949 nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
950 }
951 }
952 } else if (hasExistingRequest) {
953 // The scan monitor was successfully disabled for a previously enabled
954 // nanoapp. Remove it from the list of scan monitoring nanoapps.
955 mScanMonitorNanoapps.erase(nanoappIndex);
956 nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
957 } // else disabling an inactive request, treat as success per the CHRE API.
958 }
959
960 return success;
961 }
962
postScanMonitorAsyncResultEvent(uint16_t nanoappInstanceId,bool success,bool enable,uint8_t errorCode,const void * cookie)963 bool WifiRequestManager::postScanMonitorAsyncResultEvent(
964 uint16_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
965 const void *cookie) {
966 // Allocate and post an event to the nanoapp requesting wifi.
967 bool eventPosted = false;
968 // If we failed to enable, don't add the nanoapp to the list, but always
969 // remove it if it was trying to disable. This keeps us from getting stuck in
970 // a state where we think the scan monitor is enabled (because the list is
971 // non-empty) when we actually aren't sure (e.g. the scan monitor disablement
972 // may have been handled but delivering the result ran into an error).
973 if ((!success && enable) ||
974 updateNanoappScanMonitoringList(enable, nanoappInstanceId)) {
975 chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
976 if (event == nullptr) {
977 LOG_OOM();
978 } else {
979 event->requestType = CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR;
980 event->success = success;
981 event->errorCode = errorCode;
982 event->reserved = 0;
983 event->cookie = cookie;
984
985 if (errorCode < CHRE_ERROR_SIZE) {
986 mScanMonitorErrorHistogram[errorCode]++;
987 } else {
988 LOGE("Undefined error in ScanMonitorAsyncResult: %" PRIu8, errorCode);
989 }
990
991 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
992 CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
993 nanoappInstanceId);
994 eventPosted = true;
995 }
996 }
997
998 return eventPosted;
999 }
1000
postScanMonitorAsyncResultEventFatal(uint16_t nanoappInstanceId,bool success,bool enable,uint8_t errorCode,const void * cookie)1001 void WifiRequestManager::postScanMonitorAsyncResultEventFatal(
1002 uint16_t nanoappInstanceId, bool success, bool enable, uint8_t errorCode,
1003 const void *cookie) {
1004 if (!postScanMonitorAsyncResultEvent(nanoappInstanceId, success, enable,
1005 errorCode, cookie)) {
1006 FATAL_ERROR("Failed to send WiFi scan monitor async result event");
1007 }
1008 }
1009
postScanRequestAsyncResultEvent(uint16_t nanoappInstanceId,bool success,uint8_t errorCode,const void * cookie)1010 bool WifiRequestManager::postScanRequestAsyncResultEvent(
1011 uint16_t nanoappInstanceId, bool success, uint8_t errorCode,
1012 const void *cookie) {
1013 // TODO: the body of this function can be extracted to a common helper for use
1014 // across this function, postScanMonitorAsyncResultEvent,
1015 // postRangingAsyncResult, and GnssSession::postAsyncResultEvent
1016 bool eventPosted = false;
1017 chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
1018 if (event == nullptr) {
1019 LOG_OOM();
1020 } else {
1021 event->requestType = CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN;
1022 event->success = success;
1023 event->errorCode = errorCode;
1024 event->reserved = 0;
1025 event->cookie = cookie;
1026
1027 if (errorCode < CHRE_ERROR_SIZE) {
1028 mActiveScanErrorHistogram[errorCode]++;
1029 } else {
1030 LOGE("Undefined error in ScanRequestAsyncResult: %" PRIu8, errorCode);
1031 }
1032
1033 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1034 CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
1035 nanoappInstanceId);
1036 eventPosted = true;
1037 }
1038
1039 return eventPosted;
1040 }
1041
postScanRequestAsyncResultEventFatal(uint16_t nanoappInstanceId,bool success,uint8_t errorCode,const void * cookie)1042 void WifiRequestManager::postScanRequestAsyncResultEventFatal(
1043 uint16_t nanoappInstanceId, bool success, uint8_t errorCode,
1044 const void *cookie) {
1045 if (!postScanRequestAsyncResultEvent(nanoappInstanceId, success, errorCode,
1046 cookie)) {
1047 FATAL_ERROR("Failed to send WiFi scan request async result event");
1048 }
1049 }
1050
postScanEventFatal(chreWifiScanEvent * event)1051 void WifiRequestManager::postScanEventFatal(chreWifiScanEvent *event) {
1052 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1053 CHRE_EVENT_WIFI_SCAN_RESULT, event, freeWifiScanEventCallback);
1054 }
1055
handleScanMonitorStateChangeSync(bool enabled,uint8_t errorCode)1056 void WifiRequestManager::handleScanMonitorStateChangeSync(bool enabled,
1057 uint8_t errorCode) {
1058 addDebugLog(DebugLogEntry::forScanMonitorResult(
1059 mPendingScanMonitorRequests.empty()
1060 ? kSystemInstanceId
1061 : mPendingScanMonitorRequests.front().nanoappInstanceId,
1062 enabled, errorCode));
1063 if (mPendingScanMonitorRequests.empty()) {
1064 LOGE("Scan monitor change with no pending requests (enabled %d "
1065 "errorCode %" PRIu8 ")", enabled, errorCode);
1066 EventLoopManagerSingleton::get()->getSystemHealthMonitor().onFailure(
1067 HealthCheckId::UnexpectedWifiScanMonitorStateChange);
1068 }
1069
1070 // Success is defined as having no errors ... in life ༼ つ ◕_◕ ༽つ
1071 bool success = (errorCode == CHRE_ERROR_NONE);
1072 if (!mPendingScanMonitorRequests.empty()) {
1073 const auto &stateTransition = mPendingScanMonitorRequests.front();
1074 success &= (stateTransition.enable == enabled);
1075 postScanMonitorAsyncResultEventFatal(stateTransition.nanoappInstanceId,
1076 success, stateTransition.enable,
1077 errorCode, stateTransition.cookie);
1078 mPendingScanMonitorRequests.pop();
1079 }
1080
1081 dispatchQueuedConfigureScanMonitorRequests();
1082 }
1083
postNanAsyncResultEvent(uint16_t nanoappInstanceId,uint8_t requestType,bool success,uint8_t errorCode,const void * cookie)1084 void WifiRequestManager::postNanAsyncResultEvent(uint16_t nanoappInstanceId,
1085 uint8_t requestType,
1086 bool success,
1087 uint8_t errorCode,
1088 const void *cookie) {
1089 chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
1090 if (event == nullptr) {
1091 LOG_OOM();
1092 } else {
1093 event->requestType = requestType;
1094 event->cookie = cookie;
1095 event->errorCode = errorCode;
1096 event->success = success;
1097
1098 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1099 CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
1100 nanoappInstanceId);
1101 }
1102 }
1103
handleScanResponseSync(bool pending,uint8_t errorCode)1104 void WifiRequestManager::handleScanResponseSync(bool pending,
1105 uint8_t errorCode) {
1106 addDebugLog(DebugLogEntry::forScanResponse(
1107 mPendingScanRequests.empty()
1108 ? kSystemInstanceId
1109 : mPendingScanRequests.front().nanoappInstanceId,
1110 pending, errorCode));
1111 if (mPendingScanRequests.empty()) {
1112 EventLoopManagerSingleton::get()->getSystemHealthMonitor().onFailure(
1113 HealthCheckId::UnexpectedWifiScanResponse);
1114 }
1115
1116 if (!pending && errorCode == CHRE_ERROR_NONE) {
1117 LOGE("Invalid wifi scan response");
1118 errorCode = CHRE_ERROR;
1119 }
1120
1121 if (!mPendingScanRequests.empty()) {
1122 bool success = (pending && errorCode == CHRE_ERROR_NONE);
1123 if (!success) {
1124 LOGW("Wifi scan request failed: pending %d, errorCode %" PRIu8, pending,
1125 errorCode);
1126 }
1127 PendingScanRequest ¤tScanRequest = mPendingScanRequests.front();
1128 postScanRequestAsyncResultEventFatal(currentScanRequest.nanoappInstanceId,
1129 success, errorCode,
1130 currentScanRequest.cookie);
1131
1132 // Set a flag to indicate that results may be pending.
1133 mScanRequestResultsArePending = pending;
1134
1135 if (pending) {
1136 Nanoapp *nanoapp =
1137 EventLoopManagerSingleton::get()
1138 ->getEventLoop()
1139 .findNanoappByInstanceId(currentScanRequest.nanoappInstanceId);
1140 if (nanoapp == nullptr) {
1141 LOGW("Received WiFi scan response for unknown nanoapp");
1142 } else {
1143 nanoapp->registerForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
1144 }
1145 } else {
1146 // If the scan results are not pending, pop the first event since it's no
1147 // longer waiting for anything. Otherwise, wait for the results to be
1148 // delivered and then pop the first request.
1149 cancelScanRequestTimer();
1150 mPendingScanRequests.pop();
1151 dispatchQueuedScanRequests(true /* postAsyncResult */);
1152 }
1153 }
1154 }
1155
postRangingAsyncResult(uint8_t errorCode)1156 bool WifiRequestManager::postRangingAsyncResult(uint8_t errorCode) {
1157 bool eventPosted = false;
1158
1159 if (mPendingRangingRequests.empty()) {
1160 LOGE("Unexpected ranging event callback");
1161 } else {
1162 auto *event = memoryAlloc<struct chreAsyncResult>();
1163 if (event == nullptr) {
1164 LOG_OOM();
1165 } else {
1166 const PendingRangingRequest &req = mPendingRangingRequests.front();
1167
1168 event->requestType = CHRE_WIFI_REQUEST_TYPE_RANGING;
1169 event->success = (errorCode == CHRE_ERROR_NONE);
1170 event->errorCode = errorCode;
1171 event->reserved = 0;
1172 event->cookie = req.cookie;
1173
1174 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1175 CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
1176 req.nanoappInstanceId);
1177 eventPosted = true;
1178 }
1179 }
1180
1181 return eventPosted;
1182 }
1183
dispatchQueuedRangingRequest()1184 bool WifiRequestManager::dispatchQueuedRangingRequest() {
1185 bool success = false;
1186 uint8_t asyncError = CHRE_ERROR_NONE;
1187 PendingRangingRequest &req = mPendingRangingRequests.front();
1188
1189 if (!areRequiredSettingsEnabled()) {
1190 asyncError = CHRE_ERROR_FUNCTION_DISABLED;
1191 } else if (!sendRangingRequest(req)) {
1192 asyncError = CHRE_ERROR;
1193 } else {
1194 success = true;
1195 }
1196
1197 if (asyncError != CHRE_ERROR_NONE) {
1198 postRangingAsyncResult(asyncError);
1199 mPendingRangingRequests.pop();
1200 }
1201
1202 return success;
1203 }
1204
dispatchQueuedNanSubscribeRequest()1205 bool WifiRequestManager::dispatchQueuedNanSubscribeRequest() {
1206 bool success = false;
1207
1208 if (!mPendingNanSubscribeRequests.empty()) {
1209 uint8_t asyncError = CHRE_ERROR_NONE;
1210 const auto &req = mPendingNanSubscribeRequests.front();
1211 struct chreWifiNanSubscribeConfig config = {};
1212 buildNanSubscribeConfigFromRequest(req, &config);
1213
1214 if (!areRequiredSettingsEnabled()) {
1215 asyncError = CHRE_ERROR_FUNCTION_DISABLED;
1216 } else if (!mPlatformWifi.nanSubscribe(&config)) {
1217 asyncError = CHRE_ERROR;
1218 }
1219
1220 if (asyncError != CHRE_ERROR_NONE) {
1221 postNanAsyncResultEvent(req.nanoappInstanceId,
1222 CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE,
1223 false /*success*/, asyncError, req.cookie);
1224 mPendingNanSubscribeRequests.pop();
1225 } else {
1226 success = true;
1227 }
1228 }
1229 return success;
1230 }
1231
dispatchQueuedNanSubscribeRequestWithRetry()1232 void WifiRequestManager::dispatchQueuedNanSubscribeRequestWithRetry() {
1233 while (!mPendingNanSubscribeRequests.empty() &&
1234 !dispatchQueuedNanSubscribeRequest())
1235 ;
1236 }
1237
dispatchQueuedScanRequests(bool postAsyncResult)1238 bool WifiRequestManager::dispatchQueuedScanRequests(bool postAsyncResult) {
1239 while (!mPendingScanRequests.empty()) {
1240 uint8_t asyncError = CHRE_ERROR_NONE;
1241 const PendingScanRequest ¤tScanRequest = mPendingScanRequests.front();
1242
1243 if (!EventLoopManagerSingleton::get()
1244 ->getSettingManager()
1245 .getSettingEnabled(Setting::WIFI_AVAILABLE)) {
1246 asyncError = CHRE_ERROR_FUNCTION_DISABLED;
1247 } else {
1248 bool syncResult =
1249 mPlatformWifi.requestScan(¤tScanRequest.scanParams);
1250 addDebugLog(DebugLogEntry::forScanRequest(
1251 currentScanRequest.nanoappInstanceId, currentScanRequest.scanParams,
1252 syncResult));
1253 if (!syncResult) {
1254 asyncError = CHRE_ERROR;
1255 } else {
1256 mScanRequestTimeoutHandle = setScanRequestTimer();
1257 return true;
1258 }
1259 }
1260
1261 if (postAsyncResult) {
1262 postScanRequestAsyncResultEvent(currentScanRequest.nanoappInstanceId,
1263 false /*success*/, asyncError,
1264 currentScanRequest.cookie);
1265 } else {
1266 LOGE("Wifi scan request failed");
1267 }
1268 mPendingScanRequests.pop();
1269 }
1270 return false;
1271 }
1272
handleRangingEventSync(uint8_t errorCode,struct chreWifiRangingEvent * event)1273 void WifiRequestManager::handleRangingEventSync(
1274 uint8_t errorCode, struct chreWifiRangingEvent *event) {
1275 if (!areRequiredSettingsEnabled()) {
1276 errorCode = CHRE_ERROR_FUNCTION_DISABLED;
1277 }
1278
1279 if (postRangingAsyncResult(errorCode)) {
1280 if (errorCode != CHRE_ERROR_NONE) {
1281 LOGW("RTT ranging failed with error %d", errorCode);
1282 if (event != nullptr) {
1283 freeWifiRangingEventCallback(CHRE_EVENT_WIFI_RANGING_RESULT, event);
1284 }
1285 } else {
1286 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1287 CHRE_EVENT_WIFI_RANGING_RESULT, event, freeWifiRangingEventCallback,
1288 mPendingRangingRequests.front().nanoappInstanceId);
1289 }
1290 mPendingRangingRequests.pop();
1291 }
1292
1293 // If we have any pending requests, try issuing them to the platform until the
1294 // first one succeeds.
1295 while (!mPendingRangingRequests.empty() && !dispatchQueuedRangingRequest())
1296 ;
1297 }
1298
handleFreeWifiScanEvent(chreWifiScanEvent * scanEvent)1299 void WifiRequestManager::handleFreeWifiScanEvent(chreWifiScanEvent *scanEvent) {
1300 addDebugLog(DebugLogEntry::forScanEvent(*scanEvent));
1301 if (mScanRequestResultsArePending) {
1302 // Reset the event distribution logic once an entire scan event has been
1303 // received and processed by the nanoapp requesting the scan event.
1304 mScanEventResultCountAccumulator += scanEvent->resultCount;
1305 if (mScanEventResultCountAccumulator >= scanEvent->resultTotal) {
1306 resetScanEventResultCountAccumulator();
1307 cancelScanRequestTimer();
1308 }
1309
1310 if (!mScanRequestResultsArePending && !mPendingScanRequests.empty()) {
1311 uint16_t pendingNanoappInstanceId =
1312 mPendingScanRequests.front().nanoappInstanceId;
1313 Nanoapp *nanoapp = EventLoopManagerSingleton::get()
1314 ->getEventLoop()
1315 .findNanoappByInstanceId(pendingNanoappInstanceId);
1316 if (nanoapp == nullptr) {
1317 LOGW("Attempted to unsubscribe unknown nanoapp from WiFi scan events");
1318 } else if (!nanoappHasScanMonitorRequest(pendingNanoappInstanceId)) {
1319 nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
1320 }
1321 mPendingScanRequests.pop();
1322 dispatchQueuedScanRequests(true /* postAsyncResult */);
1323 }
1324 }
1325
1326 mPlatformWifi.releaseScanEvent(scanEvent);
1327 }
1328
freeWifiScanEventCallback(uint16_t,void * eventData)1329 void WifiRequestManager::freeWifiScanEventCallback(uint16_t /* eventType */,
1330 void *eventData) {
1331 auto *scanEvent = static_cast<struct chreWifiScanEvent *>(eventData);
1332 EventLoopManagerSingleton::get()
1333 ->getWifiRequestManager()
1334 .handleFreeWifiScanEvent(scanEvent);
1335 }
1336
freeWifiRangingEventCallback(uint16_t,void * eventData)1337 void WifiRequestManager::freeWifiRangingEventCallback(uint16_t /* eventType */,
1338 void *eventData) {
1339 auto *event = static_cast<struct chreWifiRangingEvent *>(eventData);
1340 EventLoopManagerSingleton::get()
1341 ->getWifiRequestManager()
1342 .mPlatformWifi.releaseRangingEvent(event);
1343 }
1344
freeNanDiscoveryEventCallback(uint16_t,void * eventData)1345 void WifiRequestManager::freeNanDiscoveryEventCallback(uint16_t /* eventType */,
1346 void *eventData) {
1347 auto *event = static_cast<struct chreWifiNanDiscoveryEvent *>(eventData);
1348 EventLoopManagerSingleton::get()
1349 ->getWifiRequestManager()
1350 .mPlatformWifi.releaseNanDiscoveryEvent(event);
1351 }
1352
nanSubscribe(Nanoapp * nanoapp,const struct chreWifiNanSubscribeConfig * config,const void * cookie)1353 bool WifiRequestManager::nanSubscribe(
1354 Nanoapp *nanoapp, const struct chreWifiNanSubscribeConfig *config,
1355 const void *cookie) {
1356 CHRE_ASSERT(nanoapp);
1357
1358 bool success = false;
1359
1360 if (!areRequiredSettingsEnabled()) {
1361 success = true;
1362 postNanAsyncResultEvent(
1363 nanoapp->getInstanceId(), CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE,
1364 false /*success*/, CHRE_ERROR_FUNCTION_DISABLED, cookie);
1365 } else {
1366 if (!mPendingNanSubscribeRequests.emplace()) {
1367 LOG_OOM();
1368 } else {
1369 auto &req = mPendingNanSubscribeRequests.back();
1370 req.nanoappInstanceId = nanoapp->getInstanceId();
1371 req.cookie = cookie;
1372 if (!copyNanSubscribeConfigToRequest(req, config)) {
1373 LOG_OOM();
1374 }
1375
1376 if (mNanIsAvailable) {
1377 if (mPendingNanSubscribeRequests.size() == 1) {
1378 // First in line; dispatch request immediately.
1379 success = mPlatformWifi.nanSubscribe(config);
1380 if (!success) {
1381 mPendingNanSubscribeRequests.pop_back();
1382 }
1383 } else {
1384 success = true;
1385 }
1386 } else {
1387 success = true;
1388 sendNanConfiguration(true /*enable*/);
1389 }
1390 }
1391 }
1392 return success;
1393 }
1394
nanSubscribeCancel(Nanoapp * nanoapp,uint32_t subscriptionId)1395 bool WifiRequestManager::nanSubscribeCancel(Nanoapp *nanoapp,
1396 uint32_t subscriptionId) {
1397 bool success = false;
1398 for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) {
1399 if (mNanoappSubscriptions[i].subscriptionId == subscriptionId &&
1400 mNanoappSubscriptions[i].nanoappInstanceId ==
1401 nanoapp->getInstanceId()) {
1402 success = mPlatformWifi.nanSubscribeCancel(subscriptionId);
1403 break;
1404 }
1405 }
1406
1407 if (!success) {
1408 LOGE("Failed to cancel subscription %" PRIu32 " for napp %" PRIu16,
1409 subscriptionId, nanoapp->getInstanceId());
1410 }
1411
1412 return success;
1413 }
1414
copyNanSubscribeConfigToRequest(PendingNanSubscribeRequest & req,const struct chreWifiNanSubscribeConfig * config)1415 bool WifiRequestManager::copyNanSubscribeConfigToRequest(
1416 PendingNanSubscribeRequest &req,
1417 const struct chreWifiNanSubscribeConfig *config) {
1418 bool success = false;
1419 req.type = config->subscribeType;
1420
1421 if (req.service.copy_array(config->service,
1422 std::strlen(config->service) + 1) &&
1423 req.serviceSpecificInfo.copy_array(config->serviceSpecificInfo,
1424 config->serviceSpecificInfoSize) &&
1425 req.matchFilter.copy_array(config->matchFilter,
1426 config->matchFilterLength)) {
1427 success = true;
1428 } else {
1429 LOG_OOM();
1430 }
1431
1432 return success;
1433 }
1434
buildNanSubscribeConfigFromRequest(const PendingNanSubscribeRequest & req,struct chreWifiNanSubscribeConfig * config)1435 void WifiRequestManager::buildNanSubscribeConfigFromRequest(
1436 const PendingNanSubscribeRequest &req,
1437 struct chreWifiNanSubscribeConfig *config) {
1438 config->subscribeType = req.type;
1439 config->service = req.service.data();
1440 config->serviceSpecificInfo = req.serviceSpecificInfo.data();
1441 config->serviceSpecificInfoSize =
1442 static_cast<uint32_t>(req.serviceSpecificInfo.size());
1443 config->matchFilter = req.matchFilter.data();
1444 config->matchFilterLength = static_cast<uint32_t>(req.matchFilter.size());
1445 }
1446
areRequiredSettingsEnabled()1447 inline bool WifiRequestManager::areRequiredSettingsEnabled() {
1448 SettingManager &settingManager =
1449 EventLoopManagerSingleton::get()->getSettingManager();
1450 return settingManager.getSettingEnabled(Setting::LOCATION) &&
1451 settingManager.getSettingEnabled(Setting::WIFI_AVAILABLE);
1452 }
1453
cancelNanSubscriptionsAndInformNanoapps()1454 void WifiRequestManager::cancelNanSubscriptionsAndInformNanoapps() {
1455 for (size_t i = 0; i < mNanoappSubscriptions.size(); ++i) {
1456 chreWifiNanSessionTerminatedEvent *event =
1457 memoryAlloc<chreWifiNanSessionTerminatedEvent>();
1458 if (event == nullptr) {
1459 LOG_OOM();
1460 } else {
1461 event->id = mNanoappSubscriptions[i].subscriptionId;
1462 event->reason = CHRE_ERROR_FUNCTION_DISABLED;
1463 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1464 CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED, event, freeEventDataCallback,
1465 mNanoappSubscriptions[i].nanoappInstanceId);
1466 }
1467 }
1468 mNanoappSubscriptions.clear();
1469 }
1470
cancelNanPendingRequestsAndInformNanoapps()1471 void WifiRequestManager::cancelNanPendingRequestsAndInformNanoapps() {
1472 for (size_t i = 0; i < mPendingNanSubscribeRequests.size(); ++i) {
1473 auto &req = mPendingNanSubscribeRequests[i];
1474 chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
1475 if (event == nullptr) {
1476 LOG_OOM();
1477 break;
1478 } else {
1479 event->requestType = CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE;
1480 event->success = false;
1481 event->errorCode = CHRE_ERROR_FUNCTION_DISABLED;
1482 event->cookie = req.cookie;
1483 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
1484 CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
1485 req.nanoappInstanceId);
1486 }
1487 }
1488 mPendingNanSubscribeRequests.clear();
1489 }
1490
handleNanAvailabilitySync(bool available)1491 void WifiRequestManager::handleNanAvailabilitySync(bool available) {
1492 PendingNanConfigType nanState =
1493 available ? PendingNanConfigType::ENABLE : PendingNanConfigType::DISABLE;
1494 mNanIsAvailable = available;
1495
1496 if (nanState == mNanConfigRequestToHostPendingType) {
1497 mNanConfigRequestToHostPending = false;
1498 mNanConfigRequestToHostPendingType = PendingNanConfigType::UNKNOWN;
1499 }
1500
1501 if (available) {
1502 dispatchQueuedNanSubscribeRequestWithRetry();
1503 } else {
1504 cancelNanPendingRequestsAndInformNanoapps();
1505 cancelNanSubscriptionsAndInformNanoapps();
1506 }
1507 }
1508
updateNanAvailability(bool available)1509 void WifiRequestManager::updateNanAvailability(bool available) {
1510 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
1511 bool cbAvail = NestedDataPtr<bool>(data);
1512 EventLoopManagerSingleton::get()
1513 ->getWifiRequestManager()
1514 .handleNanAvailabilitySync(cbAvail);
1515 };
1516
1517 EventLoopManagerSingleton::get()->deferCallback(
1518 SystemCallbackType::WifiNanAvailabilityEvent,
1519 NestedDataPtr<bool>(available), callback);
1520 }
1521
sendNanConfiguration(bool enable)1522 void WifiRequestManager::sendNanConfiguration(bool enable) {
1523 PendingNanConfigType requiredState =
1524 enable ? PendingNanConfigType::ENABLE : PendingNanConfigType::DISABLE;
1525 if (!mNanConfigRequestToHostPending ||
1526 (mNanConfigRequestToHostPendingType != requiredState)) {
1527 mNanConfigRequestToHostPending = true;
1528 mNanConfigRequestToHostPendingType = requiredState;
1529 EventLoopManagerSingleton::get()
1530 ->getHostCommsManager()
1531 .sendNanConfiguration(enable);
1532 }
1533 }
1534
onSettingChanged(Setting setting,bool enabled)1535 void WifiRequestManager::onSettingChanged(Setting setting, bool enabled) {
1536 if ((setting == Setting::WIFI_AVAILABLE) && !enabled) {
1537 cancelNanPendingRequestsAndInformNanoapps();
1538 cancelNanSubscriptionsAndInformNanoapps();
1539 }
1540 }
1541
1542 } // namespace chre
1543
1544 #endif // CHRE_WIFI_SUPPORT_ENABLED
1545