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(&params, &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