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 { DeviceSuspendTestActivity()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 activitySetUp()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 activityCleanUp()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 onDestroy()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 onReceive(Context context, Intent intent)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 testAPWakeUpWhenReportLatencyExpiresAccel()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 testAPWakeUpWhenReportLatencyExpiresGyro()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 testAPWakeUpWhenReportLatencyExpiresMag()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 testAPWakeUpWhenFIFOFullAccel()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 testAPWakeUpWhenFIFOFullGyro()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 testAPWakeUpWhenFIFOFullMag()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 testAccelBatchingInAPSuspendLargeReportLatency()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 testAccelBatchingInAPSuspendZeroReportLatency()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 */ testTimestampClockSource()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 runAPWakeUpWhenReportLatencyExpires(Sensor sensor)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 runAPWakeUpWhenFIFOFull(Sensor sensor)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 */ verifyClockDelta()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 */ runVerifySensorTimestampClockbase(Sensor sensor, boolean verify_clock_delta)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 runAPWakeUpByAlarmNonWakeSensor(Sensor sensor, int maxReportLatencyUs)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 verifyBatchingSupport(Sensor sensor)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 verifyBatchingPeriod(long periodUs)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 maxBatchingPeriod(Sensor sensor, long samplePeriod)464 private long maxBatchingPeriod (Sensor sensor, long samplePeriod) { 465 long fifoMaxEventCount = sensor.getFifoMaxEventCount(); 466 return fifoMaxEventCount * samplePeriod; 467 } 468 469 } 470