• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.cts.device.statsdatom;
18 
19 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.Truth.assertWithMessage;
23 
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assume.assumeNotNull;
26 
27 import android.accounts.Account;
28 import android.accounts.AccountManager;
29 import android.app.ActivityManager;
30 import android.app.ActivityManager.RunningServiceInfo;
31 import android.app.AppOpsManager;
32 import android.app.GameManager;
33 import android.app.GameModeConfiguration;
34 import android.app.GameState;
35 import android.app.job.JobInfo;
36 import android.app.job.JobScheduler;
37 import android.app.usage.NetworkStatsManager;
38 import android.bluetooth.le.BluetoothLeScanner;
39 import android.bluetooth.le.ScanCallback;
40 import android.bluetooth.le.ScanFilter;
41 import android.bluetooth.le.ScanResult;
42 import android.bluetooth.le.ScanSettings;
43 import android.bluetooth.test_utils.BlockingBluetoothAdapter;
44 import android.bluetooth.test_utils.EnableBluetoothRule;
45 import android.content.BroadcastReceiver;
46 import android.content.ComponentName;
47 import android.content.ContentResolver;
48 import android.content.Context;
49 import android.content.Intent;
50 import android.content.IntentFilter;
51 import android.content.pm.PackageManager;
52 import android.hardware.camera2.CameraCharacteristics;
53 import android.hardware.camera2.CameraDevice;
54 import android.hardware.camera2.CameraManager;
55 import android.location.GnssStatus;
56 import android.location.Location;
57 import android.location.LocationListener;
58 import android.location.LocationManager;
59 import android.media.MediaDrm;
60 import android.media.MediaPlayer;
61 import android.net.ConnectivityManager;
62 import android.net.Network;
63 import android.net.NetworkCapabilities;
64 import android.net.NetworkRequest;
65 import android.net.cts.util.CtsNetUtils;
66 import android.net.wifi.WifiManager;
67 import android.os.AsyncTask;
68 import android.os.Bundle;
69 import android.os.Handler;
70 import android.os.HandlerThread;
71 import android.os.Looper;
72 import android.os.PowerManager;
73 import android.os.Process;
74 import android.os.RemoteException;
75 import android.os.SystemClock;
76 import android.os.VibrationEffect;
77 import android.os.Vibrator;
78 import android.provider.Settings;
79 import android.text.TextUtils;
80 import android.util.Log;
81 import android.util.StatsEvent;
82 import android.util.StatsLog;
83 
84 import androidx.annotation.NonNull;
85 import androidx.test.InstrumentationRegistry;
86 import androidx.test.ext.junit.runners.AndroidJUnit4;
87 
88 import com.android.compatibility.common.util.PollingCheck;
89 import com.android.compatibility.common.util.ShellIdentityUtils;
90 
91 import libcore.javax.net.ssl.TestSSLContext;
92 import libcore.javax.net.ssl.TestSSLSocketPair;
93 
94 import org.junit.Assert;
95 import org.junit.ClassRule;
96 import org.junit.Test;
97 import org.junit.runner.RunWith;
98 
99 import java.net.HttpURLConnection;
100 import java.net.URL;
101 import java.util.Arrays;
102 import java.util.List;
103 import java.util.UUID;
104 import java.util.concurrent.CountDownLatch;
105 import java.util.concurrent.TimeUnit;
106 
107 import javax.net.ssl.SSLSocket;
108 
109 @RunWith(AndroidJUnit4.class)
110 public class AtomTests {
111     @ClassRule
112     public static final EnableBluetoothRule sEnableBluetoothRule = new EnableBluetoothRule();
113 
114     private static final String TAG = AtomTests.class.getSimpleName();
115 
116     private static final String MY_PACKAGE_NAME = "com.android.server.cts.device.statsdatom";
117 
118     @Test
testTlsHandshake()119     public void testTlsHandshake() throws Exception {
120         TestSSLContext context = TestSSLContext.create();
121         SSLSocket[] sockets = TestSSLSocketPair.connect(context, null, null);
122 
123         if (sockets.length < 2) {
124             return;
125         }
126         sockets[0].getOutputStream().write(42);
127         Assert.assertEquals(42, sockets[1].getInputStream().read());
128         sockets[0].close();
129         sockets[1].close();
130     }
131 
132     @Test
133     // Start the isolated service, which logs an AppBreadcrumbReported atom, and then exit.
testIsolatedProcessService()134     public void testIsolatedProcessService() throws Exception {
135         Context context = InstrumentationRegistry.getContext();
136         Intent intent = new Intent(context, IsolatedProcessService.class);
137         context.startService(intent);
138         sleep(2_000);
139         context.stopService(intent);
140     }
141 
142     @Test
testAudioState()143     public void testAudioState() {
144         // TODO: This should surely be getTargetContext(), here and everywhere, but test first.
145         Context context = InstrumentationRegistry.getContext();
146         MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.good);
147         mediaPlayer.start();
148         sleep(2_000);
149         mediaPlayer.stop();
150     }
151 
152     @Test
testBleScanOpportunistic()153     public void testBleScanOpportunistic() {
154         ScanSettings scanSettings = new ScanSettings.Builder()
155                 .setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC).build();
156         performBleScan(scanSettings, null, false);
157     }
158 
159     @Test
testBleScanUnoptimized()160     public void testBleScanUnoptimized() {
161         ScanSettings scanSettings = new ScanSettings.Builder()
162                 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
163         performBleScan(scanSettings, null, false);
164     }
165 
166     @Test
testBleScanResult()167     public void testBleScanResult() {
168         ScanSettings scanSettings = new ScanSettings.Builder()
169                 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
170         ScanFilter.Builder scanFilter = new ScanFilter.Builder();
171         performBleScan(scanSettings, Arrays.asList(scanFilter.build()), true);
172     }
173 
174     @Test
testBleScanInterrupted()175     public void testBleScanInterrupted() throws Exception {
176         BluetoothLeScanner bleScanner = sEnableBluetoothRule.mAdapter.getBluetoothLeScanner();
177         assertThat(bleScanner).isNotNull();
178         ScanSettings scanSettings = new ScanSettings.Builder()
179                 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
180         ScanCallback scanCallback = new ScanCallback() {
181             @Override
182             public void onScanResult(int callbackType, ScanResult result) {
183                 Log.v(TAG, "called onScanResult");
184             }
185 
186             @Override
187             public void onScanFailed(int errorCode) {
188                 Log.v(TAG, "called onScanFailed");
189             }
190 
191             @Override
192             public void onBatchScanResults(List<ScanResult> results) {
193                 Log.v(TAG, "called onBatchScanResults");
194             }
195         };
196 
197         int uid = Process.myUid();
198         int whatAtomId = 9_999;
199 
200         // Get the current setting for bluetooth background scanning.
201         // Set to 0 if the setting is not found or an error occurs.
202         int initialBleScanGlobalSetting = Settings.Global.getInt(
203                 InstrumentationRegistry.getTargetContext().getContentResolver(),
204                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
205 
206         // Turn off bluetooth background scanning.
207         Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
208                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
209 
210         // Change state to State.ON.
211         bleScanner.startScan(null, scanSettings, scanCallback);
212         sleep(6_000);
213         writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
214         writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
215 
216         assertThat(BlockingBluetoothAdapter.disable(true)).isTrue();
217         assertThat(BlockingBluetoothAdapter.enable()).isTrue();
218 
219         writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
220         writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
221         writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
222 
223         // Set bluetooth background scanning to original setting.
224         Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
225                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, initialBleScanGlobalSetting);
226     }
227 
writeSliceByBleScanStateChangedAtom(int atomId, int firstUid, boolean field2, boolean field3, boolean field4)228     private static void writeSliceByBleScanStateChangedAtom(int atomId, int firstUid,
229             boolean field2, boolean field3,
230             boolean field4) {
231         final StatsEvent.Builder builder = StatsEvent.newBuilder()
232                 .setAtomId(atomId)
233                 .writeAttributionChain(new int[]{firstUid}, new String[]{"tag1"})
234                 .writeBoolean(field2)
235                 .writeBoolean(field3)
236                 .writeBoolean(field4)
237                 .usePooledBuffer();
238 
239         StatsLog.write(builder.build());
240     }
241 
performBleScan(ScanSettings scanSettings, List<ScanFilter> scanFilters, boolean waitForResult)242     private static void performBleScan(ScanSettings scanSettings, List<ScanFilter> scanFilters,
243             boolean waitForResult) {
244         BluetoothLeScanner bleScanner = sEnableBluetoothRule.mAdapter.getBluetoothLeScanner();
245         assertThat(bleScanner).isNotNull();
246         CountDownLatch resultsLatch = new CountDownLatch(1);
247         ScanCallback scanCallback = new ScanCallback() {
248             @Override
249             public void onScanResult(int callbackType, ScanResult result) {
250                 Log.v(TAG, "called onScanResult");
251                 resultsLatch.countDown();
252             }
253 
254             @Override
255             public void onScanFailed(int errorCode) {
256                 Log.v(TAG, "called onScanFailed");
257             }
258 
259             @Override
260             public void onBatchScanResults(List<ScanResult> results) {
261                 Log.v(TAG, "called onBatchScanResults");
262                 resultsLatch.countDown();
263             }
264         };
265 
266         bleScanner.startScan(scanFilters, scanSettings, scanCallback);
267         if (waitForResult) {
268             waitForReceiver(InstrumentationRegistry.getContext(), 59_000, resultsLatch, null);
269         } else {
270             sleep(2_000);
271         }
272         bleScanner.stopScan(scanCallback);
273     }
274 
275     @Test
testCameraState()276     public void testCameraState() throws Exception {
277         Context context = InstrumentationRegistry.getContext();
278         CameraManager cam = context.getSystemService(CameraManager.class);
279         String[] cameraIds = cam.getCameraIdList();
280         if (cameraIds.length == 0) {
281             Log.e(TAG, "No camera found on device");
282             return;
283         }
284 
285         CountDownLatch latch = new CountDownLatch(1);
286         final CameraDevice.StateCallback cb = new CameraDevice.StateCallback() {
287             @Override
288             public void onOpened(CameraDevice cd) {
289                 Log.i(TAG, "CameraDevice " + cd.getId() + " opened");
290                 sleep(2_000);
291                 cd.close();
292             }
293 
294             @Override
295             public void onClosed(CameraDevice cd) {
296                 latch.countDown();
297                 Log.i(TAG, "CameraDevice " + cd.getId() + " closed");
298             }
299 
300             @Override
301             public void onDisconnected(CameraDevice cd) {
302                 Log.w(TAG, "CameraDevice  " + cd.getId() + " disconnected");
303             }
304 
305             @Override
306             public void onError(CameraDevice cd, int error) {
307                 Log.e(TAG, "CameraDevice " + cd.getId() + "had error " + error);
308             }
309         };
310 
311         HandlerThread handlerThread = new HandlerThread("br_handler_thread");
312         handlerThread.start();
313         Looper looper = handlerThread.getLooper();
314         Handler handler = new Handler(looper);
315 
316         cam.openCamera(cameraIds[0], cb, handler);
317         waitForReceiver(context, 10_000, latch, null);
318     }
319 
320     @Test
testFlashlight()321     public void testFlashlight() throws Exception {
322         Context context = InstrumentationRegistry.getContext();
323         CameraManager cam = context.getSystemService(CameraManager.class);
324         String[] cameraIds = cam.getCameraIdList();
325         boolean foundFlash = false;
326         for (int i = 0; i < cameraIds.length; i++) {
327             String id = cameraIds[i];
328             if (cam.getCameraCharacteristics(id).get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
329                 cam.setTorchMode(id, true);
330                 sleep(500);
331                 cam.setTorchMode(id, false);
332                 foundFlash = true;
333                 break;
334             }
335         }
336         if (!foundFlash) {
337             Log.e(TAG, "No flashlight found on device");
338         }
339     }
340 
341     @Test
testForegroundService()342     public void testForegroundService() throws Exception {
343         Context context = InstrumentationRegistry.getContext();
344         // The service goes into foreground and exits shortly
345         Intent intent = new Intent(context, StatsdCtsForegroundService.class);
346         context.startService(intent);
347         sleep(500);
348         context.stopService(intent);
349     }
350 
351     @Test
testForegroundServiceAccessAppOp()352     public void testForegroundServiceAccessAppOp() throws Exception {
353         Context context = InstrumentationRegistry.getContext();
354         Intent fgsIntent = new Intent(context, StatsdCtsForegroundService.class);
355         AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
356 
357         // No foreground service session
358         noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION);
359         sleep(500);
360 
361         // Foreground service session 1
362         context.startService(fgsIntent);
363         while (!checkIfServiceRunning(context, StatsdCtsForegroundService.class.getName())) {
364             sleep(50);
365         }
366         noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA);
367         noteAppOp(appOpsManager, AppOpsManager.OPSTR_FINE_LOCATION);
368         noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA);
369         startAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO);
370         noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO);
371         startAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA);
372         sleep(500);
373         context.stopService(fgsIntent);
374 
375         // No foreground service session
376         noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION);
377         sleep(500);
378 
379         // TODO(b/149098800): Start fgs a second time and log OPSTR_CAMERA again
380     }
381 
382     @Test
testAppOps()383     public void testAppOps() throws Exception {
384         Context context = InstrumentationRegistry.getContext();
385         AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
386         String[] opsList = AppOpsManager.getOpStrs();
387 
388         for (int i = 0; i < opsList.length; i++) {
389             String op = opsList[i];
390             if (TextUtils.isEmpty(op) || op.startsWith("android:deprecated")) {
391                 // Operation removed/deprecated
392                 continue;
393             }
394             try {
395                 noteAppOp(appOpsManager, opsList[i]);
396             } catch (SecurityException e) {
397             }
398         }
399     }
400 
noteAppOp(AppOpsManager aom, String opStr)401     private void noteAppOp(AppOpsManager aom, String opStr) {
402         aom.noteOp(opStr, android.os.Process.myUid(), MY_PACKAGE_NAME, null, "statsdTest");
403     }
404 
startAppOp(AppOpsManager aom, String opStr)405     private void startAppOp(AppOpsManager aom, String opStr) {
406         aom.startOp(opStr, android.os.Process.myUid(), MY_PACKAGE_NAME, null, "statsdTest");
407     }
408 
409     /** Check if service is running. */
checkIfServiceRunning(Context context, String serviceName)410     public boolean checkIfServiceRunning(Context context, String serviceName) {
411         ActivityManager manager = context.getSystemService(ActivityManager.class);
412         for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
413             if (serviceName.equals(service.service.getClassName()) && service.foreground) {
414                 return true;
415             }
416         }
417         return false;
418     }
419 
420     @Test
testGpsScan()421     public void testGpsScan() {
422         Context context = InstrumentationRegistry.getContext();
423         final LocationManager locManager = context.getSystemService(LocationManager.class);
424         if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
425             Log.e(TAG, "GPS provider is not enabled");
426             return;
427         }
428         CountDownLatch latch = new CountDownLatch(1);
429 
430         final LocationListener locListener = new LocationListener() {
431             public void onLocationChanged(Location location) {
432                 Log.v(TAG, "onLocationChanged: location has been obtained");
433             }
434 
435             public void onProviderDisabled(String provider) {
436                 Log.w(TAG, "onProviderDisabled " + provider);
437             }
438 
439             public void onProviderEnabled(String provider) {
440                 Log.w(TAG, "onProviderEnabled " + provider);
441             }
442 
443             public void onStatusChanged(String provider, int status, Bundle extras) {
444                 Log.w(TAG, "onStatusChanged " + provider + " " + status);
445             }
446         };
447 
448         new AsyncTask<Void, Void, Void>() {
449             @Override
450             protected Void doInBackground(Void... params) {
451                 Looper.prepare();
452                 locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 990, 0,
453                         locListener);
454                 sleep(1_000);
455                 locManager.removeUpdates(locListener);
456                 latch.countDown();
457                 return null;
458             }
459         }.execute();
460 
461         waitForReceiver(context, 59_000, latch, null);
462     }
463 
464     @Test
testGpsStatus()465     public void testGpsStatus() {
466         Context context = InstrumentationRegistry.getContext();
467         final LocationManager locManager = context.getSystemService(LocationManager.class);
468 
469         if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
470             Log.e(TAG, "GPS provider is not enabled");
471             return;
472         }
473 
474         // Time out set to 85 seconds (5 seconds for sleep and a possible 85 seconds if TTFF takes
475         // max time which would be around 90 seconds.
476         // This is based on similar location cts test timeout values.
477         final int TIMEOUT_IN_MSEC = 85_000;
478         final int SLEEP_TIME_IN_MSEC = 5_000;
479 
480         final CountDownLatch mLatchNetwork = new CountDownLatch(1);
481 
482         final LocationListener locListener = location -> {
483             Log.v(TAG, "onLocationChanged: location has been obtained");
484             mLatchNetwork.countDown();
485         };
486 
487         // fetch the networklocation first to make sure the ttff is not flaky
488         if (locManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
489             Log.i(TAG, "Request Network Location updates.");
490             locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
491                     0 /* minTime*/,
492                     0 /* minDistance */,
493                     locListener,
494                     Looper.getMainLooper());
495         }
496         waitForReceiver(context, TIMEOUT_IN_MSEC, mLatchNetwork, null);
497 
498         // TTFF could take up to 90 seconds, thus we need to wait till TTFF does occur if it does
499         // not occur in the first SLEEP_TIME_IN_MSEC
500         final CountDownLatch mLatchTtff = new CountDownLatch(1);
501 
502         GnssStatus.Callback gnssStatusCallback = new GnssStatus.Callback() {
503             @Override
504             public void onStarted() {
505                 Log.v(TAG, "Gnss Status Listener Started");
506             }
507 
508             @Override
509             public void onStopped() {
510                 Log.v(TAG, "Gnss Status Listener Stopped");
511             }
512 
513             @Override
514             public void onFirstFix(int ttffMillis) {
515                 Log.v(TAG, "Gnss Status Listener Received TTFF");
516                 mLatchTtff.countDown();
517             }
518 
519             @Override
520             public void onSatelliteStatusChanged(GnssStatus status) {
521                 Log.v(TAG, "Gnss Status Listener Received Status Update");
522             }
523         };
524 
525         boolean gnssStatusCallbackAdded = locManager.registerGnssStatusCallback(
526                 gnssStatusCallback, new Handler(Looper.getMainLooper()));
527         if (!gnssStatusCallbackAdded) {
528             // Registration of GnssMeasurements listener has failed, this indicates a platform bug.
529             Log.e(TAG, "Failed to start gnss status callback");
530         }
531 
532         locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
533                 0,
534                 0 /* minDistance */,
535                 locListener,
536                 Looper.getMainLooper());
537         sleep(SLEEP_TIME_IN_MSEC);
538         waitForReceiver(context, TIMEOUT_IN_MSEC, mLatchTtff, null);
539         locManager.removeUpdates(locListener);
540         locManager.unregisterGnssStatusCallback(gnssStatusCallback);
541     }
542 
543     @Test
testScreenBrightness()544     public void testScreenBrightness() {
545         Context context = InstrumentationRegistry.getContext();
546         PowerManager pm = context.getSystemService(PowerManager.class);
547         PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
548                 PowerManager.ACQUIRE_CAUSES_WAKEUP, "StatsdBrightnessTest");
549         wl.acquire();
550         sleep(500);
551 
552         setScreenBrightness(47);
553         sleep(500);
554         setScreenBrightness(70);
555         sleep(500);
556 
557 
558         wl.release();
559     }
560 
561     @Test
testSyncState()562     public void testSyncState() throws Exception {
563 
564         Context context = InstrumentationRegistry.getContext();
565         StatsdAuthenticator.removeAllAccounts(context);
566         AccountManager am = context.getSystemService(AccountManager.class);
567         CountDownLatch latch = StatsdSyncAdapter.resetCountDownLatch();
568 
569         Account account = StatsdAuthenticator.getTestAccount();
570         StatsdAuthenticator.ensureTestAccount(context);
571         sleep(500);
572 
573         // Just force set is syncable.
574         ContentResolver.setMasterSyncAutomatically(true);
575         sleep(500);
576         ContentResolver.setIsSyncable(account, StatsdProvider.AUTHORITY, 1);
577         // Wait for the first (automatic) sync to finish
578         waitForReceiver(context, 120_000, latch, null);
579 
580         //Sleep for 500ms, since we assert each start/stop to be ~500ms apart.
581         sleep(500);
582 
583         // Request and wait for the second sync to finish
584         latch = StatsdSyncAdapter.resetCountDownLatch();
585         StatsdSyncAdapter.requestSync(account);
586         waitForReceiver(context, 120_000, latch, null);
587         StatsdAuthenticator.removeAllAccounts(context);
588     }
589 
590     @Test
testScheduledJob()591     public void testScheduledJob() throws Exception {
592         final ComponentName name = new ComponentName(MY_PACKAGE_NAME,
593                 StatsdJobService.class.getName());
594 
595         Context context = InstrumentationRegistry.getContext();
596         JobScheduler js = context.getSystemService(JobScheduler.class);
597         assertWithMessage("JobScheduler service not available").that(js).isNotNull();
598 
599         JobInfo.Builder builder = new JobInfo.Builder(1, name);
600         builder.setOverrideDeadline(0);
601         JobInfo job = builder.build();
602 
603         CountDownLatch latch = StatsdJobService.resetCountDownLatch();
604         js.schedule(job);
605         waitForReceiver(context, 5_000, latch, null);
606     }
607 
608     @Test
testScheduledJob_CancelledJob()609     public void testScheduledJob_CancelledJob() throws Exception {
610         final ComponentName name = new ComponentName(MY_PACKAGE_NAME,
611                 StatsdJobService.class.getName());
612 
613         Context context = InstrumentationRegistry.getContext();
614         JobScheduler js = context.getSystemService(JobScheduler.class);
615         assertWithMessage("JobScheduler service not available").that(js).isNotNull();
616 
617         JobInfo.Builder builder = new JobInfo.Builder(1, name);
618         builder.setMinimumLatency(60_000L);
619         JobInfo job = builder.build();
620 
621         js.schedule(job);
622         js.cancel(1);
623     }
624 
625     @Test
testScheduledJobPriority()626     public void testScheduledJobPriority() throws Exception {
627         final ComponentName name =
628                 new ComponentName(MY_PACKAGE_NAME, StatsdJobService.class.getName());
629 
630         Context context = InstrumentationRegistry.getContext();
631         JobScheduler js = context.getSystemService(JobScheduler.class);
632         assertWithMessage("JobScheduler service not available").that(js).isNotNull();
633 
634         final int[] priorities = {
635                 JobInfo.PRIORITY_HIGH, JobInfo.PRIORITY_DEFAULT,
636                 JobInfo.PRIORITY_LOW, JobInfo.PRIORITY_MIN};
637         for (int priority : priorities) {
638             JobInfo job = new JobInfo.Builder(priority, name)
639                     .setOverrideDeadline(0)
640                     .setPriority(priority)
641                     .build();
642 
643             CountDownLatch latch = StatsdJobService.resetCountDownLatch();
644             js.schedule(job);
645             waitForReceiver(context, 5_000, latch, null);
646         }
647     }
648 
649     @Test
testVibratorState()650     public void testVibratorState() {
651         Context context = InstrumentationRegistry.getContext();
652         Vibrator vib = context.getSystemService(Vibrator.class);
653         if (vib.hasVibrator()) {
654             vib.vibrate(VibrationEffect.createOneShot(
655                     500 /* ms */, VibrationEffect.DEFAULT_AMPLITUDE));
656         }
657         // Sleep so that the app does not get killed.
658         sleep(1000);
659     }
660 
661     @Test
testWakelockState()662     public void testWakelockState() {
663         Context context = InstrumentationRegistry.getContext();
664         PowerManager pm = context.getSystemService(PowerManager.class);
665         PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
666                 "StatsdPartialWakelock");
667         wl.acquire();
668         sleep(500);
669         wl.release();
670     }
671 
672     @Test
testSliceByWakelockState()673     public void testSliceByWakelockState() {
674         int uid = Process.myUid();
675         int whatAtomId = 9_998;
676         int wakelockType = PowerManager.PARTIAL_WAKE_LOCK;
677         String tag = "StatsdPartialWakelock";
678 
679         Context context = InstrumentationRegistry.getContext();
680         PowerManager pm = context.getSystemService(PowerManager.class);
681         PowerManager.WakeLock wl = pm.newWakeLock(wakelockType, tag);
682 
683         wl.acquire();
684         sleep(500);
685         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
686         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
687         wl.acquire();
688         sleep(500);
689         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
690         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
691         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
692         wl.release();
693         sleep(500);
694         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
695         wl.release();
696         sleep(500);
697         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
698         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
699         writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
700     }
701 
writeSliceByWakelockStateChangedAtom(int atomId, int firstUid, int field2, String field3)702     private static void writeSliceByWakelockStateChangedAtom(int atomId, int firstUid,
703             int field2, String field3) {
704         final StatsEvent.Builder builder = StatsEvent.newBuilder()
705                 .setAtomId(atomId)
706                 .writeAttributionChain(new int[]{firstUid}, new String[]{"tag1"})
707                 .writeInt(field2)
708                 .writeString(field3)
709                 .usePooledBuffer();
710 
711         StatsLog.write(builder.build());
712     }
713 
714     @Test
testWakelockLoad()715     public void testWakelockLoad() {
716         final int NUM_THREADS = 16;
717         CountDownLatch latch = new CountDownLatch(NUM_THREADS);
718         for (int i = 0; i < NUM_THREADS; i++) {
719             Thread t = new Thread(new WakelockLoadTestRunnable("StatsdPartialWakelock" + i, latch));
720             t.start();
721         }
722         waitForReceiver(null, 120_000, latch, null);
723     }
724 
725     @Test
testWifiLockHighPerf()726     public void testWifiLockHighPerf() throws Exception {
727         Context context = InstrumentationRegistry.getContext();
728         boolean wifiConnected = isWifiConnected(context);
729         Assert.assertTrue(
730                 "Wifi is not connected. The test expects Wifi to be connected before the run",
731                 wifiConnected);
732 
733         WifiManager wm = context.getSystemService(WifiManager.class);
734         WifiManager.WifiLock lock =
735                 wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "StatsdCTSWifiLock");
736         lock.acquire();
737         sleep(500);
738         lock.release();
739     }
740 
741     @Test
testWifiConnected()742     public void testWifiConnected() throws Exception {
743         Context context = InstrumentationRegistry.getContext();
744         boolean wifiConnected = isWifiConnected(context);
745         Assert.assertTrue(
746                 "Wifi is not connected. The test expects Wifi to be connected before the run",
747                 wifiConnected);
748     }
749 
750     @Test
testWifiMulticastLock()751     public void testWifiMulticastLock() {
752         Context context = InstrumentationRegistry.getContext();
753         WifiManager wm = context.getSystemService(WifiManager.class);
754         WifiManager.MulticastLock lock = wm.createMulticastLock("StatsdCTSMulticastLock");
755         lock.acquire();
756         sleep(500);
757         lock.release();
758     }
759 
760     @Test
761     /** Does two wifi scans. */
762     // TODO: Copied this from BatterystatsValidation but we probably don't need to wait for results.
testWifiScan()763     public void testWifiScan() {
764         Context context = InstrumentationRegistry.getContext();
765         IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
766         // Sometimes a scan was already running (from a different uid), so the first scan doesn't
767         // start when requested. Therefore, additionally wait for whatever scan is currently running
768         // to finish, then request a scan again - at least one of these two scans should be
769         // attributed to this app.
770         for (int i = 0; i < 2; i++) {
771             CountDownLatch onReceiveLatch = new CountDownLatch(1);
772             BroadcastReceiver receiver = registerReceiver(context, onReceiveLatch, intentFilter);
773             context.getSystemService(WifiManager.class).startScan();
774             waitForReceiver(context, 60_000, onReceiveLatch, receiver);
775         }
776     }
777 
778     @Test
testWifiReconnect()779     public void testWifiReconnect() throws Exception {
780         Context context = InstrumentationRegistry.getContext();
781         boolean wifiConnected = isWifiConnected(context);
782         Assert.assertTrue(
783                 "Wifi is not connected. The test expects Wifi to be connected before the run",
784                 wifiConnected);
785 
786         wifiDisconnect(context);
787         sleep(500);
788         wifiReconnect(context);
789         sleep(500);
790     }
791 
792     @Test
testSimpleCpu()793     public void testSimpleCpu() {
794         long timestamp = System.currentTimeMillis();
795         for (int i = 0; i < 10000; i++) {
796             timestamp += i;
797         }
798         Log.i(TAG, "The answer is " + timestamp);
799     }
800 
801     /**
802      * Bring up and generate some traffic on cellular data connection.
803      */
804     @Test
testGenerateMobileTraffic()805     public void testGenerateMobileTraffic() throws Exception {
806         final Context context = InstrumentationRegistry.getContext();
807         doGenerateNetworkTraffic(context, NetworkCapabilities.TRANSPORT_CELLULAR);
808     }
809 
810     /**
811      * Force poll NetworkStatsService to get most updated network stats from lower layer.
812      */
813     @Test
testForcePollNetworkStats()814     public void testForcePollNetworkStats() throws Exception {
815         final Context context = InstrumentationRegistry.getContext();
816         final NetworkStatsManager nsm = context.getSystemService(NetworkStatsManager.class);
817         try {
818             nsm.setPollForce(true);
819             // This query is for triggering force poll NetworkStatsService.
820             nsm.querySummaryForUser(ConnectivityManager.TYPE_WIFI, null, Long.MIN_VALUE,
821                     Long.MAX_VALUE);
822         } catch (RemoteException e) {
823             Log.e(TAG, "doPollNetworkStats failed with " + e);
824         }
825     }
826 
827     // Constants which are locally used by doGenerateNetworkTraffic.
828     private static final int NETWORK_TIMEOUT_MILLIS = 15000;
829     private static final String HTTPS_HOST_URL =
830             "https://connectivitycheck.gstatic.com/generate_204";
831 
doGenerateNetworkTraffic(@onNull Context context, int transport)832     private void doGenerateNetworkTraffic(@NonNull Context context, int transport)
833             throws InterruptedException {
834         final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
835         final NetworkRequest request = new NetworkRequest.Builder().addCapability(
836                 NetworkCapabilities.NET_CAPABILITY_INTERNET).addTransportType(transport).build();
837         final CtsNetUtils.TestNetworkCallback callback = new CtsNetUtils.TestNetworkCallback();
838 
839         // Request network, and make http query when the network is available.
840         cm.requestNetwork(request, callback);
841 
842         // If network is not available, throws IllegalStateException.
843         final Network network = callback.waitForAvailable();
844         if (network == null) {
845             throw new IllegalStateException("network with transport " + transport
846                     + " is not available.");
847         }
848 
849         final long startTime = SystemClock.elapsedRealtime();
850         try {
851             exerciseRemoteHost(cm, network, new URL(HTTPS_HOST_URL));
852             Log.i(TAG, "exerciseRemoteHost successful in " + (SystemClock.elapsedRealtime()
853                     - startTime) + " ms");
854         } catch (Exception e) {
855             Log.e(TAG, "exerciseRemoteHost failed in " + (SystemClock.elapsedRealtime()
856                     - startTime) + " ms: " + e);
857         } finally {
858             cm.unregisterNetworkCallback(callback);
859         }
860     }
861 
862     /**
863      * Generate traffic on specified network.
864      */
exerciseRemoteHost(@onNull ConnectivityManager cm, @NonNull Network network, @NonNull URL url)865     private void exerciseRemoteHost(@NonNull ConnectivityManager cm, @NonNull Network network,
866             @NonNull URL url) throws Exception {
867         cm.bindProcessToNetwork(network);
868         HttpURLConnection urlc = null;
869         try {
870             urlc = (HttpURLConnection) network.openConnection(url);
871             urlc.setConnectTimeout(NETWORK_TIMEOUT_MILLIS);
872             urlc.setUseCaches(false);
873             urlc.connect();
874         } finally {
875             if (urlc != null) {
876                 urlc.disconnect();
877             }
878         }
879     }
880 
881     // ------- Helper methods
882 
883     /** Puts the current thread to sleep. */
sleep(int millis)884     static void sleep(int millis) {
885         try {
886             Thread.sleep(millis);
887         } catch (InterruptedException e) {
888             Log.e(TAG, "Interrupted exception while sleeping", e);
889         }
890     }
891 
892     /** Register receiver to determine when given action is complete. */
registerReceiver( Context ctx, CountDownLatch onReceiveLatch, IntentFilter intentFilter)893     private static BroadcastReceiver registerReceiver(
894             Context ctx, CountDownLatch onReceiveLatch, IntentFilter intentFilter) {
895         BroadcastReceiver receiver = new BroadcastReceiver() {
896             @Override
897             public void onReceive(Context context, Intent intent) {
898                 Log.d(TAG, "Received broadcast.");
899                 onReceiveLatch.countDown();
900             }
901         };
902         // Run Broadcast receiver in a different thread since the main thread will wait.
903         HandlerThread handlerThread = new HandlerThread("br_handler_thread");
904         handlerThread.start();
905         Looper looper = handlerThread.getLooper();
906         Handler handler = new Handler(looper);
907         ctx.registerReceiver(receiver, intentFilter, null, handler);
908         return receiver;
909     }
910 
911     /**
912      * Uses the receiver to wait until the action is complete. ctx and receiver may be null if no
913      * receiver is needed to be unregistered.
914      */
waitForReceiver(Context ctx, int maxWaitTimeMs, CountDownLatch latch, BroadcastReceiver receiver)915     private static void waitForReceiver(Context ctx,
916             int maxWaitTimeMs, CountDownLatch latch, BroadcastReceiver receiver) {
917         try {
918             boolean didFinish = latch.await(maxWaitTimeMs, TimeUnit.MILLISECONDS);
919             if (didFinish) {
920                 Log.v(TAG, "Finished performing action");
921             } else {
922                 // This is not necessarily a problem. If we just want to make sure a count was
923                 // recorded for the request, it doesn't matter if the action actually finished.
924                 Log.w(TAG, "Did not finish in specified time.");
925             }
926         } catch (InterruptedException e) {
927             Log.e(TAG, "Interrupted exception while awaiting action to finish", e);
928         }
929         if (ctx != null && receiver != null) {
930             ctx.unregisterReceiver(receiver);
931         }
932     }
933 
setScreenBrightness(int brightness)934     private static void setScreenBrightness(int brightness) {
935         runShellCommand("settings put system screen_brightness " + brightness);
936     }
937 
938     private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000;
939 
wifiDisconnect(Context context)940     public void wifiDisconnect(Context context) throws Exception {
941         WifiManager wifiManager = context.getSystemService(WifiManager.class);
942         ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.disconnect());
943 
944         PollingCheck.check(
945                 "Timed out waiting for Wifi to become disconnected",
946                 WIFI_CONNECT_TIMEOUT_MILLIS,
947                 () -> !isWifiConnected(context));
948     }
949 
wifiReconnect(Context context)950     public void wifiReconnect(Context context) throws Exception {
951         WifiManager wifiManager = context.getSystemService(WifiManager.class);
952         ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.reconnect());
953 
954         PollingCheck.check(
955                 "Timed out waiting for Wifi to become connected",
956                 WIFI_CONNECT_TIMEOUT_MILLIS,
957                 () -> isWifiConnected(context));
958     }
959 
isWifiConnected(Context context)960     private boolean isWifiConnected(Context context) throws Exception {
961         ConnectivityManager connManager = context.getSystemService(ConnectivityManager.class);
962         if (connManager == null) {
963             return false;
964         }
965 
966         Network[] networks = connManager.getAllNetworks();
967         for (Network network : networks) {
968             if (network == null) {
969                 continue;
970             }
971 
972             NetworkCapabilities caps = connManager.getNetworkCapabilities(network);
973             if (caps == null) {
974                 continue;
975             }
976 
977             if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
978                 return true;
979             }
980         }
981 
982         return false;
983     }
984 
985     @Test
testGameState()986     public void testGameState() throws Exception {
987         Context context = InstrumentationRegistry.getContext();
988         GameManager gameManager = context.getSystemService(GameManager.class);
989         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
990             assumeNotNull(gameManager);
991         }
992         gameManager.setGameState(new GameState(true, GameState.MODE_CONTENT, 1, 2));
993     }
994 
995     @Test
testSetGameMode()996     public void testSetGameMode() throws Exception {
997         Context context = InstrumentationRegistry.getContext();
998         GameManager gameManager = context.getSystemService(GameManager.class);
999         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
1000             assumeNotNull(gameManager);
1001         } else {
1002             assertNotNull(gameManager);
1003         }
1004         assertNotNull(context.getPackageName());
1005         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(gameManager,
1006                 (gm) -> gm.setGameMode(context.getPackageName(),
1007                         GameManager.GAME_MODE_PERFORMANCE), "android.permission.MANAGE_GAME_MODE");
1008         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(gameManager,
1009                 (gm) -> gm.setGameMode(context.getPackageName(),
1010                         GameManager.GAME_MODE_BATTERY), "android.permission.MANAGE_GAME_MODE");
1011     }
1012 
1013     @Test
testUpdateCustomGameModeConfiguration()1014     public void testUpdateCustomGameModeConfiguration() throws Exception {
1015         Context context = InstrumentationRegistry.getContext();
1016         GameManager gameManager = context.getSystemService(GameManager.class);
1017         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
1018             assumeNotNull(gameManager);
1019         } else {
1020             assertNotNull(gameManager);
1021         }
1022         assertNotNull(context.getPackageName());
1023         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(gameManager,
1024                 (gm) -> gm.updateCustomGameModeConfiguration(context.getPackageName(),
1025                         new GameModeConfiguration.Builder()
1026                                 .setScalingFactor(0.5f)
1027                                 .setFpsOverride(30).build()));
1028         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(gameManager,
1029                 (gm) -> gm.updateCustomGameModeConfiguration(context.getPackageName(),
1030                         new GameModeConfiguration.Builder()
1031                                 .setScalingFactor(0.9f)
1032                                 .setFpsOverride(60).build()));
1033     }
1034 
1035     @Test
testMediaDrmAtoms()1036     public void testMediaDrmAtoms() throws Exception {
1037         UUID clearKeyUuid = new UUID(0xe2719d58a985b3c9L, 0x781ab030af78d30eL);
1038         byte[] sid = null;
1039         final int OEM_ERROR = 123;
1040         final int ERROR_CONTEXT = 456;
1041         final int ANDROID_U = 14;
1042         try (MediaDrm drm = new MediaDrm(clearKeyUuid)) {
1043             if (getClearkeyVersionInt(drm) >= ANDROID_U) {
1044                 drm.setPropertyString("oemError", Integer.toString(OEM_ERROR));
1045                 drm.setPropertyString("errorContext", Integer.toString(ERROR_CONTEXT));
1046             }
1047             for (int i = 0; i < 2; i++) {
1048                 // Mock error is set per-session
1049                 drm.setPropertyString("drmErrorTest", "lostState");
1050                 sid = drm.openSession();
1051                 Assert.assertNotNull("null session id", sid);
1052                 try {
1053                     drm.closeSession(sid);
1054                 } catch (MediaDrm.MediaDrmStateException e) {
1055                     Log.d(TAG, "expected for lost state");
1056                 }
1057             }
1058         }
1059     }
1060 
getClearkeyVersionInt(MediaDrm drm)1061     private int getClearkeyVersionInt(MediaDrm drm) {
1062         try {
1063             return Integer.parseInt(drm.getPropertyString("version"));
1064         } catch (Exception e) {
1065             return Integer.MIN_VALUE;
1066         }
1067     }
1068 }
1069