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