1 /*
2 * Copyright (C) 2016 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 <general_test/basic_sensor_test_base.h>
18
19 #include <cinttypes>
20 #include <cstddef>
21
22 #include <shared/send_message.h>
23 #include <shared/time_util.h>
24
25 #include "chre/util/nanoapp/log.h"
26
27 #include <chre.h>
28
29 #define LOG_TAG "[BasicSensorTest]"
30
31 using nanoapp_testing::kOneMillisecondInNanoseconds;
32 using nanoapp_testing::kOneSecondInNanoseconds;
33 using nanoapp_testing::MessageType;
34 using nanoapp_testing::sendFatalFailureToHost;
35 using nanoapp_testing::sendFatalFailureToHostUint8;
36 using nanoapp_testing::sendInternalFailureToHost;
37 using nanoapp_testing::sendStringToHost;
38 using nanoapp_testing::sendSuccessToHost;
39
40 /*
41 * Our general test flow is as follows:
42 *
43 * Constructor: Send startEvent to self to start.
44 * StartEvent: Get default sensor and perform various consistency checks.
45 * Configure the sensor.
46 *
47 * At this point, it depends what kind of sensor we have for how we proceed
48 * with the test.
49 *
50 * One-shot: finishTest()
51 * On-change: Wait for one data event from sensor. Then finishTest().
52 * Continuous: Wait for two data events from sensor. Then finishTest().
53 *
54 * We also look for and perform basic consistency checking on sampling
55 * status change events, as well as bias data reports.
56 */
57
58 namespace general_test {
59
60 namespace {
61 constexpr uint16_t kStartEvent = CHRE_EVENT_FIRST_USER_VALUE;
62 constexpr uint64_t kEventLoopSlack = 100 * kOneMillisecondInNanoseconds;
63
getEventDuration(const chreSensorThreeAxisData * event)64 uint64_t getEventDuration(const chreSensorThreeAxisData *event) {
65 uint64_t duration = 0;
66 for (size_t i = 0; i < event->header.readingCount; i++) {
67 duration += event->readings[i].timestampDelta;
68 }
69
70 return duration;
71 }
72
isBiasEventType(uint16_t eventType)73 bool isBiasEventType(uint16_t eventType) {
74 return (eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO) ||
75 (eventType == CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO) ||
76 (eventType == CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO);
77 }
78
79 } // anonymous namespace
80
BasicSensorTestBase()81 BasicSensorTestBase::BasicSensorTestBase()
82 : Test(CHRE_API_VERSION_1_0),
83 mInMethod(true),
84 mExternalSamplingStatusChange(false),
85 mState(State::kPreStart),
86 mInstanceId(chreGetInstanceId())
87 /* All other members initialized later */ {}
88
setUp(uint32_t messageSize,const void *)89 void BasicSensorTestBase::setUp(uint32_t messageSize,
90 const void * /* message */) {
91 if (messageSize != 0) {
92 sendFatalFailureToHost("Beginning message expects 0 additional bytes, got ",
93 &messageSize);
94 }
95
96 sendStartTestMessage();
97 }
98
sendStartTestMessage()99 void BasicSensorTestBase::sendStartTestMessage() {
100 mState = State::kPreStart;
101 // Most tests start running in the constructor. However, since this
102 // is a base class, and we invoke abstract methods when running our
103 // test, we don't start until after the class has been fully
104 // constructed.
105 if (!chreSendEvent(kStartEvent, nullptr, nullptr, mInstanceId)) {
106 sendFatalFailureToHost("Failed chreSendEvent to begin test");
107 }
108 mInMethod = false;
109 }
110
checkPassiveConfigure()111 void BasicSensorTestBase::checkPassiveConfigure() {
112 chreSensorConfigureMode mode =
113 isOneShotSensor() ? CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_ONE_SHOT
114 : CHRE_SENSOR_CONFIGURE_MODE_PASSIVE_CONTINUOUS;
115
116 if (mApiVersion == CHRE_API_VERSION_1_0) {
117 // Any attempt to make a PASSIVE call with a non-default interval
118 // or latency should fail.
119 if (chreSensorConfigure(mSensorHandle, mode, CHRE_SENSOR_INTERVAL_DEFAULT,
120 999)) {
121 sendFatalFailureToHost(
122 "chreSensorConfigure() allowed passive with different latency");
123 }
124 if (chreSensorConfigure(mSensorHandle, mode, 999,
125 CHRE_SENSOR_LATENCY_DEFAULT)) {
126 sendFatalFailureToHost(
127 "chreSensorConfigure() allowed passive with different interval");
128 }
129 // TODO: In a more in-depth test, we should test passive mode
130 // receiving data. This is somewhat complicated by the fact that
131 // pretty much by definition, we don't control whether a sensor
132 // we're passively listening to is enabled or not. We could try
133 // to control this with an additional test nanoapp toggling sensor
134 // usage, but there's still the complication of other nanoapps in
135 // the system.
136 } else {
137 bool configureSuccess =
138 chreSensorConfigure(mSensorHandle, mode, CHRE_SENSOR_INTERVAL_DEFAULT,
139 kOneSecondInNanoseconds);
140 if (mSupportsPassiveMode && !configureSuccess) {
141 sendFatalFailureToHost(
142 "chreSensorConfigure() failed passive with default interval and "
143 "non-default latency");
144 } else if (!mSupportsPassiveMode && configureSuccess) {
145 sendFatalFailureToHost(
146 "chreSensorConfigure() accepted passive with default interval and "
147 "non-default latency");
148 }
149
150 if (!isOneShotSensor()) {
151 configureSuccess =
152 chreSensorConfigure(mSensorHandle, mode, kOneSecondInNanoseconds,
153 CHRE_SENSOR_LATENCY_DEFAULT);
154 if (mSupportsPassiveMode && !configureSuccess) {
155 sendFatalFailureToHost(
156 "chreSensorConfigure() failed passive with non-default interval "
157 "and default latency");
158 } else if (!mSupportsPassiveMode && configureSuccess) {
159 sendFatalFailureToHost(
160 "chreSensorConfigure() accepted passive with non-default "
161 "interval and default latency");
162 }
163
164 configureSuccess =
165 chreSensorConfigure(mSensorHandle, mode, kOneSecondInNanoseconds,
166 kOneSecondInNanoseconds);
167 if (mSupportsPassiveMode && !configureSuccess) {
168 sendFatalFailureToHost(
169 "chreSensorConfigure() failed passive with non-default interval "
170 "and latency");
171 } else if (!mSupportsPassiveMode && configureSuccess) {
172 sendFatalFailureToHost(
173 "chreSensorConfigure() accepted passive with non-default interval "
174 "and latency");
175 }
176 }
177 }
178 }
179
startTest()180 void BasicSensorTestBase::startTest() {
181 mState = State::kPreConfigure;
182
183 bool found = false;
184 if (mApiVersion >= CHRE_API_VERSION_1_5) {
185 found =
186 chreSensorFind(getSensorType(), mCurrentSensorIndex, &mSensorHandle);
187 if (!found && chreSensorFind(getSensorType(), mCurrentSensorIndex + 1,
188 &mSensorHandle)) {
189 sendFatalFailureToHostUint8("Missing sensor index ", mCurrentSensorIndex);
190 return;
191 }
192 } else {
193 found = chreSensorFindDefault(getSensorType(), &mSensorHandle);
194 }
195
196 if (!found) {
197 sendStringToHost(MessageType::kSkipped,
198 "No default sensor found for optional sensor.");
199 return;
200 }
201
202 LOGI("Starting test for sensor index %" PRIu8, mCurrentSensorIndex);
203
204 chreSensorInfo info;
205 if (!chreGetSensorInfo(mSensorHandle, &info)) {
206 sendFatalFailureToHost("GetSensorInfo() call failed");
207 }
208 if (info.sensorName == nullptr) {
209 sendFatalFailureToHost("chreSensorInfo::sensorName is NULL");
210 }
211 if (info.sensorType != getSensorType()) {
212 uint32_t type = info.sensorType;
213 sendFatalFailureToHost(
214 "chreSensorInfo::sensorType is not expected value, is:", &type);
215 }
216 if (info.isOnChange != isOnChangeSensor()) {
217 sendFatalFailureToHost(
218 "chreSensorInfo::isOnChange is opposite of what we expected");
219 }
220 if (info.isOneShot != isOneShotSensor()) {
221 sendFatalFailureToHost(
222 "chreSensorInfo::isOneShot is opposite of what we expected");
223 }
224 if (mApiVersion >= CHRE_API_VERSION_1_4) {
225 mSupportsPassiveMode = info.supportsPassiveMode;
226 } else if (info.supportsPassiveMode != 0) {
227 sendFatalFailureToHost("chreSensorInfo::supportsPassiveMode should be 0");
228 }
229
230 if (!chreGetSensorSamplingStatus(mSensorHandle, &mOriginalStatus)) {
231 sendFatalFailureToHost("chreGetSensorSamplingStatus() failed");
232 }
233
234 // Set the base timestamp to compare against before configuring the sensor.
235 mPreTimestamp = chreGetTime();
236
237 // Default interval/latency must be accepted by all sensors.
238 mNewStatus = {
239 CHRE_SENSOR_INTERVAL_DEFAULT, /* interval */
240 CHRE_SENSOR_LATENCY_DEFAULT, /* latency */
241 true /* enabled */
242 };
243 chreSensorConfigureMode mode = isOneShotSensor()
244 ? CHRE_SENSOR_CONFIGURE_MODE_ONE_SHOT
245 : CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS;
246
247 if (!chreSensorConfigure(mSensorHandle, mode, mNewStatus.interval,
248 mNewStatus.latency)) {
249 sendFatalFailureToHost(
250 "chreSensorConfigure() call failed with default interval and latency");
251 }
252 // handleEvent may start getting events, and our testing continues there.
253 // (Note: The CHRE is not allow to call handleEvent() while we're still
254 // in this method, so it's not a race to set this state here.)
255
256 // Set a new request so the test can receive events before test timeout.
257 mNewStatus = {
258 // This will be valid on all required sensors.
259 // TODO: A more in-depth test could try to change this interval
260 // from what it currently is for the sensor, and confirm it
261 // changes back when we're DONE. But that's beyond the current
262 // scope of this 'basic' test.
263 kOneSecondInNanoseconds, /* interval */
264 // We want the test to run as quickly as possible.
265 // TODO: Similar to the interval, we could try to test changes in
266 // this value, but it's beyond our 'basic' scope for now.
267 CHRE_SENSOR_LATENCY_ASAP, /* latency */
268 true /* enabled */
269 };
270
271 // Skip one-shot sensors for non-default interval configurations.
272 if (!isOneShotSensor() &&
273 !chreSensorConfigure(mSensorHandle, mode, mNewStatus.interval,
274 mNewStatus.latency)) {
275 sendFatalFailureToHost("chreSensorConfigure() call failed");
276 }
277
278 if (isOnChangeSensor()) {
279 // We should receive the current state of this sensor after the
280 // configure call. However, we're not assured additional events,
281 // since we don't know if this is going to change. Thus, we jump
282 // our testing state to waiting for the last event.
283 mState = State::kExpectingLastDataEvent;
284 } else if (isOneShotSensor()) {
285 // There's no assurance we'll get any events from a one-shot
286 // sensor, so we'll just skip to the end of the test.
287 finishTest();
288 } else {
289 mState = State::kExpectingInitialDataEvent;
290 }
291 }
292
finishTest()293 void BasicSensorTestBase::finishTest() {
294 checkPassiveConfigure();
295
296 if (!chreSensorConfigureModeOnly(mSensorHandle,
297 CHRE_SENSOR_CONFIGURE_MODE_DONE)) {
298 sendFatalFailureToHost("Unable to configure sensor mode to DONE");
299 }
300 mDoneTimestamp = chreGetTime();
301 chreSensorSamplingStatus status;
302 if (!chreGetSensorSamplingStatus(mSensorHandle, &status)) {
303 sendFatalFailureToHost("Could not get final sensor info");
304 }
305 if (!mExternalSamplingStatusChange) {
306 // No one else changed this, so it should be what we had before.
307 if (status.enabled != mOriginalStatus.enabled) {
308 sendFatalFailureToHost("SensorInfo.enabled not back to original");
309 }
310 // Interval and latency values are only relevent if the sensor is enabled.
311 if (status.enabled) {
312 if (status.interval != mOriginalStatus.interval) {
313 sendFatalFailureToHost("SensorInfo.interval not back to original");
314 }
315 if (status.latency != mOriginalStatus.latency) {
316 sendFatalFailureToHost("SensorInfo.latency not back to original");
317 }
318 }
319 }
320
321 LOGI("Test passed for sensor index %" PRIu8, mCurrentSensorIndex);
322
323 bool finished = true;
324 if (mApiVersion >= CHRE_API_VERSION_1_5) {
325 mCurrentSensorIndex++;
326 uint32_t sensorHandle;
327 if (chreSensorFind(getSensorType(), mCurrentSensorIndex, &sensorHandle)) {
328 finished = false;
329 mPrevSensorHandle = mSensorHandle;
330 sendStartTestMessage();
331 }
332 }
333
334 if (finished) {
335 mState = State::kFinished;
336 sendSuccessToHost();
337 }
338 }
339
verifyEventHeader(const chreSensorDataHeader * header,uint16_t eventType,uint64_t eventDuration)340 void BasicSensorTestBase::verifyEventHeader(const chreSensorDataHeader *header,
341 uint16_t eventType,
342 uint64_t eventDuration) {
343 if (header->sensorHandle != mSensorHandle) {
344 sendFatalFailureToHost("SensorDataHeader for wrong handle",
345 &header->sensorHandle);
346 }
347
348 // Bias and on-change sensor events may have timestamps from before any of our
349 // requests started since they aren't generated in response to requests. For
350 // these types of events, only ensure the provided timestamp is less than the
351 // current time.
352 if (!isOnChangeSensor() && !isBiasEventType(eventType)) {
353 // An on-change sensor is supposed to send its current state, which
354 // could be timestamped in the past. Everything else should be
355 // getting recent data.
356 uint64_t *minTime = nullptr;
357 uint64_t *timeToUpdate = nullptr;
358
359 if (mState == State::kExpectingInitialDataEvent) {
360 minTime = &mPreTimestamp;
361 timeToUpdate = &mFirstEventTimestamp;
362 } else if (mState == State::kExpectingLastDataEvent) {
363 minTime = &mFirstEventTimestamp;
364 timeToUpdate = &mLastEventTimestamp;
365 } else { // State::kFinished
366 minTime = &mLastEventTimestamp;
367 // Go ahead and update this timestamp again.
368 timeToUpdate = &mLastEventTimestamp;
369 }
370
371 // If there's another CHRE client requesting batched sensor data,
372 // baseTimestamp can be before mPreTimestamp. Also allow
373 // kEventLoopSlack to handle this nanoapp before handling the sensor
374 // event.
375 uint64_t minTimeWithSlack =
376 (*minTime > eventDuration + kEventLoopSlack)
377 ? (*minTime - eventDuration - kEventLoopSlack)
378 : 0;
379 if (header->baseTimestamp < minTimeWithSlack) {
380 chreLog(CHRE_LOG_ERROR,
381 "baseTimestamp %" PRIu64 " < minTimeWithSlack %" PRIu64
382 ": minTime %" PRIu64 " eventDuration %" PRIu64
383 " kEventLoopSlack %" PRIu64,
384 header->baseTimestamp, minTimeWithSlack, *minTime, eventDuration,
385 kEventLoopSlack);
386 sendFatalFailureToHost("SensorDataHeader is in the past");
387 }
388 if ((mState == State::kFinished) &&
389 (header->baseTimestamp > mDoneTimestamp)) {
390 sendFatalFailureToHost("SensorDataHeader is from after DONE");
391 }
392 *timeToUpdate = header->baseTimestamp;
393 }
394
395 if (header->baseTimestamp > chreGetTime()) {
396 sendFatalFailureToHost("SensorDataHeader is in the future");
397 }
398
399 if (header->readingCount == 0) {
400 sendFatalFailureToHost("SensorDataHeader has readingCount of 0");
401 }
402
403 if (header->reserved != 0) {
404 sendFatalFailureToHost("SensorDataHeader has non-zero reserved field");
405 }
406
407 if (mApiVersion < CHRE_API_VERSION_1_3) {
408 if (header->accuracy != 0) {
409 sendFatalFailureToHost("SensorDataHeader has non-zero reserved field");
410 }
411 } else if (header->accuracy > CHRE_SENSOR_ACCURACY_HIGH) {
412 sendFatalFailureToHostUint8("Sensor accuracy is not within valid range: ",
413 header->accuracy);
414 }
415 }
416
handleBiasEvent(uint16_t eventType,const chreSensorThreeAxisData * eventData)417 void BasicSensorTestBase::handleBiasEvent(
418 uint16_t eventType, const chreSensorThreeAxisData *eventData) {
419 uint8_t expectedSensorType = 0;
420 uint32_t eType = eventType;
421 if (eventType == CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO) {
422 expectedSensorType = CHRE_SENSOR_TYPE_GYROSCOPE;
423 } else if (eventType == CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO) {
424 expectedSensorType = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD;
425 } else if (eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO) {
426 expectedSensorType = CHRE_SENSOR_TYPE_ACCELEROMETER;
427 } else {
428 sendInternalFailureToHost("Illegal eventType in handleBiasEvent", &eType);
429 }
430
431 if (expectedSensorType != getSensorType()) {
432 sendFatalFailureToHost("Unexpected bias event:", &eType);
433 }
434 verifyEventHeader(&eventData->header, eventType, getEventDuration(eventData));
435
436 // TODO: consistency check the eventData. This check is out-of-scope for
437 // Android N testing.
438 }
439
handleSamplingChangeEvent(const chreSensorSamplingStatusEvent * eventData)440 void BasicSensorTestBase::handleSamplingChangeEvent(
441 const chreSensorSamplingStatusEvent *eventData) {
442 if (mPrevSensorHandle.has_value() &&
443 (mPrevSensorHandle.value() == eventData->sensorHandle)) {
444 // We can get a "DONE" event from the previous sensor for multi-sensor
445 // devices, so we ignore these events.
446 return;
447 }
448
449 if (eventData->sensorHandle != mSensorHandle) {
450 sendFatalFailureToHost("SamplingChangeEvent for wrong sensor handle:",
451 &eventData->sensorHandle);
452 }
453
454 // TODO: If we strictly define whether this event is or isn't
455 // generated upon being DONE with a sensor, then we can perform
456 // a strict check here. For now, we just let this go.
457 if (mState != State::kFinished) {
458 // Passive sensor requests do not guarantee sensors will always be enabled.
459 // Bypass 'enabled' check for passive configurations.
460 if (!eventData->status.enabled) {
461 sendFatalFailureToHost("SamplingChangeEvent disabled the sensor.");
462 }
463
464 if ((mNewStatus.interval != eventData->status.interval) ||
465 (mNewStatus.latency != eventData->status.latency)) {
466 // This is from someone other than us. Let's note that so we know
467 // our consistency checks are invalid.
468 mExternalSamplingStatusChange = true;
469 }
470 }
471 }
472
handleSensorDataEvent(uint16_t eventType,const void * eventData)473 void BasicSensorTestBase::handleSensorDataEvent(uint16_t eventType,
474 const void *eventData) {
475 if ((mState == State::kPreStart) || (mState == State::kPreConfigure)) {
476 sendFatalFailureToHost("SensorDataEvent sent too early.");
477 }
478 // Note, if mState is kFinished, we could be getting batched data which
479 // hadn't been delivered yet at the time we were DONE. We'll consistency
480 // check it, even though in theory we're done testing.
481 uint64_t eventDuration =
482 getEventDuration(static_cast<const chreSensorThreeAxisData *>(eventData));
483 verifyEventHeader(static_cast<const chreSensorDataHeader *>(eventData),
484 eventType, eventDuration);
485
486 // Send to the sensor itself for any additional checks of actual data.
487 confirmDataIsSane(eventData);
488 if (mState == State::kExpectingInitialDataEvent) {
489 mState = State::kExpectingLastDataEvent;
490 } else if (mState == State::kExpectingLastDataEvent) {
491 finishTest();
492 } else if (mState != State::kFinished) {
493 uint32_t value = static_cast<uint32_t>(mState);
494 sendInternalFailureToHost("Illegal mState in handleSensorDataEvent:",
495 &value);
496 }
497 }
498
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)499 void BasicSensorTestBase::handleEvent(uint32_t senderInstanceId,
500 uint16_t eventType,
501 const void *eventData) {
502 if (mInMethod) {
503 sendFatalFailureToHost("handleEvent() invoked while already in method.");
504 }
505 mInMethod = true;
506 const uint16_t dataEventType =
507 CHRE_EVENT_SENSOR_DATA_EVENT_BASE + getSensorType();
508
509 if (senderInstanceId == mInstanceId) {
510 if ((eventType == kStartEvent) && (mState == State::kPreStart)) {
511 startTest();
512 }
513 } else if (senderInstanceId != CHRE_INSTANCE_ID) {
514 sendFatalFailureToHost("Unexpected senderInstanceId:", &senderInstanceId);
515
516 } else if (eventData == nullptr) {
517 uint32_t eType = eventType;
518 sendFatalFailureToHost("Got NULL eventData for event:", &eType);
519
520 } else if (eventType == dataEventType) {
521 handleSensorDataEvent(eventType, eventData);
522
523 } else if (eventType == CHRE_EVENT_SENSOR_SAMPLING_CHANGE) {
524 handleSamplingChangeEvent(
525 static_cast<const chreSensorSamplingStatusEvent *>(eventData));
526
527 } else if (isBiasEventType(eventType)) {
528 handleBiasEvent(eventType,
529 static_cast<const chreSensorThreeAxisData *>(eventData));
530
531 } else {
532 unexpectedEvent(eventType);
533 }
534
535 mInMethod = false;
536 }
537
538 } // namespace general_test
539