Home | History | Annotate | Download | only in sensoroperations
      1 /*
      2  * Copyright (C) 2014 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.sensoroperations;
     18 
     19 import java.io.IOException;
     20 import java.util.HashSet;
     21 import java.util.List;
     22 import java.util.concurrent.CountDownLatch;
     23 import java.util.concurrent.TimeUnit;
     24 
     25 import android.hardware.cts.helpers.SensorCtsHelper;
     26 import android.hardware.cts.helpers.SensorStats;
     27 import android.hardware.cts.helpers.SensorTestPlatformException;
     28 import android.hardware.cts.helpers.TestSensorEnvironment;
     29 import android.hardware.cts.helpers.TestSensorEvent;
     30 import android.hardware.cts.helpers.TestSensorEventListener;
     31 import android.hardware.cts.helpers.TestSensorManager;
     32 import android.hardware.cts.helpers.SuspendStateMonitor;
     33 import android.hardware.cts.helpers.reporting.ISensorTestNode;
     34 import android.hardware.cts.helpers.sensorverification.EventBasicVerification;
     35 import android.hardware.cts.helpers.sensorverification.EventGapVerification;
     36 import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
     37 import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
     38 import android.hardware.cts.helpers.sensorverification.FrequencyVerification;
     39 import android.hardware.cts.helpers.sensorverification.ISensorVerification;
     40 import android.hardware.cts.helpers.sensorverification.JitterVerification;
     41 import android.hardware.cts.helpers.sensorverification.MagnitudeVerification;
     42 import android.hardware.cts.helpers.sensorverification.MeanVerification;
     43 import android.hardware.cts.helpers.sensorverification.InitialValueVerification;
     44 import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
     45 import android.os.Handler;
     46 import android.os.SystemClock;
     47 import android.os.PowerManager.WakeLock;
     48 import android.util.Log;
     49 
     50 import junit.framework.Assert;
     51 
     52 /**
     53  * A {@link SensorOperation} used to verify that sensor events and sensor values are correct.
     54  * <p>
     55  * Provides methods to set test expectations as well as providing a set of default expectations
     56  * depending on sensor type.  When {{@link #execute(ISensorTestNode)} is called, the sensor will
     57  * collect the events and then run all the tests.
     58  * </p>
     59  */
     60 public class TestSensorOperation extends SensorOperation {
     61     private static final String TAG = "TestSensorOperation";
     62 
     63     private final HashSet<ISensorVerification> mVerifications = new HashSet<>();
     64 
     65     private final TestSensorManager mSensorManager;
     66     private final TestSensorEnvironment mEnvironment;
     67     private final Executor mExecutor;
     68     private final Handler mHandler;
     69     private long mDeviceWakeUpTimeMs = -1;
     70     private long mStartTimeMs = -1;
     71     private long mStopTimeMs = -1;
     72 
     73     /**
     74      * An interface that defines an abstraction for operations to be performed by the
     75      * {@link TestSensorOperation}.
     76      */
     77     public interface Executor {
     78         void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
     79                 throws Exception;
     80     }
     81 
     82     /**
     83      * Create a {@link TestSensorOperation}.
     84      */
     85     public TestSensorOperation(TestSensorEnvironment environment, Executor executor) {
     86         this(environment, executor, null /* handler */);
     87     }
     88 
     89     /**
     90      * Create a {@link TestSensorOperation}.
     91      */
     92     public TestSensorOperation(
     93             TestSensorEnvironment environment,
     94             Executor executor,
     95             Handler handler) {
     96         mEnvironment = environment;
     97         mExecutor = executor;
     98         mHandler = handler;
     99         mSensorManager = new TestSensorManager(mEnvironment);
    100     }
    101 
    102     /**
    103      * Set all of the default test expectations.
    104      */
    105     public void addDefaultVerifications() {
    106         addVerification(EventGapVerification.getDefault(mEnvironment));
    107         addVerification(EventOrderingVerification.getDefault(mEnvironment));
    108         addVerification(FrequencyVerification.getDefault(mEnvironment));
    109         addVerification(JitterVerification.getDefault(mEnvironment));
    110         addVerification(MagnitudeVerification.getDefault(mEnvironment));
    111         addVerification(MeanVerification.getDefault(mEnvironment));
    112         addVerification(StandardDeviationVerification.getDefault(mEnvironment));
    113         addVerification(EventTimestampSynchronizationVerification.getDefault(mEnvironment));
    114         addVerification(InitialValueVerification.getDefault(mEnvironment));
    115     }
    116 
    117     public void addVerification(ISensorVerification verification) {
    118         if (verification != null) {
    119             mVerifications.add(verification);
    120         }
    121     }
    122 
    123     /**
    124      * Collect the specified number of events from the sensor and run all enabled verifications.
    125      */
    126     @Override
    127     public void execute(ISensorTestNode parent) throws Exception {
    128         getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
    129         TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
    130 
    131         mStartTimeMs = SystemClock.elapsedRealtime();
    132         if (mEnvironment.isDeviceSuspendTest()) {
    133             SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor();
    134             // Device should go into suspend here.
    135             mExecutor.execute(mSensorManager, listener);
    136             mStopTimeMs = SystemClock.elapsedRealtime();
    137             // Check if the device has gone into suspend during test execution.
    138             mDeviceWakeUpTimeMs = suspendStateMonitor.getLastWakeUpTime();
    139             suspendStateMonitor.cancel();
    140             Assert.assertTrue("Device did not go into suspend during test execution",
    141                                        mStartTimeMs < mDeviceWakeUpTimeMs &&
    142                                        mDeviceWakeUpTimeMs < mStopTimeMs);
    143         } else {
    144             mExecutor.execute(mSensorManager, listener);
    145             mStopTimeMs = SystemClock.elapsedRealtime();
    146         }
    147 
    148         boolean failed = false;
    149         StringBuilder sb = new StringBuilder();
    150         List<TestSensorEvent> collectedEvents = listener.getCollectedEvents();
    151         for (ISensorVerification verification : mVerifications) {
    152             failed |= evaluateResults(collectedEvents, verification, sb);
    153         }
    154 
    155         trySaveCollectedEvents(parent, listener);
    156         if (failed) {
    157             String msg = SensorCtsHelper
    158                     .formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
    159             getStats().addValue(SensorStats.ERROR, msg);
    160             Assert.fail(msg);
    161         }
    162     }
    163 
    164     /**
    165      * {@inheritDoc}
    166      */
    167     @Override
    168     public TestSensorOperation clone() {
    169         TestSensorOperation operation = new TestSensorOperation(mEnvironment, mExecutor);
    170         for (ISensorVerification verification : mVerifications) {
    171             operation.addVerification(verification.clone());
    172         }
    173         return operation;
    174     }
    175 
    176     /**
    177      * Evaluate the results of a test, aggregate the stats, and build the error message.
    178      */
    179     private boolean evaluateResults(
    180             List<TestSensorEvent> events,
    181             ISensorVerification verification,
    182             StringBuilder sb) {
    183         try {
    184             // this is an intermediate state in refactoring, at some point verifications might
    185             // become stateless
    186             verification.addSensorEvents(events);
    187             verification.verify(mEnvironment, getStats());
    188         } catch (AssertionError e) {
    189             if (sb.length() > 0) {
    190                 sb.append(", ");
    191             }
    192             sb.append(e.getMessage());
    193             return true;
    194         }
    195         return false;
    196     }
    197 
    198     /**
    199      * Tries to save collected {@link TestSensorEvent}s to a file.
    200      *
    201      * NOTE: it is more important to handle verifications and its results, than failing if the file
    202      * cannot be created. So we silently fail if necessary.
    203      */
    204     private void trySaveCollectedEvents(ISensorTestNode parent, TestSensorEventListener listener) {
    205         String sanitizedFileName;
    206         try {
    207             String fileName = asTestNode(parent).getName();
    208             sanitizedFileName = String.format(
    209                     "%s-%s-%s_%dus.txt",
    210                     SensorCtsHelper.sanitizeStringForFileName(fileName),
    211                     SensorStats.getSanitizedSensorName(mEnvironment.getSensor()),
    212                     mEnvironment.getFrequencyString(),
    213                     mEnvironment.getMaxReportLatencyUs());
    214             getStats().addValue(SensorStats.EVENT_LOG_FILENAME, sanitizedFileName);
    215         } catch (SensorTestPlatformException e) {
    216             Log.w(TAG, "Unable to generate file name to save collected events", e);
    217             return;
    218         }
    219 
    220         try {
    221             listener.logCollectedEventsToFile(sanitizedFileName, mDeviceWakeUpTimeMs,
    222                     mStartTimeMs, mStopTimeMs);
    223         } catch (IOException e) {
    224             Log.w(TAG, "Unable to save collected events to file: " + sanitizedFileName, e);
    225         }
    226     }
    227 
    228     /**
    229      * Creates an operation that will wait for a given amount of events to arrive.
    230      *
    231      * @param environment The test environment.
    232      * @param eventCount The number of events to wait for.
    233      */
    234     public static TestSensorOperation createOperation(
    235             TestSensorEnvironment environment,
    236             final int eventCount) {
    237         Executor executor = new Executor() {
    238             @Override
    239             public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
    240                     throws InterruptedException {
    241                 try {
    242                     CountDownLatch latch = sensorManager.registerListener(listener, eventCount);
    243                     listener.waitForEvents(latch, eventCount, true);
    244                 } finally {
    245                     sensorManager.unregisterListener();
    246                 }
    247             }
    248         };
    249         return new TestSensorOperation(environment, executor);
    250     }
    251 
    252     /**
    253      * Creates an operation that will wait for a given amount of events to arrive.
    254      *
    255      * After the execution of this type of test operation, the wakelock passed in will be acquired.
    256      * Make sure it is released at clean up.
    257      *
    258      * @param environment The test environment.
    259      * @param eventCount The number of events to wait for.
    260      */
    261     public static TestSensorOperation createOperation(
    262             final TestSensorEnvironment environment,
    263             final WakeLock wakeLock,
    264             final boolean flushBeforeAfterSuspend) {
    265         Executor executor = new Executor() {
    266             @Override
    267             public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
    268                     throws InterruptedException {
    269                 try {
    270                     sensorManager.registerListener(listener);
    271                     if (flushBeforeAfterSuspend) {
    272                         int initialNumEvents1 = listener.getCollectedEvents().size();
    273                         SensorCtsHelper.sleep(2, TimeUnit.SECONDS);
    274                         CountDownLatch flushLatch1 = sensorManager.requestFlush();
    275                         listener.waitForFlushComplete(flushLatch1, false);
    276                         Assert.assertTrue("1.No sensor events collected on calling flush " +
    277                                 environment.toString(),
    278                                 listener.getCollectedEvents().size() - initialNumEvents1 > 0);
    279                     }
    280                     // acknowledge waitForFlushComplete
    281                     listener.releaseWakeLock();
    282 
    283                     Log.i(TAG, "Collected sensor events size1=" +
    284                             listener.getCollectedEvents().size());
    285                     int initialNumEvents2 = listener.getCollectedEvents().size();
    286 
    287                     // allow device to go to sleep
    288                     if (wakeLock.isHeld()) {
    289                         wakeLock.release();
    290                     }
    291 
    292                     SuspendStateMonitor suspendMonitor = new SuspendStateMonitor();
    293                     long approxStartTimeMs = SystemClock.elapsedRealtime();
    294                     // Allow the device to go into suspend. Wait for wake-up.
    295                     suspendMonitor.waitForWakeUp(15);
    296                     suspendMonitor.cancel();
    297 
    298                     // keep device awake for processing
    299                     if (!wakeLock.isHeld()) {
    300                         wakeLock.acquire();
    301                     }
    302 
    303                     CountDownLatch flushLatch2 = sensorManager.requestFlush();
    304                     listener.waitForFlushComplete(flushLatch2, false);
    305 
    306                     Log.i(TAG, "Collected sensor events size2=" +
    307                             listener.getCollectedEvents().size());
    308 
    309                     if (listener.getCollectedEvents().size() - initialNumEvents2 <= 0 &&
    310                             suspendMonitor.getLastWakeUpTime() > 0) {
    311                         // Fail
    312                         String str = String.format("No Sensor events collected by calling flush " +
    313                                 "after device wake up. Approx time after which device went into " +
    314                                 "suspend %dms ,approx AP wake-up time %dms %s",
    315                                 approxStartTimeMs, suspendMonitor.getLastWakeUpTime(),
    316                                 environment.toString());
    317                         Assert.fail(str);
    318                     }
    319                     if (flushBeforeAfterSuspend) {
    320                         int initialNumEvents3 = listener.getCollectedEvents().size();
    321                         SensorCtsHelper.sleep(2, TimeUnit.SECONDS);
    322                         CountDownLatch flushLatch3 = sensorManager.requestFlush();
    323                         listener.waitForFlushComplete(flushLatch3, false);
    324                         Assert.assertTrue("3.No sensor events collected on calling flush " +
    325                                 environment.toString(),
    326                                 listener.getCollectedEvents().size() - initialNumEvents3 > 0);
    327                     }
    328                     Log.i(TAG, "Collected sensor events size3=" +
    329                             listener.getCollectedEvents().size());
    330                 } finally {
    331                     // make sure the device can run until the test activity take over.
    332                     if(!wakeLock.isHeld()) {
    333                         wakeLock.acquire();
    334                     }
    335                     sensorManager.unregisterListener();
    336                 }
    337             }
    338         };
    339         return new TestSensorOperation(environment, executor);
    340     }
    341 
    342     /**
    343      * Creates an operation that will wait for a given amount of time to collect events.
    344      *
    345      * @param environment The test environment.
    346      * @param duration The duration to wait for events.
    347      * @param timeUnit The time unit for {@code duration}.
    348      */
    349     public static TestSensorOperation createOperation(
    350             TestSensorEnvironment environment,
    351             final long duration,
    352             final TimeUnit timeUnit) {
    353         Executor executor = new Executor() {
    354             @Override
    355             public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
    356                     throws InterruptedException {
    357                 try {
    358                     sensorManager.registerListener(listener);
    359                     listener.waitForEvents(duration, timeUnit);
    360                 } finally {
    361                     sensorManager.unregisterListener();
    362                 }
    363             }
    364         };
    365         return new TestSensorOperation(environment, executor);
    366     }
    367 
    368     /**
    369      * Creates an operation that will wait for a given amount of time before calling
    370      * {@link TestSensorManager#requestFlush()}.
    371      *
    372      * @param environment The test environment.
    373      * @param duration The duration to wait before calling {@link TestSensorManager#requestFlush()}.
    374      * @param timeUnit The time unit for {@code duration}.
    375      */
    376     public static TestSensorOperation createFlushOperation(
    377             TestSensorEnvironment environment,
    378             final long duration,
    379             final TimeUnit timeUnit) {
    380 
    381         return createFlushOperation(environment, new int[] {(int)timeUnit.toMillis(duration)}, -1);
    382     }
    383 
    384     /**
    385      * Creates an operation that make a series of flush (by calling
    386      * {@link TestSensorManager#requestFlush()}) with predefined interval after registerListener.
    387      *
    388      * @param environment The test environment.
    389      * @param flushIntervalMs intervals between calls to {@link TestSensorManager#requestFlush()}.
    390      * @param clearEventIndex the index of interval which
    391      *        {@link TestSensorEventListerner#clearEvent} is called (-1 for never).
    392      */
    393     public static TestSensorOperation createFlushOperation(
    394             TestSensorEnvironment environment,
    395             final int [] flushIntervalMs,
    396             final int    clearEventIndex) {
    397 
    398         Assert.assertTrue(clearEventIndex >= -1 && flushIntervalMs.length > clearEventIndex);
    399 
    400         Executor executor = new Executor() {
    401             @Override
    402             public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
    403                     throws InterruptedException {
    404                 try {
    405                     sensorManager.registerListener(listener);
    406 
    407                     int i = 0;
    408                     for (int interval: flushIntervalMs) {
    409                         SensorCtsHelper.sleep(interval, TimeUnit.MILLISECONDS);
    410                         listener.waitForFlushComplete(
    411                                 sensorManager.requestFlush(),
    412                                 i <= clearEventIndex);
    413                         ++i;
    414                     }
    415                 } finally {
    416                     sensorManager.unregisterListener();
    417                 }
    418             }
    419         };
    420         return new TestSensorOperation(environment, executor);
    421     }
    422 }
    423