Home | History | Annotate | Download | only in sensors
      1 package com.android.cts.verifier.sensors;
      2 
      3 import java.util.ArrayList;
      4 import java.util.List;
      5 import java.util.Timer;
      6 import java.util.TimerTask;
      7 import java.util.concurrent.CountDownLatch;
      8 import java.util.concurrent.TimeUnit;
      9 
     10 import com.android.cts.verifier.R;
     11 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
     12 import com.android.cts.verifier.sensors.helpers.SensorTestScreenManipulator;
     13 
     14 import android.app.AlarmManager;
     15 import android.app.PendingIntent;
     16 import android.content.BroadcastReceiver;
     17 import android.content.Context;
     18 import android.content.Intent;
     19 import android.content.IntentFilter;
     20 import android.hardware.Sensor;
     21 import android.hardware.SensorEvent;
     22 import android.hardware.SensorEventListener;
     23 import android.hardware.SensorManager;
     24 import android.hardware.TriggerEvent;
     25 import android.hardware.TriggerEventListener;
     26 import android.hardware.cts.helpers.MovementDetectorHelper;
     27 import android.hardware.cts.helpers.SensorStats;
     28 import android.hardware.cts.helpers.SensorStats;
     29 import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
     30 import android.hardware.cts.helpers.TestSensorEnvironment;
     31 import android.hardware.cts.helpers.TestSensorEvent;
     32 import android.hardware.cts.helpers.TestSensorEventListener;
     33 import android.hardware.cts.helpers.TestSensorManager;
     34 import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
     35 import android.hardware.cts.helpers.SensorNotSupportedException;
     36 import android.hardware.cts.helpers.sensorverification.BatchArrivalVerification;
     37 import android.hardware.cts.helpers.sensorverification.TimestampClockSourceVerification;
     38 import android.os.PowerManager;
     39 import android.os.PowerManager.WakeLock;
     40 import android.os.SystemClock;
     41 import android.support.v4.content.LocalBroadcastManager;
     42 import android.util.Log;
     43 import android.view.MotionEvent;
     44 import android.view.View;
     45 
     46 import junit.framework.Assert;
     47 
     48 public class DeviceSuspendTestActivity
     49             extends SensorCtsVerifierTestActivity {
     50         public DeviceSuspendTestActivity() {
     51             super(DeviceSuspendTestActivity.class);
     52         }
     53 
     54         private SensorTestScreenManipulator mScreenManipulator;
     55         private PowerManager.WakeLock mDeviceSuspendLock;
     56         private PendingIntent mPendingIntent;
     57         private AlarmManager mAlarmManager;
     58         private static String ACTION_ALARM = "DeviceSuspendTestActivity.ACTION_ALARM";
     59         private static String TAG = "DeviceSuspendSensorTest";
     60         private SensorManager mSensorManager;
     61 
     62         @Override
     63         protected void activitySetUp() throws InterruptedException {
     64             mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
     65             mScreenManipulator = new SensorTestScreenManipulator(this);
     66             mScreenManipulator.initialize(this);
     67             LocalBroadcastManager.getInstance(this).registerReceiver(myBroadCastReceiver,
     68                                             new IntentFilter(ACTION_ALARM));
     69 
     70             Intent intent = new Intent(this, AlarmReceiver.class);
     71             mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
     72 
     73             mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
     74 
     75             PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
     76             mDeviceSuspendLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
     77                                                 "DeviceSuspendTestActivity");
     78             mDeviceSuspendLock.acquire();
     79             SensorTestLogger logger = getTestLogger();
     80             logger.logInstructions(R.string.snsr_device_suspend_test_instr);
     81             waitForUserToBegin();
     82         }
     83 
     84         @Override
     85         protected void activityCleanUp() {
     86             mScreenManipulator.turnScreenOn();
     87             try {
     88                 playSound();
     89             } catch(InterruptedException e) {
     90               // Ignore.
     91             }
     92             LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver);
     93             if (mDeviceSuspendLock != null && mDeviceSuspendLock.isHeld()) {
     94                 mDeviceSuspendLock.release();
     95             }
     96         }
     97 
     98         @Override
     99         protected void onDestroy() {
    100             super.onDestroy();
    101             if (mScreenManipulator != null) {
    102                 mScreenManipulator.releaseScreenOn();
    103                 mScreenManipulator.close();
    104             }
    105         }
    106 
    107         public static class AlarmReceiver extends BroadcastReceiver {
    108             @Override
    109             public void onReceive(Context context, Intent intent) {
    110                 Intent alarm_intent = new Intent(context, DeviceSuspendTestActivity.class);
    111                 alarm_intent.setAction(DeviceSuspendTestActivity.ACTION_ALARM);
    112                 LocalBroadcastManager.getInstance(context).sendBroadcastSync(alarm_intent);
    113             }
    114         }
    115 
    116         public BroadcastReceiver myBroadCastReceiver = new BroadcastReceiver() {
    117             @Override
    118             public void onReceive(Context context, Intent intent) {
    119                 if (!mDeviceSuspendLock.isHeld()) {
    120                     mDeviceSuspendLock.acquire();
    121                 }
    122             }
    123         };
    124 
    125         public String testAPWakeUpWhenReportLatencyExpiresAccel() throws Throwable {
    126             Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER, true);
    127             if (wakeUpSensor == null) {
    128                 throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER, true);
    129             }
    130             return runAPWakeUpWhenReportLatencyExpires(wakeUpSensor);
    131         }
    132 
    133         public String testAPWakeUpWhenReportLatencyExpiresGyro() throws Throwable {
    134             Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE, true);
    135             if (wakeUpSensor == null) {
    136                 throw new SensorNotSupportedException(Sensor.TYPE_GYROSCOPE, true);
    137             }
    138             return runAPWakeUpWhenReportLatencyExpires(wakeUpSensor);
    139         }
    140 
    141         public String testAPWakeUpWhenReportLatencyExpiresMag() throws Throwable {
    142             Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD,true);
    143             if (wakeUpSensor == null) {
    144                 throw new SensorNotSupportedException(Sensor.TYPE_MAGNETIC_FIELD, true);
    145             }
    146             return runAPWakeUpWhenFIFOFull(wakeUpSensor);
    147         }
    148 
    149         public String testAPWakeUpWhenFIFOFullAccel() throws Throwable {
    150             Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER, true);
    151             if (wakeUpSensor == null) {
    152                 throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER, true);
    153             }
    154             return runAPWakeUpWhenFIFOFull(wakeUpSensor);
    155         }
    156 
    157         public String testAPWakeUpWhenFIFOFullGyro() throws Throwable {
    158             Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE, true);
    159             if (wakeUpSensor == null) {
    160                 throw new SensorNotSupportedException(Sensor.TYPE_GYROSCOPE, true);
    161             }
    162             return runAPWakeUpWhenFIFOFull(wakeUpSensor);
    163         }
    164 
    165         public String testAPWakeUpWhenFIFOFullMag() throws Throwable {
    166             Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD,true);
    167             if (wakeUpSensor == null) {
    168                 throw new SensorNotSupportedException(Sensor.TYPE_MAGNETIC_FIELD, true);
    169             }
    170             return runAPWakeUpWhenFIFOFull(wakeUpSensor);
    171         }
    172 
    173         public String testAccelBatchingInAPSuspendLargeReportLatency() throws Throwable {
    174             Sensor accel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    175             if (accel == null) {
    176                 throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER, false);
    177             }
    178             return runAPWakeUpByAlarmNonWakeSensor(accel, (int)TimeUnit.SECONDS.toMicros(1000));
    179         }
    180 
    181         public String testAccelBatchingInAPSuspendZeroReportLatency() throws Throwable {
    182             Sensor accel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    183            if (accel == null) {
    184                 throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER, false);
    185             }
    186             return runAPWakeUpByAlarmNonWakeSensor(accel, 0);
    187         }
    188 
    189         /**
    190          * Verify that each continuous sensor is using the correct
    191          * clock source (CLOCK_BOOTTIME) for timestamps.
    192          */
    193         public String testTimestampClockSource() throws Throwable {
    194             String string = null;
    195             boolean error_occurred = false;
    196             List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
    197             if (sensorList == null) {
    198                 throw new SensorTestStateNotSupportedException(
    199                     "Sensors are not available in the system.");
    200             }
    201 
    202             // Make sure clocks are different (i.e. kernel has suspended at least once)
    203             // so that we can determine if sensors are using correct clocksource timestamp
    204             final int MAX_SLEEP_ATTEMPTS = 10;
    205             final int SLEEP_DURATION_MS = 2000;
    206             int sleep_attempts = 0;
    207             boolean device_needs_sleep = true;
    208             boolean wakelock_was_held = false;
    209 
    210             final long ALARM_WAKE_UP_DELAY_MS = TimeUnit.SECONDS.toMillis(20);
    211             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    212                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    213                                     mPendingIntent);
    214 
    215             if (mDeviceSuspendLock != null && mDeviceSuspendLock.isHeld()) {
    216                 wakelock_was_held = true;
    217                 mDeviceSuspendLock.release();
    218             }
    219 
    220             do {
    221                 try {
    222                     verifyClockDelta();
    223                     device_needs_sleep = false;
    224                 } catch(Throwable e) {
    225                     // Delta between clocks too small, must sleep longer
    226                     if (sleep_attempts++ > MAX_SLEEP_ATTEMPTS) {
    227                         mAlarmManager.cancel(mPendingIntent);
    228                         if (wakelock_was_held) {
    229                             mDeviceSuspendLock.acquire();
    230                         }
    231                         throw e;
    232                     }
    233                     Thread.sleep(SLEEP_DURATION_MS);
    234                 }
    235             } while (device_needs_sleep);
    236 
    237             if (wakelock_was_held) {
    238                 mDeviceSuspendLock.acquire();
    239             }
    240             mAlarmManager.cancel(mPendingIntent);
    241 
    242             for (Sensor sensor : sensorList) {
    243                 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
    244                     try {
    245                         string = runVerifySensorTimestampClockbase(sensor, false);
    246                         if (string != null) {
    247                             return string;
    248                         }
    249                     } catch(Throwable e) {
    250                         Log.e(TAG, e.getMessage());
    251                         error_occurred = true;
    252                     }
    253                 } else {
    254                     Log.i(TAG, "testTimestampClockSource skipping non-continuous sensor: '" + sensor.getName());
    255                 }
    256             }
    257             if (error_occurred) {
    258                 throw new Error("Sensors must use CLOCK_BOOTTIME as clock source for timestamping events");
    259             }
    260             return null;
    261         }
    262 
    263         public String runAPWakeUpWhenReportLatencyExpires(Sensor sensor) throws Throwable {
    264 
    265             verifyBatchingSupport(sensor);
    266 
    267             int fifoMaxEventCount = sensor.getFifoMaxEventCount();
    268             int samplingPeriodUs = sensor.getMaxDelay();
    269             if (samplingPeriodUs == 0) {
    270                 // If maxDelay is not defined, set the value for 5 Hz.
    271                 samplingPeriodUs = 200000;
    272             }
    273 
    274             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
    275             verifyBatchingPeriod(fifoBasedReportLatencyUs);
    276 
    277             final long MAX_REPORT_LATENCY_US = TimeUnit.SECONDS.toMicros(15); // 15 seconds
    278             TestSensorEnvironment environment = new TestSensorEnvironment(
    279                     this,
    280                     sensor,
    281                     false,
    282                     samplingPeriodUs,
    283                     (int) MAX_REPORT_LATENCY_US,
    284                     true /*isDeviceSuspendTest*/);
    285 
    286             TestSensorOperation op = TestSensorOperation.createOperation(environment,
    287                                                                           mDeviceSuspendLock,
    288                                                                           false);
    289             final long ALARM_WAKE_UP_DELAY_MS =
    290                     TimeUnit.MICROSECONDS.toMillis(MAX_REPORT_LATENCY_US) +
    291                     TimeUnit.SECONDS.toMillis(10);
    292 
    293             op.addVerification(BatchArrivalVerification.getDefault(environment));
    294             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    295                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    296                                     mPendingIntent);
    297             try {
    298                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    299                 op.execute(getCurrentTestNode());
    300             } finally {
    301                 mAlarmManager.cancel(mPendingIntent);
    302             }
    303             return null;
    304         }
    305 
    306         public String runAPWakeUpWhenFIFOFull(Sensor sensor) throws Throwable {
    307             verifyBatchingSupport(sensor);
    308 
    309             // Try to fill the FIFO at the fastest rate and check if the time is enough to run
    310             // the manual test.
    311             int samplingPeriodUs = sensor.getMinDelay();
    312 
    313             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
    314 
    315             final long MIN_LATENCY_US = TimeUnit.SECONDS.toMicros(20);
    316             // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
    317             // seconds of time to allow the device to be in suspend state.
    318             if (fifoBasedReportLatencyUs < MIN_LATENCY_US) {
    319                 int fifoMaxEventCount = sensor.getFifoMaxEventCount();
    320                 samplingPeriodUs = (int) MIN_LATENCY_US/fifoMaxEventCount;
    321                 fifoBasedReportLatencyUs = MIN_LATENCY_US;
    322             }
    323 
    324             final int MAX_REPORT_LATENCY_US = Integer.MAX_VALUE;
    325             final long ALARM_WAKE_UP_DELAY_MS =
    326                     TimeUnit.MICROSECONDS.toMillis(fifoBasedReportLatencyUs) +
    327                     TimeUnit.SECONDS.toMillis(10);
    328 
    329             TestSensorEnvironment environment = new TestSensorEnvironment(
    330                     this,
    331                     sensor,
    332                     false,
    333                     (int) samplingPeriodUs,
    334                     (int) MAX_REPORT_LATENCY_US,
    335                     true /*isDeviceSuspendTest*/);
    336 
    337             TestSensorOperation op = TestSensorOperation.createOperation(environment,
    338                                                                         mDeviceSuspendLock,
    339                                                                         true);
    340             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    341                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    342                                     mPendingIntent);
    343             op.addDefaultVerifications();
    344             try {
    345                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    346                 op.execute(getCurrentTestNode());
    347             } finally {
    348                 mAlarmManager.cancel(mPendingIntent);
    349             }
    350             return null;
    351         }
    352 
    353         /**
    354          * Verify the CLOCK_MONOTONIC and CLOCK_BOOTTIME clock sources are different
    355          * by at least 2 seconds.  Since delta between these two clock sources represents
    356          * time kernel has spent in suspend, device needs to have gone into suspend for
    357          * for at least 2 seconds since device was initially booted.
    358          */
    359         private void verifyClockDelta() throws Throwable {
    360             final int MIN_DELTA_BETWEEN_CLOCKS_MS = 2000;
    361             long uptimeMs = SystemClock.uptimeMillis();
    362             long realtimeMs = SystemClock.elapsedRealtime();
    363             long deltaMs = (realtimeMs - uptimeMs);
    364             if (deltaMs < MIN_DELTA_BETWEEN_CLOCKS_MS) {
    365                 throw new Error("Delta between clock sources too small ("
    366                                   + deltaMs + "mS), device must sleep more than "
    367                                   + MIN_DELTA_BETWEEN_CLOCKS_MS/1000 + " seconds");
    368             }
    369             Log.i(TAG, "Delta between CLOCK_MONOTONIC and CLOCK_BOOTTIME is " + deltaMs + " mS");
    370         }
    371 
    372 
    373         /**
    374          * Verify sensor is using the correct clock source (CLOCK_BOOTTIME) for timestamps.
    375          * To tell the clock sources apart, the kernel must have suspended at least once.
    376          *
    377          * @param sensor - sensor to verify
    378          * @param verify_clock_delta
    379          *          true to verify that clock sources differ before running test
    380          *          false to skip verification of sufficient delta between clock sources
    381          */
    382         public String runVerifySensorTimestampClockbase(Sensor sensor, boolean verify_clock_delta)
    383             throws Throwable {
    384             Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    385             if (verify_clock_delta) {
    386                 verifyClockDelta();
    387             }
    388             /* Enable a sensor, grab a sample, and then verify timestamp is > realtimeNs
    389              * to assure the correct clock source is being used for the sensor timestamp.
    390              */
    391             final int MIN_TIMESTAMP_BASE_SAMPLES = 1;
    392             int samplingPeriodUs = sensor.getMinDelay();
    393             TestSensorEnvironment environment = new TestSensorEnvironment(
    394                     this,
    395                     sensor,
    396                     false,
    397                     (int) samplingPeriodUs,
    398                     0,
    399                     false /*isDeviceSuspendTest*/);
    400             TestSensorOperation op = TestSensorOperation.createOperation(environment, MIN_TIMESTAMP_BASE_SAMPLES);
    401             op.addVerification(TimestampClockSourceVerification.getDefault(environment));
    402             try {
    403                 op.execute(getCurrentTestNode());
    404             } finally {
    405             }
    406             return null;
    407         }
    408 
    409 
    410         public String runAPWakeUpByAlarmNonWakeSensor(Sensor sensor, int maxReportLatencyUs)
    411             throws  Throwable {
    412             verifyBatchingSupport(sensor);
    413 
    414             int samplingPeriodUs = sensor.getMaxDelay();
    415             if (samplingPeriodUs == 0 || samplingPeriodUs > 200000) {
    416                 // If maxDelay is not defined, set the value for 5 Hz.
    417                 samplingPeriodUs = 200000;
    418             }
    419 
    420             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
    421             verifyBatchingPeriod(fifoBasedReportLatencyUs);
    422 
    423             TestSensorEnvironment environment = new TestSensorEnvironment(
    424                     this,
    425                     sensor,
    426                     false,
    427                     (int) samplingPeriodUs,
    428                     maxReportLatencyUs,
    429                     true /*isDeviceSuspendTest*/);
    430 
    431             final long ALARM_WAKE_UP_DELAY_MS = 20000;
    432             TestSensorOperation op = TestSensorOperation.createOperation(environment,
    433                                                                          mDeviceSuspendLock,
    434                                                                          true);
    435             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    436                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    437                                     mPendingIntent);
    438             try {
    439                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    440                 op.execute(getCurrentTestNode());
    441             } finally {
    442                 mAlarmManager.cancel(mPendingIntent);
    443             }
    444             return null;
    445         }
    446 
    447         private void verifyBatchingSupport(Sensor sensor)
    448                 throws SensorTestStateNotSupportedException {
    449             int fifoMaxEventCount = sensor.getFifoMaxEventCount();
    450             if (fifoMaxEventCount == 0) {
    451                 throw new SensorTestStateNotSupportedException("Batching not supported.");
    452             }
    453         }
    454 
    455         private void verifyBatchingPeriod(long periodUs)
    456                 throws SensorTestStateNotSupportedException {
    457             // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
    458             // seconds of time to allow the device to be in suspend state.
    459             if (periodUs < TimeUnit.SECONDS.toMicros(20)) {
    460                 throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
    461             }
    462         }
    463 
    464         private long maxBatchingPeriod (Sensor sensor, long samplePeriod) {
    465             long fifoMaxEventCount = sensor.getFifoMaxEventCount();
    466             return fifoMaxEventCount * samplePeriod;
    467         }
    468 
    469 }
    470