blob: 266907913ccf8a9b3ae23120fc5d11760b044f48 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.hardware.cts.helpers.sensorverification;
import junit.framework.Assert;
import android.hardware.SensorEvent;
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
import android.os.SystemClock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import android.util.Log;
/**
* A {@link ISensorVerification} which verifies that the timestamp of the {@link SensorEvent} is
* synchronized with {@link SystemClock#elapsedRealtimeNanos()}, based on a given threshold.
*/
public class TimestampClockSourceVerification extends AbstractSensorVerification {
public static final String TAG = "TimestampClockSourceVerification";
public static final String PASSED_KEY = "timestamp_verification_passed";
// number of indices to print in assertion message before truncating
private static final int TRUNCATE_MESSAGE_LENGTH = 3;
private static final long DEFAULT_THRESHOLD_NS = TimeUnit.MILLISECONDS.toNanos(1000);
private static final float ALLOWED_LATENCY_ERROR = 0.1f; //10%
private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<TestSensorEvent>();
private long mMaximumLatencyNs;
/**
* Constructs an instance of {@link TimestampClockSourceVerification}.
*
* @param maxLatencyNs Maximum allowed timestamp delta between event timestamp and current time
*/
public TimestampClockSourceVerification (
long maxLatencyUs) {
mMaximumLatencyNs = maxLatencyUs * 1000;
}
/**
* Gets a default {@link TimestampClockSourceVerification}.
*
* @param environment The test environment
* @return The verification or null if the verification is not supported in the given
* environment.
*/
public static TimestampClockSourceVerification getDefault(
TestSensorEnvironment environment) {
long reportLatencyUs = environment.getMaxReportLatencyUs();
long fifoMaxEventCount = environment.getSensor().getFifoMaxEventCount();
int maximumExpectedSamplingPeriodUs = environment.getMaximumExpectedSamplingPeriodUs();
if (fifoMaxEventCount > 0 && maximumExpectedSamplingPeriodUs != Integer.MAX_VALUE) {
long fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
// If the device goes into suspend mode and the sensor is a non wake-up sensor, the
// FIFO will keep overwriting itself and the reportLatency will be equal to the time
// it takes to fill up the FIFO.
if (environment.isDeviceSuspendTest() && !environment.getSensor().isWakeUpSensor()) {
reportLatencyUs = fifoBasedReportLatencyUs;
} else {
// In this case the sensor under test is either a wake-up sensor OR it
// is a non wake-up sensor but the device does not go into suspend.
// So the expected delay of a sensor_event is the minimum of the
// fifoBasedReportLatencyUs and the requested latency by the application.
reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs);
}
}
// Add an additional filter delay which is a function of the samplingPeriod.
long filterDelayUs = (long)(2.5 * maximumExpectedSamplingPeriodUs);
long expectedSyncLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs + filterDelayUs);
return new TimestampClockSourceVerification(expectedSyncLatencyNs);
}
@Override
public void verify(TestSensorEnvironment environment, SensorStats stats) {
StringBuilder errorMessageBuilder =
new StringBuilder(" Incorrect timestamp clock source failures: ");
boolean success = false;
int failuresCount = 0;
List<IndexedEvent> failures;
try {
failures = verifyTimestampClockSource(errorMessageBuilder);
failuresCount = failures.size();
stats.addValue(SensorStats.EVENT_TIME_WRONG_CLOCKSOURCE_COUNT_KEY, failuresCount);
stats.addValue(
SensorStats.EVENT_TIME_WRONG_CLOCKSOURCE_POSITIONS_KEY,
getIndexArray(failures));
success = failures.isEmpty();
} catch (Throwable e) {
failuresCount++;
stats.addValue(SensorStats.EVENT_TIME_WRONG_CLOCKSOURCE_COUNT_KEY, 0);
}
stats.addValue(PASSED_KEY, success);
errorMessageBuilder.insert(0, failuresCount);
Assert.assertTrue(errorMessageBuilder.toString(), success);
}
/**
* {@inheritDoc}
*/
@Override
public TimestampClockSourceVerification clone() {
return new TimestampClockSourceVerification(
mMaximumLatencyNs);
}
/**
* {@inheritDoc}
*/
@Override
protected void addSensorEventInternal(TestSensorEvent event) {
mCollectedEvents.add(event);
}
/**
* Verifies timestamp clock source for each collected event
*
* @param builder A string builder to store error messaged found in the collected sensor events.
* @return A list of events tha failed the verification.
*/
private List<IndexedEvent> verifyTimestampClockSource(StringBuilder builder) throws Throwable {
int collectedEventsCount = mCollectedEvents.size();
ArrayList<IndexedEvent> failures = new ArrayList<IndexedEvent>();
if (collectedEventsCount == 0) {
if (failures.size() < TRUNCATE_MESSAGE_LENGTH) {
builder.append("No events received !");
}
Assert.assertTrue("No events received !", false);
}
for (int i = 0; i < collectedEventsCount; ++i) {
TestSensorEvent event = mCollectedEvents.get(i);
long eventTimestampNs = event.timestamp;
long receivedTimestampNs = event.receivedTimestamp;
long upperThresholdNs = receivedTimestampNs;
long lowerThresholdNs = receivedTimestampNs - mMaximumLatencyNs;
if (eventTimestampNs < lowerThresholdNs || eventTimestampNs > upperThresholdNs) {
if (failures.size() < TRUNCATE_MESSAGE_LENGTH) {
builder.append("position=").append(i);
builder.append(", timestamp=").append(String.format("%.2fms",
nanosToMillis(eventTimestampNs)));
builder.append(", expected=[").append(String.format("%.2fms",
nanosToMillis(lowerThresholdNs)));
builder.append(", ").append(String.format("%.2f]ms; ",
nanosToMillis(upperThresholdNs)));
}
failures.add(new IndexedEvent(i, event));
}
}
if (failures.size() >= TRUNCATE_MESSAGE_LENGTH) {
builder.append("more; ");
}
return failures;
}
}