• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chre_settings_test_manager.h"
18 
19 #include <pb_decode.h>
20 #include <pb_encode.h>
21 
22 #include "chre/util/macros.h"
23 #include "chre/util/nanoapp/ble.h"
24 #include "chre/util/nanoapp/callbacks.h"
25 #include "chre/util/nanoapp/log.h"
26 #include "chre/util/time.h"
27 #include "chre_settings_test.nanopb.h"
28 #include "send_message.h"
29 
30 #define LOG_TAG "[ChreSettingsTest]"
31 
32 using chre::createBleScanFilterForKnownBeacons;
33 using chre::ble_constants::kNumScanFilters;
34 
35 namespace chre {
36 
37 namespace settings_test {
38 
39 namespace {
40 
41 constexpr uint32_t kWifiScanningCookie = 0x1234;
42 constexpr uint32_t kWifiRttCookie = 0x2345;
43 constexpr uint32_t kGnssLocationCookie = 0x3456;
44 constexpr uint32_t kGnssMeasurementCookie = 0x4567;
45 constexpr uint32_t kWwanCellInfoCookie = 0x5678;
46 
47 // The default audio handle.
48 constexpr uint32_t kAudioHandle = 0;
49 
50 // Flag to verify if an audio data event was received after a valid sampling
51 // change event (i.e., we only got the data event after a source-enabled-and-
52 // not-suspended event).
53 bool gGotSourceEnabledEvent = false;
54 
55 uint32_t gAudioDataTimerHandle = CHRE_TIMER_INVALID;
56 constexpr uint32_t kAudioDataTimerCookie = 0xc001cafe;
57 uint32_t gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
58 constexpr uint32_t kAudioStatusTimerCookie = 0xb01dcafe;
59 uint32_t gRangingRequestRetryTimerHandle = CHRE_TIMER_INVALID;
60 constexpr uint32_t kRangingRequestSetupRetryTimerCookie = 0x600ccafe;
61 constexpr uint32_t kRangingRequestRetryTimerCookie = 0x600dcafe;
62 uint32_t gWwanRequestRetryTimerHandle = CHRE_TIMER_INVALID;
63 constexpr uint32_t kWwanRequestRetryTimerCookie = 0x01d3cafe;
64 
65 constexpr uint8_t kMaxWwanRequestRetries = 3;
66 constexpr uint8_t kMaxWifiRequestRetries = 3;
67 
getFeature(const chre_settings_test_TestCommand & command,Manager::Feature * feature)68 bool getFeature(const chre_settings_test_TestCommand &command,
69                 Manager::Feature *feature) {
70   bool success = true;
71   switch (command.feature) {
72     case chre_settings_test_TestCommand_Feature_WIFI_SCANNING:
73       *feature = Manager::Feature::WIFI_SCANNING;
74       break;
75     case chre_settings_test_TestCommand_Feature_WIFI_RTT:
76       *feature = Manager::Feature::WIFI_RTT;
77       break;
78     case chre_settings_test_TestCommand_Feature_GNSS_LOCATION:
79       *feature = Manager::Feature::GNSS_LOCATION;
80       break;
81     case chre_settings_test_TestCommand_Feature_GNSS_MEASUREMENT:
82       *feature = Manager::Feature::GNSS_MEASUREMENT;
83       break;
84     case chre_settings_test_TestCommand_Feature_WWAN_CELL_INFO:
85       *feature = Manager::Feature::WWAN_CELL_INFO;
86       break;
87     case chre_settings_test_TestCommand_Feature_AUDIO:
88       *feature = Manager::Feature::AUDIO;
89       break;
90     case chre_settings_test_TestCommand_Feature_BLE_SCANNING:
91       *feature = Manager::Feature::BLE_SCANNING;
92       break;
93     default:
94       LOGE("Unknown feature %d", command.feature);
95       success = false;
96   }
97 
98   return success;
99 }
100 
getFeatureState(const chre_settings_test_TestCommand & command,Manager::FeatureState * state)101 bool getFeatureState(const chre_settings_test_TestCommand &command,
102                      Manager::FeatureState *state) {
103   bool success = true;
104   switch (command.state) {
105     case chre_settings_test_TestCommand_State_ENABLED:
106       *state = Manager::FeatureState::ENABLED;
107       break;
108     case chre_settings_test_TestCommand_State_DISABLED:
109       *state = Manager::FeatureState::DISABLED;
110       break;
111     default:
112       LOGE("Unknown feature state %d", command.state);
113       success = false;
114   }
115 
116   return success;
117 }
118 
getTestStep(const chre_settings_test_TestCommand & command,Manager::TestStep * step)119 bool getTestStep(const chre_settings_test_TestCommand &command,
120                  Manager::TestStep *step) {
121   bool success = true;
122   switch (command.step) {
123     case chre_settings_test_TestCommand_Step_SETUP:
124       *step = Manager::TestStep::SETUP;
125       break;
126     case chre_settings_test_TestCommand_Step_START:
127       *step = Manager::TestStep::START;
128       break;
129     default:
130       LOGE("Unknown test step %d", command.step);
131       success = false;
132   }
133 
134   return success;
135 }
136 
isTestSupported()137 bool isTestSupported() {
138   // CHRE settings requirements were introduced in CHRE v1.4
139   return chreGetVersion() >= CHRE_API_VERSION_1_4;
140 }
141 
142 }  // anonymous namespace
143 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)144 void Manager::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
145                           const void *eventData) {
146   if (eventType == CHRE_EVENT_MESSAGE_FROM_HOST) {
147     handleMessageFromHost(
148         senderInstanceId,
149         static_cast<const chreMessageFromHostData *>(eventData));
150   } else if (senderInstanceId == CHRE_INSTANCE_ID) {
151     handleDataFromChre(eventType, eventData);
152   } else {
153     LOGW("Got unknown event type from senderInstanceId %" PRIu32
154          " and with eventType %" PRIu16,
155          senderInstanceId, eventType);
156   }
157 }
158 
isFeatureSupported(Feature feature)159 bool Manager::isFeatureSupported(Feature feature) {
160   bool supported = false;
161 
162   uint32_t version = chreGetVersion();
163   switch (feature) {
164     case Feature::WIFI_SCANNING: {
165       uint32_t capabilities = chreWifiGetCapabilities();
166       supported = (version >= CHRE_API_VERSION_1_1) &&
167                   ((capabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) != 0);
168       break;
169     }
170     case Feature::WIFI_RTT: {
171       uint32_t capabilities = chreWifiGetCapabilities();
172       supported = (version >= CHRE_API_VERSION_1_2) &&
173                   ((capabilities & CHRE_WIFI_CAPABILITIES_RTT_RANGING) != 0);
174       break;
175     }
176     case Feature::GNSS_LOCATION: {
177       uint32_t capabilities = chreGnssGetCapabilities();
178       supported = (version >= CHRE_API_VERSION_1_1) &&
179                   ((capabilities & CHRE_GNSS_CAPABILITIES_LOCATION) != 0);
180       break;
181     }
182     case Feature::GNSS_MEASUREMENT: {
183       uint32_t capabilities = chreGnssGetCapabilities();
184       supported = (version >= CHRE_API_VERSION_1_1) &&
185                   ((capabilities & CHRE_GNSS_CAPABILITIES_MEASUREMENTS) != 0);
186       break;
187     }
188     case Feature::WWAN_CELL_INFO: {
189       uint32_t capabilities = chreWwanGetCapabilities();
190       supported = (version >= CHRE_API_VERSION_1_1) &&
191                   ((capabilities & CHRE_WWAN_GET_CELL_INFO) != 0);
192       break;
193     }
194     case Feature::AUDIO: {
195       struct chreAudioSource source;
196       supported = chreAudioGetSource(kAudioHandle, &source);
197       break;
198     }
199     case Feature::BLE_SCANNING: {
200       uint32_t capabilities = chreBleGetCapabilities();
201       supported = (version >= CHRE_API_VERSION_1_7) &&
202                   ((capabilities & CHRE_BLE_CAPABILITIES_SCAN) != 0);
203       break;
204     }
205     default:
206       LOGE("Unknown feature %" PRIu8, static_cast<uint8_t>(feature));
207   }
208 
209   return supported;
210 }
211 
handleMessageFromHost(uint32_t senderInstanceId,const chreMessageFromHostData * hostData)212 void Manager::handleMessageFromHost(uint32_t senderInstanceId,
213                                     const chreMessageFromHostData *hostData) {
214   bool success = false;
215   uint32_t messageType = hostData->messageType;
216   if (senderInstanceId != CHRE_INSTANCE_ID) {
217     LOGE("Incorrect sender instance id: %" PRIu32, senderInstanceId);
218   } else if (messageType != chre_settings_test_MessageType_TEST_COMMAND) {
219     LOGE("Invalid message type %" PRIu32, messageType);
220   } else {
221     pb_istream_t istream = pb_istream_from_buffer(
222         static_cast<const pb_byte_t *>(hostData->message),
223         hostData->messageSize);
224     chre_settings_test_TestCommand testCommand =
225         chre_settings_test_TestCommand_init_default;
226 
227     if (!pb_decode(&istream, chre_settings_test_TestCommand_fields,
228                    &testCommand)) {
229       LOGE("Failed to decode start command error %s", PB_GET_ERROR(&istream));
230     } else {
231       Feature feature;
232       FeatureState state;
233       TestStep step;
234       if (getFeature(testCommand, &feature) &&
235           getFeatureState(testCommand, &state) &&
236           getTestStep(testCommand, &step)) {
237         LOGD("starting test: feature: %u, state %u, step %u",
238              static_cast<uint8_t>(feature), static_cast<uint8_t>(state),
239              static_cast<uint8_t>(step));
240         handleStartTestMessage(hostData->hostEndpoint, feature, state, step);
241         success = true;
242       }
243     }
244   }
245   if (!success) {
246     test_shared::sendTestResultToHost(
247         hostData->hostEndpoint, chre_settings_test_MessageType_TEST_RESULT,
248         /*success=*/false, /*abortOnFailure=*/false);
249   }
250 }
251 
handleStartTestMessage(uint16_t hostEndpointId,Feature feature,FeatureState state,TestStep step)252 void Manager::handleStartTestMessage(uint16_t hostEndpointId, Feature feature,
253                                      FeatureState state, TestStep step) {
254   // If the test/feature is not supported, treat as success and skip the test.
255   if (!isTestSupported() || !isFeatureSupported(feature)) {
256     LOGW("Skipping test - TestSupported: %u, FeatureSupported: %u",
257          isTestSupported(), isFeatureSupported(feature));
258     sendTestResult(hostEndpointId, /*success=*/true);
259   } else {
260     bool success = false;
261     if (step == TestStep::SETUP) {
262       if (feature != Feature::WIFI_RTT) {
263         LOGE("Unexpected feature %" PRIu8 " for test step",
264              static_cast<uint8_t>(feature));
265       } else {
266         success = chreWifiRequestScanAsyncDefault(&kWifiScanningCookie);
267       }
268     } else {
269       success = startTestForFeature(feature);
270     }
271 
272     if (!success) {
273       sendTestResult(hostEndpointId, /*success=*/false);
274     } else {
275       mTestSession = TestSession(hostEndpointId, feature, state, step);
276     }
277   }
278 }
279 
handleDataFromChre(uint16_t eventType,const void * eventData)280 void Manager::handleDataFromChre(uint16_t eventType, const void *eventData) {
281   if (mTestSession.has_value()) {
282     // The validation for the correct data w.r.t. the current test session
283     // will be done in the methods called from here.
284     switch (eventType) {
285       case CHRE_EVENT_AUDIO_DATA:
286         handleAudioDataEvent(
287             static_cast<const struct chreAudioDataEvent *>(eventData));
288         break;
289 
290       case CHRE_EVENT_AUDIO_SAMPLING_CHANGE:
291         handleAudioSourceStatusEvent(
292             static_cast<const struct chreAudioSourceStatusEvent *>(eventData));
293         break;
294 
295       case CHRE_EVENT_TIMER:
296         handleTimerEvent(eventData);
297         break;
298 
299       case CHRE_EVENT_WIFI_ASYNC_RESULT:
300         handleWifiAsyncResult(static_cast<const chreAsyncResult *>(eventData));
301         break;
302 
303       case CHRE_EVENT_WIFI_SCAN_RESULT:
304         handleWifiScanResult(static_cast<const chreWifiScanEvent *>(eventData));
305         break;
306 
307       case CHRE_EVENT_GNSS_ASYNC_RESULT:
308         handleGnssAsyncResult(static_cast<const chreAsyncResult *>(eventData));
309         break;
310 
311       case CHRE_EVENT_WWAN_CELL_INFO_RESULT:
312         handleWwanCellInfoResult(
313             static_cast<const chreWwanCellInfoResult *>(eventData));
314         break;
315 
316       case CHRE_EVENT_BLE_ASYNC_RESULT:
317         handleBleAsyncResult(static_cast<const chreAsyncResult *>(eventData));
318         break;
319 
320       default:
321         LOGE("Unknown event type %" PRIu16, eventType);
322     }
323   }
324 }
325 
requestRangingForFeatureWifiRtt()326 bool Manager::requestRangingForFeatureWifiRtt() {
327   if (!mCachedRangingTarget.has_value()) {
328     LOGE("No cached WiFi RTT ranging target");
329     return false;
330   }
331   struct chreWifiRangingParams params = {
332       .targetListLen = 1, .targetList = &mCachedRangingTarget.value()};
333   return chreWifiRequestRangingAsync(&params, &kWifiRttCookie);
334 }
335 
startTestForFeature(Feature feature)336 bool Manager::startTestForFeature(Feature feature) {
337   bool success = true;
338   switch (feature) {
339     case Feature::WIFI_SCANNING:
340       success = chreWifiRequestScanAsyncDefault(&kWifiScanningCookie);
341       break;
342 
343     case Feature::WIFI_RTT: {
344       mWifiRequestRetries = 0;
345       success = requestRangingForFeatureWifiRtt();
346       break;
347     }
348 
349     case Feature::GNSS_LOCATION:
350       success = chreGnssLocationSessionStartAsync(/*minIntervalMs=*/1000,
351                                                   /*minTimeToNextFixMs=*/0,
352                                                   &kGnssLocationCookie);
353       break;
354 
355     case Feature::GNSS_MEASUREMENT:
356       success = chreGnssMeasurementSessionStartAsync(/*minIntervalMs=*/1000,
357                                                      &kGnssMeasurementCookie);
358       break;
359 
360     case Feature::WWAN_CELL_INFO:
361       mWwanRequestRetries = 0;
362       success = chreWwanGetCellInfoAsync(&kWwanCellInfoCookie);
363       break;
364 
365     case Feature::AUDIO: {
366       struct chreAudioSource source;
367       if ((success = chreAudioGetSource(kAudioHandle, &source))) {
368         success = chreAudioConfigureSource(kAudioHandle, /*enable=*/true,
369                                            source.minBufferDuration,
370                                            source.minBufferDuration);
371       }
372       break;
373     }
374 
375     case Feature::BLE_SCANNING: {
376       struct chreBleScanFilter filter;
377       chreBleGenericFilter uuidFilters[kNumScanFilters];
378       createBleScanFilterForKnownBeacons(filter, uuidFilters, kNumScanFilters);
379       success = chreBleStartScanAsync(/*mode=*/CHRE_BLE_SCAN_MODE_FOREGROUND,
380                                       /*reportDelayMs=*/0, &filter);
381       break;
382     }
383 
384     default:
385       LOGE("Unknown feature %" PRIu8, static_cast<uint8_t>(feature));
386       return false;
387   }
388 
389   if (!success) {
390     LOGE("Failed to make request for test feature %" PRIu8,
391          static_cast<uint8_t>(feature));
392   } else {
393     LOGI("Starting test for feature %" PRIu8, static_cast<uint8_t>(feature));
394   }
395 
396   return success;
397 }
398 
validateAsyncResult(const chreAsyncResult * result,const void * expectedCookie)399 bool Manager::validateAsyncResult(const chreAsyncResult *result,
400                                   const void *expectedCookie) {
401   bool success = false;
402   if (result->cookie != expectedCookie) {
403     LOGE("Unexpected cookie on async result");
404   } else {
405     bool featureEnabled = (mTestSession->featureState == FeatureState::ENABLED);
406     bool disabledErrorCode =
407         (result->errorCode == CHRE_ERROR_FUNCTION_DISABLED);
408 
409     if (featureEnabled && disabledErrorCode) {
410       LOGE("Got disabled error code when feature is enabled");
411     } else if (!featureEnabled && !disabledErrorCode) {
412       LOGE("Got non-disabled error code when feature is disabled");
413     } else {
414       success = true;
415     }
416   }
417 
418   return success;
419 }
420 
handleWifiAsyncResult(const chreAsyncResult * result)421 void Manager::handleWifiAsyncResult(const chreAsyncResult *result) {
422   bool success = false;
423   uint8_t feature = static_cast<uint8_t>(mTestSession->feature);
424   switch (result->requestType) {
425     case CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN: {
426       if (mTestSession->feature == Feature::WIFI_RTT) {
427         if (result->errorCode == CHRE_ERROR ||
428             result->errorCode == CHRE_ERROR_BUSY) {
429           if (mWifiRequestRetries >= kMaxWifiRequestRetries) {
430             // The request has failed repeatedly and we are no longer retrying
431             // Return success=false to the host rather than timeout.
432             LOGE("Reached max wifi request retries: test feature %" PRIu8
433                  ". Num retries=%" PRIu8,
434                  feature, kMaxWifiRequestRetries);
435             break;
436           }
437 
438           // Retry on CHRE_ERROR/CHRE_ERROR_BUSY after a short delay
439           mWifiRequestRetries++;
440           uint64_t delay = kOneSecondInNanoseconds * 2;
441           const uint32_t *cookie = mTestSession->step == TestStep::SETUP
442                                        ? &kRangingRequestSetupRetryTimerCookie
443                                        : &kRangingRequestRetryTimerCookie;
444           gRangingRequestRetryTimerHandle =
445               chreTimerSet(delay, cookie, /*oneShot=*/true);
446           LOGW(
447               "Request failed during %s step. Retrying "
448               "after delay=%" PRIu64 "ns, num_retries=%" PRIu8 "/%" PRIu8,
449               mTestSession->step == TestStep::SETUP ? "SETUP" : "START", delay,
450               mWifiRequestRetries, kMaxWifiRequestRetries);
451           return;
452         }
453 
454         if (result->errorCode == CHRE_ERROR_NONE) {
455           // Ignore validating the scan async response since we only care about
456           // the actual scan event to initiate the RTT request.
457           return;
458         } else {
459           LOGE("Unexpected error in async result: test feature: %" PRIu8
460                " error: %" PRIu8,
461                feature, static_cast<uint8_t>(result->errorCode));
462           break;
463         }
464       }
465       if (mTestSession->feature != Feature::WIFI_SCANNING) {
466         LOGE("Unexpected WiFi scan async result: test feature %" PRIu8,
467              feature);
468       } else {
469         success = validateAsyncResult(
470             result, static_cast<const void *>(&kWifiScanningCookie));
471       }
472       break;
473     }
474     case CHRE_WIFI_REQUEST_TYPE_RANGING: {
475       if (mTestSession->feature != Feature::WIFI_RTT) {
476         LOGE("Unexpected WiFi ranging async result: test feature %" PRIu8,
477              feature);
478       } else {
479         success = validateAsyncResult(
480             result, static_cast<const void *>(&kWifiRttCookie));
481       }
482       break;
483     }
484     default:
485       LOGE("Unexpected WiFi request type %" PRIu8, result->requestType);
486   }
487 
488   sendTestResult(mTestSession->hostEndpointId, success);
489 }
490 
handleWifiScanResult(const chreWifiScanEvent * result)491 void Manager::handleWifiScanResult(const chreWifiScanEvent *result) {
492   if (mTestSession->feature == Feature::WIFI_RTT &&
493       mTestSession->step == TestStep::SETUP) {
494     if (result->resultCount == 0) {
495       LOGE("Received empty WiFi scan result");
496       sendTestResult(mTestSession->hostEndpointId, /*success=*/false);
497     } else {
498       mReceivedScanResults += result->resultCount;
499       chreWifiRangingTarget target;
500       // Try to find an AP with the FTM responder flag set. The RTT ranging
501       // request should still work equivalently even if the flag is not set (but
502       // possibly with an error in the ranging result), so we use the last entry
503       // if none is found.
504       size_t index = result->resultCount - 1;
505       for (uint8_t i = 0; i < result->resultCount - 1; i++) {
506         if ((result->results[i].flags &
507              CHRE_WIFI_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER) != 0) {
508           index = i;
509           break;
510         }
511       }
512       chreWifiRangingTargetFromScanResult(&result->results[index], &target);
513       mCachedRangingTarget = target;
514       if (result->resultTotal == mReceivedScanResults) {
515         mReceivedScanResults = 0;
516         test_shared::sendEmptyMessageToHost(
517             mTestSession->hostEndpointId,
518             chre_settings_test_MessageType_TEST_SETUP_COMPLETE);
519       }
520     }
521   }
522 }
523 
handleGnssAsyncResult(const chreAsyncResult * result)524 void Manager::handleGnssAsyncResult(const chreAsyncResult *result) {
525   bool success = false;
526   switch (result->requestType) {
527     case CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_START: {
528       if (mTestSession->feature != Feature::GNSS_LOCATION) {
529         LOGE("Unexpected GNSS location async result: test feature %" PRIu8,
530              static_cast<uint8_t>(mTestSession->feature));
531       } else {
532         success = validateAsyncResult(
533             result, static_cast<const void *>(&kGnssLocationCookie));
534         chreGnssLocationSessionStopAsync(&kGnssLocationCookie);
535       }
536       break;
537     }
538     case CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_START: {
539       if (mTestSession->feature != Feature::GNSS_MEASUREMENT) {
540         LOGE("Unexpected GNSS measurement async result: test feature %" PRIu8,
541              static_cast<uint8_t>(mTestSession->feature));
542       } else {
543         success = validateAsyncResult(
544             result, static_cast<const void *>(&kGnssMeasurementCookie));
545         chreGnssMeasurementSessionStopAsync(&kGnssMeasurementCookie);
546       }
547       break;
548     }
549     default:
550       LOGE("Unexpected GNSS request type %" PRIu8, result->requestType);
551   }
552 
553   sendTestResult(mTestSession->hostEndpointId, success);
554 }
555 
handleWwanCellInfoResult(const chreWwanCellInfoResult * result)556 void Manager::handleWwanCellInfoResult(const chreWwanCellInfoResult *result) {
557   bool success = false;
558   // For WWAN, we treat "DISABLED" as success but with empty results, per
559   // CHRE API requirements.
560   if (mTestSession->feature != Feature::WWAN_CELL_INFO) {
561     LOGE("Unexpected WWAN cell info result: test feature %" PRIu8,
562          static_cast<uint8_t>(mTestSession->feature));
563   } else if (result->cookie != &kWwanCellInfoCookie) {
564     LOGE("Unexpected cookie on WWAN cell info result");
565   } else if (result->errorCode != CHRE_ERROR_NONE) {
566     LOGE("WWAN cell info result failed: error code %" PRIu8, result->errorCode);
567   } else if (mTestSession->featureState == FeatureState::DISABLED &&
568              result->cellInfoCount > 0) {
569     // Allow some retries to wait for the modem to clear the cell info cache.
570     if (mWwanRequestRetries >= kMaxWwanRequestRetries) {
571       LOGE(
572           "WWAN cell info result should be empty when disabled. Hit retry "
573           "limit (%" PRIu8 "), cell_info_count= %" PRIu8,
574           kMaxWwanRequestRetries, result->cellInfoCount);
575     } else {
576       mWwanRequestRetries++;
577       uint64_t delay = kOneSecondInNanoseconds * 1;
578       gWwanRequestRetryTimerHandle =
579           chreTimerSet(delay, &kWwanRequestRetryTimerCookie, /*oneShot=*/true);
580       if (gWwanRequestRetryTimerHandle != CHRE_TIMER_INVALID) {
581         LOGW("WWAN cell info result should be empty when disabled: count %" PRIu8
582             " Retrying after delay=%" PRIu64 "ns, num_retries=%" PRIu8
583             "/%" PRIu8,
584             result->cellInfoCount, delay, mWwanRequestRetries,
585             kMaxWwanRequestRetries);
586         return;
587       }
588       LOGE("Failed to set WWAN cell info retry timer");
589     }
590   } else {
591     success = true;
592   }
593 
594   sendTestResult(mTestSession->hostEndpointId, success);
595 }
596 
597 // The MicDisabled Settings test works as follows:
598 // * The contents of the Source Status Event are parsed, and there are 4
599 //   possible scenarios for the flow of our test:
600 //
601 // - Mic Access was disabled, source was suspended
602 // -- Since CHRE guarantees that we'll receive audio data events spaced at
603 //    the source's minBufferDuration apart (plus a small delay/latency),
604 //    we set a timer for (minBufferDuration + 1) seconds to verify that no
605 //    data event was received. We pass the test on a timeout.
606 //
607 // - Mic Access was disabled, source wasn't suspended
608 // -- We fail the test
609 //
610 // - Mic Access was enabled, source was suspended
611 // -- We fail the test
612 //
613 // - Mic Access was enabled, source wasn't suspended
614 // -- We set a flag 'GotSourceEnabledEvent'. The audio data event checks this
615 // flag, and reports success/failure appropriately.
616 
handleAudioSourceStatusEvent(const struct chreAudioSourceStatusEvent * event)617 void Manager::handleAudioSourceStatusEvent(
618     const struct chreAudioSourceStatusEvent *event) {
619   LOGI("Received sampling status event suspended %d", event->status.suspended);
620   mAudioSamplingEnabled = !event->status.suspended;
621   if (!mTestSession.has_value()) {
622     return;
623   }
624 
625   bool success = false;
626   if (mTestSession->featureState == FeatureState::ENABLED) {
627     if (event->status.suspended) {
628       if (gAudioStatusTimerHandle != CHRE_TIMER_INVALID) {
629         chreTimerCancel(gAudioStatusTimerHandle);
630         gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
631       }
632 
633       struct chreAudioSource source;
634       if (chreAudioGetSource(kAudioHandle, &source)) {
635         const uint64_t duration =
636             source.minBufferDuration + kOneSecondInNanoseconds;
637         gAudioDataTimerHandle =
638             chreTimerSet(duration, &kAudioDataTimerCookie, /*oneShot=*/true);
639 
640         if (gAudioDataTimerHandle == CHRE_TIMER_INVALID) {
641           LOGE("Failed to set data check timer");
642         } else {
643           success = true;
644         }
645       } else {
646         LOGE("Failed to query audio source");
647       }
648     } else {
649       // There might be a corner case where CHRE might have queued an audio
650       // available event just as the microphone disable setting change is
651       // received that might wrongfully indicate that microphone access
652       // wasn't disabled when it is dispatched. We add a 2 second timer to
653       // allow CHRE to send the source status change event to account for
654       // this, and fail the test if the timer expires without getting said
655       // event.
656       LOGW("Source wasn't suspended when Mic Access disabled, waiting 2 sec");
657       gAudioStatusTimerHandle =
658           chreTimerSet(2 * kOneSecondInNanoseconds, &kAudioStatusTimerCookie,
659                        /*oneShot=*/true);
660       if (gAudioStatusTimerHandle == CHRE_TIMER_INVALID) {
661         LOGE("Failed to set audio status check timer");
662       } else {
663         // continue the test, fail on timeout.
664         success = true;
665       }
666     }
667   } else {
668     gGotSourceEnabledEvent = true;
669     success = true;
670   }
671 
672   if (!success) {
673     sendTestResult(mTestSession->hostEndpointId, success);
674   }
675 }
676 
handleAudioDataEvent(const struct chreAudioDataEvent * event)677 void Manager::handleAudioDataEvent(const struct chreAudioDataEvent *event) {
678   UNUSED_VAR(event);
679 
680   bool success = false;
681   if (mTestSession.has_value()) {
682     if (mTestSession->featureState == FeatureState::ENABLED) {
683       if (gAudioDataTimerHandle != CHRE_TIMER_INVALID) {
684         chreTimerCancel(gAudioDataTimerHandle);
685         gAudioDataTimerHandle = CHRE_TIMER_INVALID;
686       }
687     } else if (gGotSourceEnabledEvent) {
688       success = true;
689     }
690     chreAudioConfigureSource(kAudioHandle, /*enable=*/false,
691                              /*minBufferDuration=*/0,
692                              /*maxbufferDuration=*/0);
693     sendTestResult(mTestSession->hostEndpointId, success);
694   }
695 }
696 
handleTimerEvent(const void * eventData)697 void Manager::handleTimerEvent(const void *eventData) {
698   bool testSuccess = false;
699   auto *cookie = static_cast<const uint32_t *>(eventData);
700 
701   if (*cookie == kRangingRequestSetupRetryTimerCookie) {
702     gRangingRequestRetryTimerHandle = CHRE_TIMER_INVALID;
703     chreWifiRequestScanAsyncDefault(&kWifiScanningCookie);
704     return;
705   }
706 
707   if (*cookie == kRangingRequestRetryTimerCookie) {
708     gRangingRequestRetryTimerHandle = CHRE_TIMER_INVALID;
709     requestRangingForFeatureWifiRtt();
710     return;
711   }
712 
713   if (*cookie == kWwanRequestRetryTimerCookie) {
714     gWwanRequestRetryTimerHandle = CHRE_TIMER_INVALID;
715     if (chreWwanGetCellInfoAsync(&kWwanCellInfoCookie)) {
716       return;
717     }
718     LOGE("Failed to re-request WWAN cell info, rejected for processing");
719   }
720 
721   // Ignore the audio status timer if the suspended status was received.
722   if (*cookie == kAudioStatusTimerCookie && !mAudioSamplingEnabled) {
723     gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
724     return;
725   }
726 
727   if (*cookie == kAudioDataTimerCookie) {
728     gAudioDataTimerHandle = CHRE_TIMER_INVALID;
729     testSuccess = true;
730   } else if (*cookie == kAudioStatusTimerCookie) {
731     gAudioStatusTimerHandle = CHRE_TIMER_INVALID;
732     LOGE("Source wasn't suspended when Mic Access was disabled");
733   } else {
734     LOGE("Invalid timer cookie: %" PRIx32, *cookie);
735   }
736   chreAudioConfigureSource(/*handle=*/0, /*enable=*/false,
737                            /*minBufferDuration=*/0, /*maxBufferDuration=*/0);
738   sendTestResult(mTestSession->hostEndpointId, testSuccess);
739 }
740 
handleBleAsyncResult(const chreAsyncResult * result)741 void Manager::handleBleAsyncResult(const chreAsyncResult *result) {
742   bool success = false;
743   switch (result->requestType) {
744     case CHRE_BLE_REQUEST_TYPE_START_SCAN: {
745       if (mTestSession->feature != Feature::BLE_SCANNING) {
746         LOGE("Unexpected BLE scan async result: test feature %" PRIu8,
747              static_cast<uint8_t>(mTestSession->feature));
748       } else {
749         success = validateAsyncResult(result, nullptr);
750       }
751       break;
752     }
753     default:
754       LOGE("Unexpected BLE request type %" PRIu8, result->requestType);
755   }
756 
757   sendTestResult(mTestSession->hostEndpointId, success);
758 }
759 
sendTestResult(uint16_t hostEndpointId,bool success)760 void Manager::sendTestResult(uint16_t hostEndpointId, bool success) {
761   test_shared::sendTestResultToHost(hostEndpointId,
762                                     chre_settings_test_MessageType_TEST_RESULT,
763                                     success, /*abortOnFailure=*/false);
764   mTestSession.reset();
765   mCachedRangingTarget.reset();
766 }
767 
768 }  // namespace settings_test
769 
770 }  // namespace chre
771