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