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