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