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