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