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