1 /*
2 * Copyright (C) 2021 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_stress_test_manager.h"
18
19 #include <pb_decode.h>
20
21 #include "chre/util/macros.h"
22 #include "chre/util/nanoapp/callbacks.h"
23 #include "chre/util/nanoapp/log.h"
24 #include "chre_stress_test.nanopb.h"
25 #include "send_message.h"
26
27 #define LOG_TAG "[ChreStressTest]"
28
29 namespace chre {
30
31 namespace stress_test {
32
33 namespace {
34
35 constexpr chre::Nanoseconds kWifiScanInterval = chre::Seconds(5);
36
isRequestTypeForLocation(uint8_t requestType)37 bool isRequestTypeForLocation(uint8_t requestType) {
38 return (requestType == CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_START) ||
39 (requestType == CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_STOP);
40 }
41
isRequestTypeForMeasurement(uint8_t requestType)42 bool isRequestTypeForMeasurement(uint8_t requestType) {
43 return (requestType == CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_START) ||
44 (requestType == CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_STOP);
45 }
46
47 } // anonymous namespace
48
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)49 void Manager::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
50 const void *eventData) {
51 if (eventType == CHRE_EVENT_MESSAGE_FROM_HOST) {
52 handleMessageFromHost(
53 senderInstanceId,
54 static_cast<const chreMessageFromHostData *>(eventData));
55 } else if (senderInstanceId == CHRE_INSTANCE_ID) {
56 handleDataFromChre(eventType, eventData);
57 } else {
58 LOGW("Got unknown event type from senderInstanceId %" PRIu32
59 " and with eventType %" PRIu16,
60 senderInstanceId, eventType);
61 }
62 }
63
handleMessageFromHost(uint32_t senderInstanceId,const chreMessageFromHostData * hostData)64 void Manager::handleMessageFromHost(uint32_t senderInstanceId,
65 const chreMessageFromHostData *hostData) {
66 bool success = false;
67 uint32_t messageType = hostData->messageType;
68 if (senderInstanceId != CHRE_INSTANCE_ID) {
69 LOGE("Incorrect sender instance id: %" PRIu32, senderInstanceId);
70 } else if (messageType == chre_stress_test_MessageType_TEST_HOST_RESTARTED) {
71 // Do nothing and only update the host endpoint
72 mHostEndpoint = hostData->hostEndpoint;
73 success = true;
74 } else if (messageType != chre_stress_test_MessageType_TEST_COMMAND) {
75 LOGE("Invalid message type %" PRIu32, messageType);
76 } else if (mHostEndpoint.has_value() &&
77 hostData->hostEndpoint != mHostEndpoint.value()) {
78 LOGE("Invalid host endpoint %" PRIu16 " expected %" PRIu16,
79 hostData->hostEndpoint, mHostEndpoint.value());
80 } else {
81 pb_istream_t istream = pb_istream_from_buffer(
82 static_cast<const pb_byte_t *>(hostData->message),
83 hostData->messageSize);
84 chre_stress_test_TestCommand testCommand =
85 chre_stress_test_TestCommand_init_default;
86
87 if (!pb_decode(&istream, chre_stress_test_TestCommand_fields,
88 &testCommand)) {
89 LOGE("Failed to decode start command error %s", PB_GET_ERROR(&istream));
90 } else {
91 LOGI("Got message from host: feature %d start %d", testCommand.feature,
92 testCommand.start);
93
94 success = true;
95 switch (testCommand.feature) {
96 case chre_stress_test_TestCommand_Feature_WIFI_ON_DEMAND_SCAN: {
97 handleWifiStartCommand(testCommand.start);
98 break;
99 }
100 case chre_stress_test_TestCommand_Feature_GNSS_LOCATION: {
101 handleGnssLocationStartCommand(testCommand.start);
102 break;
103 }
104 case chre_stress_test_TestCommand_Feature_GNSS_MEASUREMENT: {
105 handleGnssMeasurementStartCommand(testCommand.start);
106 break;
107 }
108 case chre_stress_test_TestCommand_Feature_WWAN: {
109 handleWwanStartCommand(testCommand.start);
110 break;
111 }
112 case chre_stress_test_TestCommand_Feature_WIFI_SCAN_MONITOR: {
113 handleWifiScanMonitoringCommand(testCommand.start);
114 break;
115 }
116 default: {
117 LOGE("Unknown feature %d", testCommand.feature);
118 success = false;
119 break;
120 }
121 }
122 }
123
124 mHostEndpoint = hostData->hostEndpoint;
125 }
126
127 if (!success) {
128 test_shared::sendTestResultWithMsgToHost(
129 hostData->hostEndpoint,
130 chre_stress_test_MessageType_TEST_RESULT /* messageType */, success,
131 nullptr /* errMessage */);
132 }
133 }
134
handleDataFromChre(uint16_t eventType,const void * eventData)135 void Manager::handleDataFromChre(uint16_t eventType, const void *eventData) {
136 switch (eventType) {
137 case CHRE_EVENT_TIMER:
138 handleTimerEvent(static_cast<const uint32_t *>(eventData));
139 break;
140
141 case CHRE_EVENT_WIFI_ASYNC_RESULT:
142 handleWifiAsyncResult(static_cast<const chreAsyncResult *>(eventData));
143 break;
144
145 case CHRE_EVENT_WIFI_SCAN_RESULT:
146 handleWifiScanEvent(static_cast<const chreWifiScanEvent *>(eventData));
147 break;
148
149 case CHRE_EVENT_GNSS_ASYNC_RESULT:
150 handleGnssAsyncResult(static_cast<const chreAsyncResult *>(eventData));
151 break;
152
153 case CHRE_EVENT_GNSS_LOCATION:
154 handleGnssLocationEvent(
155 static_cast<const chreGnssLocationEvent *>(eventData));
156 break;
157
158 case CHRE_EVENT_GNSS_DATA:
159 handleGnssDataEvent(static_cast<const chreGnssDataEvent *>(eventData));
160 break;
161
162 case CHRE_EVENT_WWAN_CELL_INFO_RESULT:
163 handleCellInfoResult(
164 static_cast<const chreWwanCellInfoResult *>(eventData));
165 break;
166
167 default:
168 LOGW("Unknown event type %" PRIu16, eventType);
169 break;
170 }
171 }
172
handleTimerEvent(const uint32_t * handle)173 void Manager::handleTimerEvent(const uint32_t *handle) {
174 if (*handle == mWifiScanTimerHandle) {
175 handleDelayedWifiTimer();
176 } else if (*handle == mWifiScanAsyncTimerHandle) {
177 sendFailure("WiFi scan request timed out");
178 } else if (*handle == mGnssLocationTimerHandle) {
179 makeGnssLocationRequest();
180 } else if (*handle == mGnssMeasurementTimerHandle) {
181 makeGnssMeasurementRequest();
182 } else if (*handle == mGnssLocationAsyncTimerHandle &&
183 mGnssLocationAsyncRequest.has_value()) {
184 sendFailure("GNSS location async result timed out");
185 } else if (*handle == mGnssMeasurementAsyncTimerHandle &&
186 mGnssMeasurementAsyncRequest.has_value()) {
187 sendFailure("GNSS measurement async result timed out");
188 } else if (*handle == mWwanTimerHandle) {
189 makeWwanCellInfoRequest();
190 } else if (*handle == mWifiScanMonitorAsyncTimerHandle) {
191 sendFailure("WiFi scan monitor request timed out");
192 } else {
193 sendFailure("Unknown timer handle");
194 }
195 }
196
handleDelayedWifiTimer()197 void Manager::handleDelayedWifiTimer() {
198 // NOTE: We set the maxScanAgeMs to something smaller than the WiFi
199 // scan periodicity to ensure new scans are generated.
200 static const struct chreWifiScanParams params = {
201 /*.scanType=*/CHRE_WIFI_SCAN_TYPE_NO_PREFERENCE,
202 /*.maxScanAgeMs=*/2000, // 2 seconds
203 /*.frequencyListLen=*/0,
204 /*.frequencyList=*/NULL,
205 /*.ssidListLen=*/0,
206 /*.ssidList=*/NULL,
207 /*.radioChainPref=*/CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT,
208 /*.channelSet=*/CHRE_WIFI_CHANNEL_SET_NON_DFS};
209
210 bool success = chreWifiRequestScanAsync(¶ms, &kOnDemandWifiScanCookie);
211 LOGI("Requested on demand wifi success ? %d", success);
212 if (!success) {
213 sendFailure("Failed to make WiFi scan request");
214 } else {
215 mWifiScanAsyncRequest = AsyncRequest(&kOnDemandWifiScanCookie);
216 setTimer(CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS, true /* oneShot */,
217 &mWifiScanAsyncTimerHandle);
218 }
219 }
220
handleWifiAsyncResult(const chreAsyncResult * result)221 void Manager::handleWifiAsyncResult(const chreAsyncResult *result) {
222 if (result->requestType == CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN) {
223 if (result->success) {
224 LOGI("On-demand scan success");
225 } else {
226 LOGW("On-demand scan failed: code %" PRIu8, result->errorCode);
227 }
228
229 if (!mWifiScanAsyncRequest.has_value()) {
230 sendFailure("Received WiFi async result with no pending request");
231 } else if (result->cookie != mWifiScanAsyncRequest->cookie) {
232 sendFailure("On-demand scan cookie mismatch");
233 }
234
235 cancelTimer(&mWifiScanAsyncTimerHandle);
236 mWifiScanAsyncRequest.reset();
237 requestDelayedWifiScan();
238 } else if (result->requestType ==
239 CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR) {
240 if (!result->success) {
241 LOGE("Scan monitor async failure: code %" PRIu8, result->errorCode);
242 sendFailure("Scan monitor async failed");
243 }
244
245 cancelTimer(&mWifiScanMonitorAsyncTimerHandle);
246 mWifiScanMonitorEnabled = (result->cookie != nullptr);
247 } else {
248 sendFailure("Unknown WiFi async result type");
249 }
250 }
251
handleGnssAsyncResult(const chreAsyncResult * result)252 void Manager::handleGnssAsyncResult(const chreAsyncResult *result) {
253 if (isRequestTypeForLocation(result->requestType)) {
254 validateGnssAsyncResult(result, mGnssLocationAsyncRequest,
255 &mGnssLocationAsyncTimerHandle);
256 } else if (isRequestTypeForMeasurement(result->requestType)) {
257 validateGnssAsyncResult(result, mGnssMeasurementAsyncRequest,
258 &mGnssMeasurementAsyncTimerHandle);
259 } else {
260 sendFailure("Unknown GNSS async result type");
261 }
262 }
263
validateGnssAsyncResult(const chreAsyncResult * result,Optional<AsyncRequest> & request,uint32_t * asyncTimerHandle)264 void Manager::validateGnssAsyncResult(const chreAsyncResult *result,
265 Optional<AsyncRequest> &request,
266 uint32_t *asyncTimerHandle) {
267 if (!request.has_value()) {
268 sendFailure("Received GNSS async result with no pending request");
269 } else if (!result->success) {
270 sendFailure("Async GNSS failure");
271 } else if (result->cookie != request->cookie) {
272 sendFailure("GNSS async cookie mismatch");
273 }
274
275 cancelTimer(asyncTimerHandle);
276 request.reset();
277 }
278
checkTimestamp(uint64_t timestamp,uint64_t pastTimestamp)279 void Manager::checkTimestamp(uint64_t timestamp, uint64_t pastTimestamp) {
280 if (timestamp < pastTimestamp) {
281 sendFailure("Timestamp was too old");
282 } else if (timestamp == pastTimestamp) {
283 sendFailure("Timestamp was duplicate");
284 }
285 }
286
handleGnssLocationEvent(const chreGnssLocationEvent * event)287 void Manager::handleGnssLocationEvent(const chreGnssLocationEvent *event) {
288 LOGI("Received GNSS location event at %" PRIu64 " ms", event->timestamp);
289
290 checkTimestamp(event->timestamp, mPrevGnssLocationEventTimestampMs);
291 mPrevGnssLocationEventTimestampMs = event->timestamp;
292 }
293
handleGnssDataEvent(const chreGnssDataEvent * event)294 void Manager::handleGnssDataEvent(const chreGnssDataEvent *event) {
295 static uint32_t sPrevDiscontCount = 0;
296 LOGI("Received GNSS measurement event at %" PRIu64 " ns count %" PRIu32
297 " flags 0x%" PRIx16,
298 event->clock.time_ns, event->clock.hw_clock_discontinuity_count,
299 event->clock.flags);
300
301 if (sPrevDiscontCount == event->clock.hw_clock_discontinuity_count) {
302 checkTimestamp(event->clock.time_ns, mPrevGnssMeasurementEventTimestampNs);
303 }
304
305 sPrevDiscontCount = event->clock.hw_clock_discontinuity_count;
306 mPrevGnssMeasurementEventTimestampNs = event->clock.time_ns;
307 }
308
handleWifiScanEvent(const chreWifiScanEvent * event)309 void Manager::handleWifiScanEvent(const chreWifiScanEvent *event) {
310 LOGI("Received Wifi scan event of type %" PRIu8 " with %" PRIu8
311 " results at %" PRIu64 " ns",
312 event->scanType, event->resultCount, event->referenceTime);
313
314 if (event->eventIndex == 0) {
315 checkTimestamp(event->referenceTime, mPrevWifiScanEventTimestampNs);
316 mPrevWifiScanEventTimestampNs = event->referenceTime;
317 }
318
319 if (mWifiScanMonitorEnabled) {
320 chreSendMessageToHostEndpoint(
321 nullptr, 0,
322 chre_stress_test_MessageType_TEST_WIFI_SCAN_MONITOR_TRIGGERED,
323 mHostEndpoint.value(), nullptr /* freeCallback */);
324 }
325 }
326
handleCellInfoResult(const chreWwanCellInfoResult * event)327 void Manager::handleCellInfoResult(const chreWwanCellInfoResult *event) {
328 LOGI("Received %" PRIu8 " cell info results", event->cellInfoCount);
329
330 mWwanCellInfoAsyncRequest.reset();
331 if (event->errorCode != CHRE_ERROR_NONE) {
332 LOGE("Cell info request failed with error code %" PRIu8, event->errorCode);
333 sendFailure("Cell info request failed");
334 } else if (event->cellInfoCount > 0) {
335 uint64_t maxTimestamp = 0;
336 for (uint8_t i = 0; i < event->cellInfoCount; i++) {
337 maxTimestamp = MAX(maxTimestamp, event->cells[i].timeStamp);
338 checkTimestamp(event->cells[i].timeStamp,
339 mPrevWwanCellInfoEventTimestampNs);
340 }
341
342 mPrevWwanCellInfoEventTimestampNs = maxTimestamp;
343 }
344 }
345
handleWifiStartCommand(bool start)346 void Manager::handleWifiStartCommand(bool start) {
347 mWifiTestStarted = start;
348 if (start) {
349 requestDelayedWifiScan();
350 } else {
351 cancelTimer(&mWifiScanTimerHandle);
352 }
353 }
354
handleGnssLocationStartCommand(bool start)355 void Manager::handleGnssLocationStartCommand(bool start) {
356 constexpr uint64_t kTimerDelayNs = Seconds(60).toRawNanoseconds();
357
358 if (chreGnssGetCapabilities() & CHRE_GNSS_CAPABILITIES_LOCATION) {
359 mGnssLocationTestStarted = start;
360 makeGnssLocationRequest();
361
362 if (start) {
363 setTimer(kTimerDelayNs, false /* oneShot */, &mGnssLocationTimerHandle);
364 } else {
365 cancelTimer(&mGnssLocationTimerHandle);
366 }
367 } else {
368 sendFailure("Platform has no location capability");
369 }
370 }
371
handleGnssMeasurementStartCommand(bool start)372 void Manager::handleGnssMeasurementStartCommand(bool start) {
373 constexpr uint64_t kTimerDelayNs = Seconds(60).toRawNanoseconds();
374
375 if (chreGnssGetCapabilities() & CHRE_GNSS_CAPABILITIES_MEASUREMENTS) {
376 mGnssMeasurementTestStarted = start;
377 makeGnssMeasurementRequest();
378
379 if (start) {
380 setTimer(kTimerDelayNs, false /* oneShot */,
381 &mGnssMeasurementTimerHandle);
382 } else {
383 cancelTimer(&mGnssMeasurementTimerHandle);
384 }
385 } else {
386 sendFailure("Platform has no GNSS measurement capability");
387 }
388 }
389
handleWwanStartCommand(bool start)390 void Manager::handleWwanStartCommand(bool start) {
391 constexpr uint64_t kTimerDelayNs = CHRE_ASYNC_RESULT_TIMEOUT_NS;
392
393 if (chreWwanGetCapabilities() & CHRE_WWAN_GET_CELL_INFO) {
394 mWwanTestStarted = start;
395 makeWwanCellInfoRequest();
396
397 if (start) {
398 setTimer(kTimerDelayNs, false /* oneShot */, &mWwanTimerHandle);
399 } else {
400 cancelTimer(&mWwanTimerHandle);
401 }
402 } else {
403 sendFailure("Platform has no WWAN cell info capability");
404 }
405 }
406
handleWifiScanMonitoringCommand(bool start)407 void Manager::handleWifiScanMonitoringCommand(bool start) {
408 if (chreWifiGetCapabilities() & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
409 const uint32_t kWifiScanMonitorEnabledCookie = 0x1234;
410 bool success = chreWifiConfigureScanMonitorAsync(
411 start, start ? &kWifiScanMonitorEnabledCookie : nullptr);
412 LOGI("Scan monitor enable %d request success ? %d", start, success);
413
414 if (!success) {
415 sendFailure("Scan monitor request failed");
416 } else {
417 setTimer(CHRE_ASYNC_RESULT_TIMEOUT_NS, true /* oneShot */,
418 &mWifiScanMonitorAsyncTimerHandle);
419 }
420 } else {
421 sendFailure("Platform has no WiFi scan monitoring capability");
422 }
423 }
424
setTimer(uint64_t delayNs,bool oneShot,uint32_t * timerHandle)425 void Manager::setTimer(uint64_t delayNs, bool oneShot, uint32_t *timerHandle) {
426 *timerHandle = chreTimerSet(delayNs, timerHandle, oneShot);
427 if (*timerHandle == CHRE_TIMER_INVALID) {
428 sendFailure("Failed to set timer");
429 }
430 }
431
cancelTimer(uint32_t * timerHandle)432 void Manager::cancelTimer(uint32_t *timerHandle) {
433 if (*timerHandle != CHRE_TIMER_INVALID) {
434 if (!chreTimerCancel(*timerHandle)) {
435 // We don't treat this as a test failure, because the CHRE API does not
436 // guarantee this method succeeds (e.g. if the timer is one-shot and just
437 // fired).
438 LOGW("Failed to cancel timer");
439 }
440 *timerHandle = CHRE_TIMER_INVALID;
441 }
442 }
443
makeGnssLocationRequest()444 void Manager::makeGnssLocationRequest() {
445 // The list of location intervals to iterate; wraps around.
446 static const uint32_t kMinIntervalMsList[] = {1000, 0};
447 static size_t sIntervalIndex = 0;
448
449 uint32_t minIntervalMs = 0;
450 if (mGnssLocationTestStarted) {
451 minIntervalMs = kMinIntervalMsList[sIntervalIndex];
452 sIntervalIndex = (sIntervalIndex + 1) % ARRAY_SIZE(kMinIntervalMsList);
453 } else {
454 sIntervalIndex = 0;
455 }
456
457 bool success = false;
458 if (minIntervalMs > 0) {
459 success = chreGnssLocationSessionStartAsync(
460 minIntervalMs, 0 /* minTimeToNextFixMs */, &kGnssLocationCookie);
461 } else {
462 success = chreGnssLocationSessionStopAsync(&kGnssLocationCookie);
463 }
464
465 LOGI("Configure GNSS location interval %" PRIu32 " ms success ? %d",
466 minIntervalMs, success);
467
468 if (!success) {
469 sendFailure("Failed to make location request");
470 } else {
471 mGnssLocationAsyncRequest = AsyncRequest(&kGnssLocationCookie);
472 setTimer(CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS, true /* oneShot */,
473 &mGnssLocationAsyncTimerHandle);
474 }
475 }
476
makeGnssMeasurementRequest()477 void Manager::makeGnssMeasurementRequest() {
478 // The list of measurement intervals to iterate; wraps around.
479 static const uint32_t kMinIntervalMsList[] = {1000, 0};
480 static size_t sIntervalIndex = 0;
481
482 uint32_t minIntervalMs = 0;
483 if (mGnssMeasurementTestStarted) {
484 minIntervalMs = kMinIntervalMsList[sIntervalIndex];
485 sIntervalIndex = (sIntervalIndex + 1) % ARRAY_SIZE(kMinIntervalMsList);
486 } else {
487 sIntervalIndex = 0;
488 }
489
490 bool success = false;
491 if (minIntervalMs > 0) {
492 success = chreGnssMeasurementSessionStartAsync(minIntervalMs,
493 &kGnssMeasurementCookie);
494 } else {
495 success = chreGnssMeasurementSessionStopAsync(&kGnssMeasurementCookie);
496 // Reset the previous timestamp, since the GNSS internal clock may reset.
497 mPrevGnssMeasurementEventTimestampNs = 0;
498 }
499
500 LOGI("Configure GNSS measurement interval %" PRIu32 " ms success ? %d",
501 minIntervalMs, success);
502
503 if (!success) {
504 sendFailure("Failed to make measurement request");
505 } else {
506 mGnssMeasurementAsyncRequest = AsyncRequest(&kGnssMeasurementCookie);
507 setTimer(CHRE_GNSS_ASYNC_RESULT_TIMEOUT_NS, true /* oneShot */,
508 &mGnssMeasurementAsyncTimerHandle);
509 }
510 }
511
requestDelayedWifiScan()512 void Manager::requestDelayedWifiScan() {
513 if (mWifiTestStarted) {
514 if (chreWifiGetCapabilities() & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) {
515 setTimer(kWifiScanInterval.toRawNanoseconds(), true /* oneShot */,
516 &mWifiScanTimerHandle);
517 } else {
518 sendFailure("Platform has no on-demand scan capability");
519 }
520 }
521 }
522
makeWwanCellInfoRequest()523 void Manager::makeWwanCellInfoRequest() {
524 if (mWwanTestStarted) {
525 if (mWwanCellInfoAsyncRequest.has_value()) {
526 if (chreGetTime() > mWwanCellInfoAsyncRequest->requestTimeNs +
527 CHRE_ASYNC_RESULT_TIMEOUT_NS) {
528 sendFailure("Prev cell info request did not complete in time");
529 }
530 } else {
531 bool success = chreWwanGetCellInfoAsync(&kWwanCellInfoCookie);
532
533 LOGI("Cell info request success ? %d", success);
534
535 if (!success) {
536 sendFailure("Failed to make cell info request");
537 } else {
538 mWwanCellInfoAsyncRequest = AsyncRequest(&kWwanCellInfoCookie);
539 }
540 }
541 }
542 }
543
sendFailure(const char * errorMessage)544 void Manager::sendFailure(const char *errorMessage) {
545 test_shared::sendTestResultWithMsgToHost(
546 mHostEndpoint.value(),
547 chre_stress_test_MessageType_TEST_RESULT /* messageType */,
548 false /* success */, errorMessage);
549 }
550
551 } // namespace stress_test
552
553 } // namespace chre
554