• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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