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