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