blob: 050c7bbab6117e3fb669255b22e5abd20e79a4f3 [file] [log] [blame]
/*
* Copyright (C) 2013 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;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.SensorCtsHelper;
import android.hardware.cts.helpers.SensorNotSupportedException;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.sensoroperations.ParallelSensorOperation;
import android.hardware.cts.helpers.sensoroperations.RepeatingSensorOperation;
import android.hardware.cts.helpers.sensoroperations.SequentialSensorOperation;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import android.hardware.cts.helpers.sensorverification.FrequencyVerification;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* Set of tests that verifies proper interaction of the sensors in the platform.
*
* To execute these test cases, the following command can be used:
* $ adb shell am instrument -e class android.hardware.cts.SensorIntegrationTests \
* -w android.hardware.cts/android.test.InstrumentationCtsTestRunner
*/
public class SensorIntegrationTests extends SensorTestCase {
private static final String TAG = "SensorIntegrationTests";
/**
* This test focuses in the interaction of continuous and batching clients for the same Sensor
* under test. The verification ensures that sensor clients can interact with the System and
* not affect other clients in the way.
*
* The test verifies for each client that the a set of sampled data arrives in order. However
* each client in the test has different set of parameters that represent different types of
* clients in the real world.
*
* A test failure might indicate that the HAL implementation does not respect the assumption
* that the sensors must be independent. Activating one sensor should not cause another sensor
* to deactivate or to change behavior.
* It is however, acceptable that when a client is activated at a higher sampling rate, it would
* cause other clients to receive data at a faster sampling rate. A client causing other clients
* to receive data at a lower sampling rate is, however, not acceptable.
*
* The assertion associated with the test failure provides:
* - the thread id on which the failure occurred
* - the sensor type and sensor handle that caused the failure
* - the event that caused the issue
* It is important to look at the internals of the Sensor HAL to identify how the interaction
* of several clients can lead to the failing state.
*/
public void testSensorsWithSeveralClients() throws Throwable {
SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
final int ITERATIONS = 50;
final int MAX_REPORTING_LATENCY_US = (int) TimeUnit.SECONDS.toMicros(5);
final Context context = getContext();
int sensorTypes[] = {
Sensor.TYPE_ACCELEROMETER,
Sensor.TYPE_MAGNETIC_FIELD,
Sensor.TYPE_GYROSCOPE };
ParallelSensorOperation operation = new ParallelSensorOperation();
for(int sensorType : sensorTypes) {
TestSensorEnvironment environment = new TestSensorEnvironment(
context,
sensorType,
shouldEmulateSensorUnderLoad(),
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation continuousOperation =
TestSensorOperation.createOperation(environment, 100 /* eventCount */);
continuousOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(continuousOperation, ITERATIONS));
Sensor sensor = TestSensorEnvironment.getSensor(context, sensorType);
TestSensorEnvironment batchingEnvironment = new TestSensorEnvironment(
context,
sensorType,
shouldEmulateSensorUnderLoad(),
true, /* isIntegrationTest */
sensor.getMinDelay(),
MAX_REPORTING_LATENCY_US);
TestSensorOperation batchingOperation =
TestSensorOperation.createOperation(batchingEnvironment, 100 /* eventCount */);
batchingOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(batchingOperation, ITERATIONS));
}
operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
}
/**
* This test focuses in the interaction of several sensor Clients. The test characterizes by
* using clients for different Sensors under Test that vary the sampling rates and report
* latencies for the requests.
* The verification ensures that the sensor clients can vary the parameters of their requests
* without affecting other clients.
*
* The test verifies for each client that a set of sampled data arrives in order. However each
* client in the test has different set of parameters that represent different types of clients
* in the real world.
*
* The test can be susceptible to issues when several clients interacting with the system
* actually affect the operation of other clients.
*
* The assertion associated with the test failure provides:
* - the thread id on which the failure occurred
* - the sensor type and sensor handle that caused the failure
* - the event that caused the issue
* It is important to look at the internals of the Sensor HAL to identify how the interaction
* of several clients can lead to the failing state.
*/
public void testSensorsMovingRates() throws Throwable {
SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
// use at least two instances to ensure more than one client of any given sensor is in play
final int INSTANCES_TO_USE = 5;
final int ITERATIONS_TO_EXECUTE = 100;
ParallelSensorOperation operation = new ParallelSensorOperation();
int sensorTypes[] = {
Sensor.TYPE_ACCELEROMETER,
Sensor.TYPE_MAGNETIC_FIELD,
Sensor.TYPE_GYROSCOPE };
Context context = getContext();
for(int sensorType : sensorTypes) {
for(int instance = 0; instance < INSTANCES_TO_USE; ++instance) {
SequentialSensorOperation sequentialOperation = new SequentialSensorOperation();
for(int iteration = 0; iteration < ITERATIONS_TO_EXECUTE; ++iteration) {
TestSensorEnvironment environment = new TestSensorEnvironment(
context,
sensorType,
shouldEmulateSensorUnderLoad(),
true, /* isIntegrationTest */
generateSamplingRateInUs(sensorType),
generateReportLatencyInUs());
TestSensorOperation sensorOperation =
TestSensorOperation.createOperation(environment, 100 /* eventCount */);
sensorOperation.addVerification(new EventOrderingVerification());
sequentialOperation.add(sensorOperation);
}
operation.add(sequentialOperation);
}
}
operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
}
public void testAccelerometerReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_ACCELEROMETER);
}
public void testUncalibratedAccelerometerReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED);
}
public void testMagneticFieldReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_MAGNETIC_FIELD);
}
public void testUncalibratedMagneticFieldReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
}
public void testOrientationReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_ORIENTATION);
}
public void testGyroscopeReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GYROSCOPE);
}
public void testUncalibratedGyroscopeReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);
}
public void testPressureReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_PRESSURE);
}
public void testGravityReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GRAVITY);
}
public void testLinearAccelerationReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_LINEAR_ACCELERATION);
}
public void testRotationVectorReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_ROTATION_VECTOR);
}
public void testGameRotationVectorReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GAME_ROTATION_VECTOR);
}
public void testGeomagneticRotationVectorReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
}
public void testAccelerometerLimitedAxesReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES);
}
public void testAccelerometerLimitedAxesUncalibratedReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED);
}
public void testGyroscopeLimitedAxesReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GYROSCOPE_LIMITED_AXES);
}
public void testGyroscopeLimitedAxesUncalibratedReconfigureWhileActive() throws Throwable {
verifySensorReconfigureWhileActive(Sensor.TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED);
}
/**
* This test focuses on ensuring that an active sensor is able to be reconfigured when a new
* client requests a different sampling rate.
*
* The test verifies that if a sensor is active with a slow sampling rate and a new client
* requests a faster sampling rate, the sensor begins returning data at the faster sampling
* rate.
*
* The assertion associated with the test failure provides:
* - the thread id on which the failure occurred
* - the sensor type and sensor handle that caused the failure
* - the event that caused the issue
* It is important to look at the internals of the Sensor HAL to identify how the interaction
* of several clients can lead to the failing state.
*/
public void verifySensorReconfigureWhileActive(int sensorType) throws Throwable {
SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
final int DELAY_BEFORE_CHANGING_RATE_SEC = 2;
final int EVENTS_FOR_VERIFICATION = 200;
Context context = getContext();
SensorManager sensorManager =
(SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
assertNotNull("SensorService is not present in the system", sensorManager);
Sensor sensor = sensorManager.getDefaultSensor(sensorType);
if(sensor == null) {
throw new SensorNotSupportedException(sensorType);
}
// Request for the sensor rate to be set to the slowest rate.
ParallelSensorOperation operation = new ParallelSensorOperation();
TestSensorEnvironment environmentSlow = new TestSensorEnvironment(
context,
sensor,
shouldEmulateSensorUnderLoad(),
true, /* isIntegrationTest */
sensor.getMaxDelay(),
(int)TimeUnit.SECONDS.toMicros(20));
TestSensorOperation sensorOperationSlow = TestSensorOperation.createOperation(
environmentSlow, 2 * DELAY_BEFORE_CHANGING_RATE_SEC, TimeUnit.SECONDS);
operation.add(sensorOperationSlow);
// Create a second operation that will run in parallel and request the fastest rate after
// an initial delay. The delay is to ensure that the first operation has enabled the sensor.
// The sensor should begin reporting at the newly requested rate. Execute a flush prior to
// the reconfiguration to ensure that the lower frequency events are not received after the
// reconfiguration of the sensor.
SequentialSensorOperation sequentialSensorOperation = new SequentialSensorOperation();
TestSensorEnvironment environmentFast = new TestSensorEnvironment(
context,
sensor,
shouldEmulateSensorUnderLoad(),
true, /* isIntegrationTest */
sensor.getMinDelay(),
0 /* max reporting latency */);
// Create the flush operation with a delay to ensure the low frequency configuration was
// handled and executed. Use the original environment since the flush operation will
// register a new listener and reconfigure the sensor.
TestSensorOperation flushOperation = TestSensorOperation.createFlushOperation(
environmentSlow, DELAY_BEFORE_CHANGING_RATE_SEC, TimeUnit.SECONDS);
sequentialSensorOperation.add(flushOperation);
// Create the reconfiguration request and add it after the flush
TestSensorOperation sensorOperationFast = TestSensorOperation.createOperation(
environmentFast, EVENTS_FOR_VERIFICATION);
sensorOperationFast.addVerification(FrequencyVerification.getDefault(environmentFast));
sequentialSensorOperation.add(sensorOperationFast);
// Add the sequential operation containing the flush and high frequency request to the
// existing parallel operation that already contains the low frequency request.
operation.add(sequentialSensorOperation);
operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
}
/**
* Regress:
* - b/10641388
*/
public void testAccelerometerAccelerometerStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER);
}
public void testAccelerometerGyroscopeStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_GYROSCOPE);
}
public void testAccelerometerMagneticFieldStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_MAGNETIC_FIELD);
}
public void testGyroscopeAccelerometerStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_GYROSCOPE, Sensor.TYPE_ACCELEROMETER);
}
public void testGyroscopeGyroscopeStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_GYROSCOPE, Sensor.TYPE_GYROSCOPE);
}
public void testGyroscopeMagneticFieldStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_GYROSCOPE, Sensor.TYPE_MAGNETIC_FIELD);
}
public void testMagneticFieldAccelerometerStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_ACCELEROMETER);
}
public void testMagneticFieldGyroscopeStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_GYROSCOPE);
}
public void testMagneticFieldMagneticFieldStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD);
}
public void testAccelerometerLimitedAxesAccelerometerLimitedAxesStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES,
Sensor.TYPE_ACCELEROMETER_LIMITED_AXES);
}
public void testAccelerometerLimitedAxesGyroscopeLimitedAxesStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES,
Sensor.TYPE_GYROSCOPE_LIMITED_AXES);
}
public void testAccelerometerLimitedAxesMagneticFieldStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_ACCELEROMETER_LIMITED_AXES,
Sensor.TYPE_MAGNETIC_FIELD);
}
public void testGyroscopeLimitedAxesAccelerometerLimitedAxesStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_GYROSCOPE_LIMITED_AXES,
Sensor.TYPE_ACCELEROMETER_LIMITED_AXES);
}
public void testGyroscopeLimitedAxesGyroscopeLimitedAxesStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_GYROSCOPE_LIMITED_AXES,
Sensor.TYPE_GYROSCOPE_LIMITED_AXES);
}
public void testGyroscopeLimitedAxesMagneticFieldStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_GYROSCOPE_LIMITED_AXES,
Sensor.TYPE_MAGNETIC_FIELD);
}
public void testMagneticFieldAccelerometerLimitedAxesStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_MAGNETIC_FIELD,
Sensor.TYPE_ACCELEROMETER_LIMITED_AXES);
}
public void testMagneticFieldGyroscopeLimitedAxesStopping() throws Throwable {
verifySensorStoppingInteraction(Sensor.TYPE_MAGNETIC_FIELD,
Sensor.TYPE_GYROSCOPE_LIMITED_AXES);
}
/**
* This test verifies that starting/stopping a particular Sensor client in the System does not
* affect other sensor clients.
* the test is used to validate that starting/stopping operations are independent on several
* sensor clients.
*
* The test verifies for each client that the a set of sampled data arrives in order. However
* each client in the test has different set of parameters that represent different types of
* clients in the real world.
*
* The test can be susceptible to issues when several clients interacting with the system
* actually affect the operation of other clients.
*
* The assertion associated with the test failure provides:
* - the thread id on which the failure occurred
* - the sensor type and sensor handle that caused the failure
* - the event that caused the issue
* It is important to look at the internals of the Sensor HAL to identify how the interaction
* of several clients can lead to the failing state.
*/
public void verifySensorStoppingInteraction(
int sensorTypeTestee,
int sensorTypeTester) throws Throwable {
SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
Context context = getContext();
TestSensorEnvironment testerEnvironment = new TestSensorEnvironment(
context,
sensorTypeTester,
shouldEmulateSensorUnderLoad(),
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation tester =
TestSensorOperation.createOperation(testerEnvironment, 100 /* event count */);
tester.addVerification(new EventOrderingVerification());
TestSensorEnvironment testeeEnvironment = new TestSensorEnvironment(
context,
sensorTypeTestee,
shouldEmulateSensorUnderLoad(),
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation testee =
TestSensorOperation.createOperation(testeeEnvironment, 100 /* event count */);
testee.addVerification(new EventOrderingVerification());
ParallelSensorOperation operation = new ParallelSensorOperation();
operation.add(tester, testee);
operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
testee = testee.clone();
testee.execute(getCurrentTestNode());
testee.getStats().log(TAG);
}
/**
* Private helpers.
*/
private final Random mGenerator = new Random();
private int generateSamplingRateInUs(int sensorType) {
int rate;
switch(mGenerator.nextInt(5)) {
case 0:
rate = SensorManager.SENSOR_DELAY_FASTEST;
break;
default:
Sensor sensor = TestSensorEnvironment.getSensor(getContext(), sensorType);
int maxSamplingRate = sensor.getMinDelay();
rate = maxSamplingRate * mGenerator.nextInt(10);
}
return rate;
}
private int generateReportLatencyInUs() {
long reportLatencyUs = TimeUnit.SECONDS.toMicros(mGenerator.nextInt(5) + 1);
return (int) reportLatencyUs;
}
}