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 androidx.localbroadcastmanager.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 runAPWakeUpWhenReportLatencyExpires(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                     Log.i(TAG, "testTimestampClockSource skipping non-continuous sensor: '" + sensor.getName());
245                     continue;
246                 }
247                 if (sensor.getType() >= Sensor.TYPE_DEVICE_PRIVATE_BASE) {
248                     Log.i(TAG, "testTimestampClockSource skipping vendor specific sensor: '" + sensor.getName());
249                     continue;
250                 }
251                 try {
252                     string = runVerifySensorTimestampClockbase(sensor, false);
253                     if (string != null) {
254                         return string;
255                     }
256                 } catch(Throwable e) {
257                     Log.e(TAG, e.getMessage());
258                     error_occurred = true;
259                 }
260             }
261             if (error_occurred) {
262                 throw new Error("Sensors must use CLOCK_BOOTTIME as clock source for timestamping events");
263             }
264             return null;
265         }
266 
runAPWakeUpWhenReportLatencyExpires(Sensor sensor)267         public String runAPWakeUpWhenReportLatencyExpires(Sensor sensor) throws Throwable {
268 
269             verifyBatchingSupport(sensor);
270 
271             int fifoMaxEventCount = sensor.getFifoMaxEventCount();
272             int samplingPeriodUs = sensor.getMaxDelay();
273             if (samplingPeriodUs == 0) {
274                 // If maxDelay is not defined, set the value for 5 Hz.
275                 samplingPeriodUs = 200000;
276             }
277 
278             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
279             verifyBatchingPeriod(fifoBasedReportLatencyUs);
280 
281             final long MAX_REPORT_LATENCY_US = TimeUnit.SECONDS.toMicros(15); // 15 seconds
282             TestSensorEnvironment environment = new TestSensorEnvironment(
283                     this,
284                     sensor,
285                     false,
286                     samplingPeriodUs,
287                     (int) MAX_REPORT_LATENCY_US,
288                     true /*isDeviceSuspendTest*/);
289 
290             TestSensorOperation op = TestSensorOperation.createOperation(environment,
291                                                                           mDeviceSuspendLock,
292                                                                           false);
293             final long ALARM_WAKE_UP_DELAY_MS =
294                     TimeUnit.MICROSECONDS.toMillis(MAX_REPORT_LATENCY_US) +
295                     TimeUnit.SECONDS.toMillis(10);
296 
297             op.addVerification(BatchArrivalVerification.getDefault(environment));
298             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
299                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
300                                     mPendingIntent);
301             try {
302                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
303                 op.execute(getCurrentTestNode());
304             } finally {
305                 mAlarmManager.cancel(mPendingIntent);
306             }
307             return null;
308         }
309 
runAPWakeUpWhenFIFOFull(Sensor sensor)310         public String runAPWakeUpWhenFIFOFull(Sensor sensor) throws Throwable {
311             verifyBatchingSupport(sensor);
312 
313             // Try to fill the FIFO at the fastest rate and check if the time is enough to run
314             // the manual test.
315             int samplingPeriodUs = sensor.getMinDelay();
316 
317             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
318 
319             final long MIN_LATENCY_US = TimeUnit.SECONDS.toMicros(20);
320             // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
321             // seconds of time to allow the device to be in suspend state.
322             if (fifoBasedReportLatencyUs < MIN_LATENCY_US) {
323                 int fifoMaxEventCount = sensor.getFifoMaxEventCount();
324                 samplingPeriodUs = (int) MIN_LATENCY_US/fifoMaxEventCount;
325                 fifoBasedReportLatencyUs = MIN_LATENCY_US;
326             }
327 
328             final int MAX_REPORT_LATENCY_US = Integer.MAX_VALUE;
329             final long ALARM_WAKE_UP_DELAY_MS =
330                     TimeUnit.MICROSECONDS.toMillis(fifoBasedReportLatencyUs) +
331                     TimeUnit.SECONDS.toMillis(10);
332 
333             TestSensorEnvironment environment = new TestSensorEnvironment(
334                     this,
335                     sensor,
336                     false,
337                     (int) samplingPeriodUs,
338                     (int) MAX_REPORT_LATENCY_US,
339                     true /*isDeviceSuspendTest*/);
340 
341             TestSensorOperation op = TestSensorOperation.createOperation(environment,
342                                                                         mDeviceSuspendLock,
343                                                                         true);
344             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
345                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
346                                     mPendingIntent);
347             op.addDefaultVerifications();
348             try {
349                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
350                 op.execute(getCurrentTestNode());
351             } finally {
352                 mAlarmManager.cancel(mPendingIntent);
353             }
354             return null;
355         }
356 
357         /**
358          * Verify the CLOCK_MONOTONIC and CLOCK_BOOTTIME clock sources are different
359          * by at least 2 seconds.  Since delta between these two clock sources represents
360          * time kernel has spent in suspend, device needs to have gone into suspend for
361          * for at least 2 seconds since device was initially booted.
362          */
verifyClockDelta()363         private void verifyClockDelta() throws Throwable {
364             final int MIN_DELTA_BETWEEN_CLOCKS_MS = 2000;
365             long uptimeMs = SystemClock.uptimeMillis();
366             long realtimeMs = SystemClock.elapsedRealtime();
367             long deltaMs = (realtimeMs - uptimeMs);
368             if (deltaMs < MIN_DELTA_BETWEEN_CLOCKS_MS) {
369                 throw new Error("Delta between clock sources too small ("
370                                   + deltaMs + "mS), device must sleep more than "
371                                   + MIN_DELTA_BETWEEN_CLOCKS_MS/1000 + " seconds");
372             }
373             Log.i(TAG, "Delta between CLOCK_MONOTONIC and CLOCK_BOOTTIME is " + deltaMs + " mS");
374         }
375 
376 
377         /**
378          * Verify sensor is using the correct clock source (CLOCK_BOOTTIME) for timestamps.
379          * To tell the clock sources apart, the kernel must have suspended at least once.
380          *
381          * @param sensor - sensor to verify
382          * @param verify_clock_delta
383          *          true to verify that clock sources differ before running test
384          *          false to skip verification of sufficient delta between clock sources
385          */
runVerifySensorTimestampClockbase(Sensor sensor, boolean verify_clock_delta)386         public String runVerifySensorTimestampClockbase(Sensor sensor, boolean verify_clock_delta)
387             throws Throwable {
388             Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
389             if (verify_clock_delta) {
390                 verifyClockDelta();
391             }
392             /* Enable a sensor, grab a sample, and then verify timestamp is > realtimeNs
393              * to assure the correct clock source is being used for the sensor timestamp.
394              */
395             final int MIN_TIMESTAMP_BASE_SAMPLES = 1;
396             int samplingPeriodUs = sensor.getMinDelay();
397             TestSensorEnvironment environment = new TestSensorEnvironment(
398                     this,
399                     sensor,
400                     false,
401                     (int) samplingPeriodUs,
402                     0,
403                     false /*isDeviceSuspendTest*/);
404             TestSensorOperation op = TestSensorOperation.createOperation(environment, MIN_TIMESTAMP_BASE_SAMPLES);
405             op.addVerification(TimestampClockSourceVerification.getDefault(environment));
406             try {
407                 op.execute(getCurrentTestNode());
408             } finally {
409             }
410             return null;
411         }
412 
413 
runAPWakeUpByAlarmNonWakeSensor(Sensor sensor, int maxReportLatencyUs)414         public String runAPWakeUpByAlarmNonWakeSensor(Sensor sensor, int maxReportLatencyUs)
415             throws  Throwable {
416             verifyBatchingSupport(sensor);
417 
418             int samplingPeriodUs = sensor.getMaxDelay();
419             if (samplingPeriodUs == 0 || samplingPeriodUs > 200000) {
420                 // If maxDelay is not defined, set the value for 5 Hz.
421                 samplingPeriodUs = 200000;
422             }
423 
424             long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
425             verifyBatchingPeriod(fifoBasedReportLatencyUs);
426 
427             TestSensorEnvironment environment = new TestSensorEnvironment(
428                     this,
429                     sensor,
430                     false,
431                     (int) samplingPeriodUs,
432                     maxReportLatencyUs,
433                     true /*isDeviceSuspendTest*/);
434 
435             final long ALARM_WAKE_UP_DELAY_MS = 20000;
436             TestSensorOperation op = TestSensorOperation.createOperation(environment,
437                                                                          mDeviceSuspendLock,
438                                                                          true);
439             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
440                                     SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
441                                     mPendingIntent);
442             try {
443                 Log.i(TAG, "Running .. " + getCurrentTestNode().getName() + " " + sensor.getName());
444                 op.execute(getCurrentTestNode());
445             } finally {
446                 mAlarmManager.cancel(mPendingIntent);
447             }
448             return null;
449         }
450 
verifyBatchingSupport(Sensor sensor)451         private void verifyBatchingSupport(Sensor sensor)
452                 throws SensorTestStateNotSupportedException {
453             int fifoMaxEventCount = sensor.getFifoMaxEventCount();
454             if (fifoMaxEventCount == 0) {
455                 throw new SensorTestStateNotSupportedException("Batching not supported.");
456             }
457         }
458 
verifyBatchingPeriod(long periodUs)459         private void verifyBatchingPeriod(long periodUs)
460                 throws SensorTestStateNotSupportedException {
461             // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
462             // seconds of time to allow the device to be in suspend state.
463             if (periodUs < TimeUnit.SECONDS.toMicros(20)) {
464                 throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
465             }
466         }
467 
maxBatchingPeriod(Sensor sensor, long samplePeriod)468         private long maxBatchingPeriod (Sensor sensor, long samplePeriod) {
469             long fifoMaxEventCount = sensor.getFifoMaxEventCount();
470             return fifoMaxEventCount * samplePeriod;
471         }
472 
473 }
474