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