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