Home | History | Annotate | Download | only in sensorverification
      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 package android.hardware.cts.helpers.sensorverification;
     18 
     19 import junit.framework.Assert;
     20 
     21 import android.hardware.SensorEvent;
     22 import android.hardware.cts.helpers.SensorStats;
     23 import android.hardware.cts.helpers.TestSensorEnvironment;
     24 import android.hardware.cts.helpers.TestSensorEvent;
     25 import android.os.SystemClock;
     26 
     27 import java.util.ArrayList;
     28 import java.util.List;
     29 import java.util.concurrent.TimeUnit;
     30 import android.util.Log;
     31 
     32 /**
     33  * A {@link ISensorVerification} which verifies that the timestamp of the {@link SensorEvent} is
     34  * synchronized with {@link SystemClock#elapsedRealtimeNanos()}, based on a given threshold.
     35  */
     36 public class TimestampClockSourceVerification extends AbstractSensorVerification {
     37     public static final String TAG = "TimestampClockSourceVerification";
     38     public static final String PASSED_KEY = "timestamp_verification_passed";
     39 
     40     // number of indices to print in assertion message before truncating
     41     private static final int TRUNCATE_MESSAGE_LENGTH = 3;
     42 
     43     private static final long DEFAULT_THRESHOLD_NS = TimeUnit.MILLISECONDS.toNanos(1000);
     44     private static final float ALLOWED_LATENCY_ERROR = 0.1f; //10%
     45 
     46     private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<TestSensorEvent>();
     47 
     48     private long mMaximumLatencyNs;
     49 
     50     /**
     51      * Constructs an instance of {@link TimestampClockSourceVerification}.
     52      *
     53      * @param maxLatencyNs Maximum allowed timestamp delta between event timestamp and current time
     54      */
     55     public TimestampClockSourceVerification (
     56             long maxLatencyUs) {
     57         mMaximumLatencyNs = maxLatencyUs * 1000;
     58     }
     59 
     60     /**
     61      * Gets a default {@link TimestampClockSourceVerification}.
     62      *
     63      * @param environment The test environment
     64      * @return The verification or null if the verification is not supported in the given
     65      *         environment.
     66      */
     67     public static TimestampClockSourceVerification getDefault(
     68             TestSensorEnvironment environment) {
     69         long reportLatencyUs = environment.getMaxReportLatencyUs();
     70         long fifoMaxEventCount = environment.getSensor().getFifoMaxEventCount();
     71         int maximumExpectedSamplingPeriodUs = environment.getMaximumExpectedSamplingPeriodUs();
     72         if (fifoMaxEventCount > 0 && maximumExpectedSamplingPeriodUs != Integer.MAX_VALUE) {
     73             long fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
     74             // If the device goes into suspend mode and the sensor is a non wake-up sensor, the
     75             // FIFO will keep overwriting itself and the reportLatency will be equal to the time
     76             // it takes to fill up the FIFO.
     77             if (environment.isDeviceSuspendTest() && !environment.getSensor().isWakeUpSensor()) {
     78                 reportLatencyUs = fifoBasedReportLatencyUs;
     79             } else {
     80                 // In this case the sensor under test is either a wake-up sensor OR it
     81                 // is a non wake-up sensor but the device does not go into suspend.
     82                 // So the expected delay of a sensor_event is the minimum of the
     83                 // fifoBasedReportLatencyUs and the requested latency by the application.
     84                 reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs);
     85             }
     86         }
     87         // Add an additional filter delay which is a function of the samplingPeriod.
     88         long filterDelayUs = (long)(2.5 * maximumExpectedSamplingPeriodUs);
     89 
     90         long expectedSyncLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs + filterDelayUs);
     91 
     92         return new TimestampClockSourceVerification(expectedSyncLatencyNs);
     93     }
     94 
     95     @Override
     96     public void verify(TestSensorEnvironment environment, SensorStats stats) {
     97         StringBuilder errorMessageBuilder =
     98                 new StringBuilder(" Incorrect timestamp clock source failures: ");
     99         boolean success = false;
    100         int failuresCount = 0;
    101         List<IndexedEvent> failures;
    102 
    103         try {
    104             failures = verifyTimestampClockSource(errorMessageBuilder);
    105             failuresCount = failures.size();
    106             stats.addValue(SensorStats.EVENT_TIME_WRONG_CLOCKSOURCE_COUNT_KEY, failuresCount);
    107             stats.addValue(
    108                     SensorStats.EVENT_TIME_WRONG_CLOCKSOURCE_POSITIONS_KEY,
    109                     getIndexArray(failures));
    110             success = failures.isEmpty();
    111         } catch (Throwable e) {
    112             failuresCount++;
    113             stats.addValue(SensorStats.EVENT_TIME_WRONG_CLOCKSOURCE_COUNT_KEY, 0);
    114         }
    115         stats.addValue(PASSED_KEY, success);
    116         errorMessageBuilder.insert(0, failuresCount);
    117         Assert.assertTrue(errorMessageBuilder.toString(), success);
    118     }
    119 
    120     /**
    121      * {@inheritDoc}
    122      */
    123     @Override
    124     public TimestampClockSourceVerification clone() {
    125         return new TimestampClockSourceVerification(
    126                 mMaximumLatencyNs);
    127     }
    128 
    129     /**
    130      * {@inheritDoc}
    131      */
    132     @Override
    133     protected void addSensorEventInternal(TestSensorEvent event) {
    134         mCollectedEvents.add(event);
    135     }
    136 
    137     /**
    138      * Verifies timestamp clock source for each collected event
    139      *
    140      * @param builder A string builder to store error messaged found in the collected sensor events.
    141      * @return A list of events tha failed the verification.
    142      */
    143     private List<IndexedEvent> verifyTimestampClockSource(StringBuilder builder) throws Throwable {
    144         int collectedEventsCount = mCollectedEvents.size();
    145         ArrayList<IndexedEvent> failures = new ArrayList<IndexedEvent>();
    146 
    147         if (collectedEventsCount == 0) {
    148             if (failures.size() < TRUNCATE_MESSAGE_LENGTH) {
    149                 builder.append("No events received !");
    150             }
    151             Assert.assertTrue("No events received !", false);
    152         }
    153 
    154         for (int i = 0; i < collectedEventsCount; ++i) {
    155             TestSensorEvent event = mCollectedEvents.get(i);
    156             long eventTimestampNs = event.timestamp;
    157             long receivedTimestampNs = event.receivedTimestamp;
    158             long upperThresholdNs = receivedTimestampNs;
    159             long lowerThresholdNs = receivedTimestampNs - mMaximumLatencyNs;
    160 
    161             if (eventTimestampNs < lowerThresholdNs || eventTimestampNs > upperThresholdNs) {
    162                 if (failures.size() < TRUNCATE_MESSAGE_LENGTH) {
    163                     builder.append("position=").append(i);
    164                     builder.append(", timestamp=").append(String.format("%.2fms",
    165                                 nanosToMillis(eventTimestampNs)));
    166                     builder.append(", expected=[").append(String.format("%.2fms",
    167                                 nanosToMillis(lowerThresholdNs)));
    168                     builder.append(", ").append(String.format("%.2f]ms; ",
    169                                 nanosToMillis(upperThresholdNs)));
    170                 }
    171                 failures.add(new IndexedEvent(i, event));
    172             }
    173         }
    174         if (failures.size() >= TRUNCATE_MESSAGE_LENGTH) {
    175             builder.append("more; ");
    176         }
    177         return failures;
    178     }
    179 }
    180