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