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 androidx.localbroadcastmanager.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 runAPWakeUpWhenReportLatencyExpires(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                     Log.i(TAG, "testTimestampClockSource skipping non-continuous sensor: '" + sensor.getName());
    245                     continue;
    246                 }
    247                 if (sensor.getType() >= Sensor.TYPE_DEVICE_PRIVATE_BASE) {
    248                     Log.i(TAG, "testTimestampClockSource skipping vendor specific sensor: '" + sensor.getName());
    249                     continue;
    250                 }
    251                 try {
    252                     string = runVerifySensorTimestampClockbase(sensor, false);
    253                     if (string != null) {
    254                         return string;
    255                     }
    256                 } catch(Throwable e) {
    257                     Log.e(TAG, e.getMessage());
    258                     error_occurred = true;
    259                 }
    260             }
    261             if (error_occurred) {
    262                 throw new Error("Sensors must use CLOCK_BOOTTIME as clock source for timestamping events");
    263             }
    264             return null;
    265         }
    266 
    267         public String runAPWakeUpWhenReportLatencyExpires(Sensor sensor) throws Throwable {
    268 
    269             verifyBatchingSupport(sensor);
    270 
    271             int fifoMaxEventCount = sensor.getFifoMaxEventCount();
    272             int samplingPeriodUs = sensor.getMaxDelay();
    273             if (samplingPeriodUs == 0) {
    274                 // If maxDelay is not defined, set the value for 5 Hz.
    275                 samplingPeriodUs = 200000;
    276             }
    277 
    278             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
    279             verifyBatchingPeriod(fifoBasedReportLatencyUs);
    280 
    281             final long MAX_REPORT_LATENCY_US = TimeUnit.SECONDS.toMicros(15); // 15 seconds
    282             TestSensorEnvironment environment = new TestSensorEnvironment(
    283                     this,
    284                     sensor,
    285                     false,
    286                     samplingPeriodUs,
    287                     (int) MAX_REPORT_LATENCY_US,
    288                     true /*isDeviceSuspendTest*/);
    289 
    290             TestSensorOperation op = TestSensorOperation.createOperation(environment,
    291                                                                           mDeviceSuspendLock,
    292                                                                           false);
    293             final long ALARM_WAKE_UP_DELAY_MS =
    294                     TimeUnit.MICROSECONDS.toMillis(MAX_REPORT_LATENCY_US) +
    295                     TimeUnit.SECONDS.toMillis(10);
    296 
    297             op.addVerification(BatchArrivalVerification.getDefault(environment));
    298             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    299                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    300                                     mPendingIntent);
    301             try {
    302                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    303                 op.execute(getCurrentTestNode());
    304             } finally {
    305                 mAlarmManager.cancel(mPendingIntent);
    306             }
    307             return null;
    308         }
    309 
    310         public String runAPWakeUpWhenFIFOFull(Sensor sensor) throws Throwable {
    311             verifyBatchingSupport(sensor);
    312 
    313             // Try to fill the FIFO at the fastest rate and check if the time is enough to run
    314             // the manual test.
    315             int samplingPeriodUs = sensor.getMinDelay();
    316 
    317             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
    318 
    319             final long MIN_LATENCY_US = TimeUnit.SECONDS.toMicros(20);
    320             // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
    321             // seconds of time to allow the device to be in suspend state.
    322             if (fifoBasedReportLatencyUs < MIN_LATENCY_US) {
    323                 int fifoMaxEventCount = sensor.getFifoMaxEventCount();
    324                 samplingPeriodUs = (int) MIN_LATENCY_US/fifoMaxEventCount;
    325                 fifoBasedReportLatencyUs = MIN_LATENCY_US;
    326             }
    327 
    328             final int MAX_REPORT_LATENCY_US = Integer.MAX_VALUE;
    329             final long ALARM_WAKE_UP_DELAY_MS =
    330                     TimeUnit.MICROSECONDS.toMillis(fifoBasedReportLatencyUs) +
    331                     TimeUnit.SECONDS.toMillis(10);
    332 
    333             TestSensorEnvironment environment = new TestSensorEnvironment(
    334                     this,
    335                     sensor,
    336                     false,
    337                     (int) samplingPeriodUs,
    338                     (int) MAX_REPORT_LATENCY_US,
    339                     true /*isDeviceSuspendTest*/);
    340 
    341             TestSensorOperation op = TestSensorOperation.createOperation(environment,
    342                                                                         mDeviceSuspendLock,
    343                                                                         true);
    344             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    345                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    346                                     mPendingIntent);
    347             op.addDefaultVerifications();
    348             try {
    349                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    350                 op.execute(getCurrentTestNode());
    351             } finally {
    352                 mAlarmManager.cancel(mPendingIntent);
    353             }
    354             return null;
    355         }
    356 
    357         /**
    358          * Verify the CLOCK_MONOTONIC and CLOCK_BOOTTIME clock sources are different
    359          * by at least 2 seconds.  Since delta between these two clock sources represents
    360          * time kernel has spent in suspend, device needs to have gone into suspend for
    361          * for at least 2 seconds since device was initially booted.
    362          */
    363         private void verifyClockDelta() throws Throwable {
    364             final int MIN_DELTA_BETWEEN_CLOCKS_MS = 2000;
    365             long uptimeMs = SystemClock.uptimeMillis();
    366             long realtimeMs = SystemClock.elapsedRealtime();
    367             long deltaMs = (realtimeMs - uptimeMs);
    368             if (deltaMs < MIN_DELTA_BETWEEN_CLOCKS_MS) {
    369                 throw new Error("Delta between clock sources too small ("
    370                                   + deltaMs + "mS), device must sleep more than "
    371                                   + MIN_DELTA_BETWEEN_CLOCKS_MS/1000 + " seconds");
    372             }
    373             Log.i(TAG, "Delta between CLOCK_MONOTONIC and CLOCK_BOOTTIME is " + deltaMs + " mS");
    374         }
    375 
    376 
    377         /**
    378          * Verify sensor is using the correct clock source (CLOCK_BOOTTIME) for timestamps.
    379          * To tell the clock sources apart, the kernel must have suspended at least once.
    380          *
    381          * @param sensor - sensor to verify
    382          * @param verify_clock_delta
    383          *          true to verify that clock sources differ before running test
    384          *          false to skip verification of sufficient delta between clock sources
    385          */
    386         public String runVerifySensorTimestampClockbase(Sensor sensor, boolean verify_clock_delta)
    387             throws Throwable {
    388             Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    389             if (verify_clock_delta) {
    390                 verifyClockDelta();
    391             }
    392             /* Enable a sensor, grab a sample, and then verify timestamp is > realtimeNs
    393              * to assure the correct clock source is being used for the sensor timestamp.
    394              */
    395             final int MIN_TIMESTAMP_BASE_SAMPLES = 1;
    396             int samplingPeriodUs = sensor.getMinDelay();
    397             TestSensorEnvironment environment = new TestSensorEnvironment(
    398                     this,
    399                     sensor,
    400                     false,
    401                     (int) samplingPeriodUs,
    402                     0,
    403                     false /*isDeviceSuspendTest*/);
    404             TestSensorOperation op = TestSensorOperation.createOperation(environment, MIN_TIMESTAMP_BASE_SAMPLES);
    405             op.addVerification(TimestampClockSourceVerification.getDefault(environment));
    406             try {
    407                 op.execute(getCurrentTestNode());
    408             } finally {
    409             }
    410             return null;
    411         }
    412 
    413 
    414         public String runAPWakeUpByAlarmNonWakeSensor(Sensor sensor, int maxReportLatencyUs)
    415             throws  Throwable {
    416             verifyBatchingSupport(sensor);
    417 
    418             int samplingPeriodUs = sensor.getMaxDelay();
    419             if (samplingPeriodUs == 0 || samplingPeriodUs > 200000) {
    420                 // If maxDelay is not defined, set the value for 5 Hz.
    421                 samplingPeriodUs = 200000;
    422             }
    423 
    424             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
    425             verifyBatchingPeriod(fifoBasedReportLatencyUs);
    426 
    427             TestSensorEnvironment environment = new TestSensorEnvironment(
    428                     this,
    429                     sensor,
    430                     false,
    431                     (int) samplingPeriodUs,
    432                     maxReportLatencyUs,
    433                     true /*isDeviceSuspendTest*/);
    434 
    435             final long ALARM_WAKE_UP_DELAY_MS = 20000;
    436             TestSensorOperation op = TestSensorOperation.createOperation(environment,
    437                                                                          mDeviceSuspendLock,
    438                                                                          true);
    439             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    440                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
    441                                     mPendingIntent);
    442             try {
    443                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
    444                 op.execute(getCurrentTestNode());
    445             } finally {
    446                 mAlarmManager.cancel(mPendingIntent);
    447             }
    448             return null;
    449         }
    450 
    451         private void verifyBatchingSupport(Sensor sensor)
    452                 throws SensorTestStateNotSupportedException {
    453             int fifoMaxEventCount = sensor.getFifoMaxEventCount();
    454             if (fifoMaxEventCount == 0) {
    455                 throw new SensorTestStateNotSupportedException("Batching not supported.");
    456             }
    457         }
    458 
    459         private void verifyBatchingPeriod(long periodUs)
    460                 throws SensorTestStateNotSupportedException {
    461             // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
    462             // seconds of time to allow the device to be in suspend state.
    463             if (periodUs < TimeUnit.SECONDS.toMicros(20)) {
    464                 throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
    465             }
    466         }
    467 
    468         private long maxBatchingPeriod (Sensor sensor, long samplePeriod) {
    469             long fifoMaxEventCount = sensor.getFifoMaxEventCount();
    470             return fifoMaxEventCount * samplePeriod;
    471         }
    472 
    473 }
    474