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 package android.cts.statsdatom.statsd; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.app.AppOpEnum; 22 import android.cts.statsdatom.lib.AtomTestUtils; 23 import android.cts.statsdatom.lib.ConfigUtils; 24 import android.cts.statsdatom.lib.DeviceUtils; 25 import android.cts.statsdatom.lib.ReportUtils; 26 import android.os.WakeLockLevelEnum; 27 import android.server.ErrorSource; 28 29 import com.android.compatibility.common.util.PropertyUtil; 30 import com.android.internal.os.StatsdConfigProto.FieldValueMatcher; 31 import com.android.internal.os.StatsdConfigProto.StatsdConfig; 32 import com.android.os.AtomsProto.ANROccurred; 33 import com.android.os.AtomsProto.AppBreadcrumbReported; 34 import com.android.os.AtomsProto.AppCrashOccurred; 35 import com.android.os.AtomsProto.AppUsageEventOccurred; 36 import com.android.os.AtomsProto.Atom; 37 import com.android.os.AtomsProto.AttributionNode; 38 import com.android.os.AtomsProto.AudioStateChanged; 39 import com.android.os.AtomsProto.CameraStateChanged; 40 import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid; 41 import com.android.os.AtomsProto.FlashlightStateChanged; 42 import com.android.os.AtomsProto.ForegroundServiceAppOpSessionEnded; 43 import com.android.os.AtomsProto.ForegroundServiceStateChanged; 44 import com.android.os.AtomsProto.GpsScanStateChanged; 45 import com.android.os.AtomsProto.LmkKillOccurred; 46 import com.android.os.AtomsProto.MediaCodecStateChanged; 47 import com.android.os.AtomsProto.OverlayStateChanged; 48 import com.android.os.AtomsProto.SyncStateChanged; 49 import com.android.os.AtomsProto.TestAtomReported; 50 import com.android.os.AtomsProto.UiEventReported; 51 import com.android.os.AtomsProto.VibratorStateChanged; 52 import com.android.os.AtomsProto.WakelockStateChanged; 53 import com.android.os.StatsLog.EventMetricData; 54 import com.android.tradefed.build.IBuildInfo; 55 import com.android.tradefed.log.LogUtil; 56 import com.android.tradefed.testtype.DeviceTestCase; 57 import com.android.tradefed.testtype.IBuildReceiver; 58 import com.android.tradefed.util.Pair; 59 60 import java.util.Arrays; 61 import java.util.Collections; 62 import java.util.HashSet; 63 import java.util.List; 64 import java.util.Set; 65 import java.util.function.Function; 66 import java.util.stream.Collectors; 67 68 /** 69 * Statsd atom tests that are done via app, for atoms that report a uid. 70 */ 71 public class UidAtomTests extends DeviceTestCase implements IBuildReceiver { 72 73 private static final String TAG = "Statsd.UidAtomTests"; 74 75 private static final String TEST_PACKAGE_NAME = "com.android.server.cts.device.statsd"; 76 77 private static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay"; 78 79 private static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output"; 80 private static final String FEATURE_CAMERA = "android.hardware.camera"; 81 private static final String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash"; 82 private static final String FEATURE_CAMERA_FRONT = "android.hardware.camera.front"; 83 private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; 84 private static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps"; 85 private static final String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture"; 86 private static final String FEATURE_TV = "android.hardware.type.television"; 87 88 private IBuildInfo mCtsBuild; 89 90 @Override setUp()91 protected void setUp() throws Exception { 92 super.setUp(); 93 assertThat(mCtsBuild).isNotNull(); 94 ConfigUtils.removeConfig(getDevice()); 95 ReportUtils.clearReports(getDevice()); 96 DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild); 97 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 98 } 99 100 @Override tearDown()101 protected void tearDown() throws Exception { 102 ConfigUtils.removeConfig(getDevice()); 103 ReportUtils.clearReports(getDevice()); 104 DeviceUtils.uninstallStatsdTestApp(getDevice()); 105 super.tearDown(); 106 } 107 108 @Override setBuild(IBuildInfo buildInfo)109 public void setBuild(IBuildInfo buildInfo) { 110 mCtsBuild = buildInfo; 111 } 112 113 /** 114 * Tests that statsd correctly maps isolated uids to host uids by verifying that atoms logged 115 * from an isolated process are seen as coming from their host process. 116 */ testIsolatedToHostUidMapping()117 public void testIsolatedToHostUidMapping() throws Exception { 118 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 119 Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER, /*uidInAttributionChain=*/false); 120 121 // Create an isolated service from which an AppBreadcrumbReported atom is logged. 122 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", 123 "testIsolatedProcessService"); 124 125 // Verify correctness of data. 126 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 127 assertThat(data).hasSize(1); 128 AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported(); 129 assertThat(atom.getUid()).isEqualTo(DeviceUtils.getStatsdTestAppUid(getDevice())); 130 assertThat(atom.getLabel()).isEqualTo(0); 131 assertThat(atom.getState()).isEqualTo(AppBreadcrumbReported.State.START); 132 } 133 shouldTestLmkdStats()134 private boolean shouldTestLmkdStats() throws Exception { 135 boolean hasKernel = DeviceUtils.isKernelGreaterEqual(getDevice(), Pair.create(4, 19)); 136 boolean hasFirstApiLevel = PropertyUtil.getFirstApiLevel(getDevice()) > 30; 137 return (hasKernel && hasFirstApiLevel) 138 || "true".equals(DeviceUtils.getProperty(getDevice(), "ro.lmk.log_stats")); 139 } 140 testLmkKillOccurred()141 public void testLmkKillOccurred() throws Exception { 142 if (!shouldTestLmkdStats()) { 143 LogUtil.CLog.d("Skipping lmkd stats test."); 144 return; 145 } 146 147 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 148 Atom.LMK_KILL_OCCURRED_FIELD_NUMBER, /*uidInAttributionChain=*/false); 149 int appUid = DeviceUtils.getStatsdTestAppUid(getDevice()); 150 151 // Start the victim process (service running in process :lmk_victim) 152 // We rely on a victim process (instead of expecting the allocating process to die) 153 // because it can be flaky and dependent on lmkd configuration 154 // (e.g. the OOM reaper can get to it first, depending on the allocation timings) 155 DeviceUtils.executeServiceAction(getDevice(), "LmkVictimBackgroundService", 156 "action.end_immediately"); 157 // Start fg activity and allocate 158 try (AutoCloseable a = DeviceUtils.withActivity( 159 getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 160 "StatsdCtsForegroundActivity", "action", "action.lmk")) { 161 // Sorted list of events in order in which they occurred. 162 List<EventMetricData> data = null; 163 for (int i = 0; i < 60; ++i) { 164 Thread.sleep(1_000); 165 data = ReportUtils.getEventMetricDataList(getDevice()); 166 if (!data.isEmpty()) { 167 break; 168 } 169 } 170 171 assertThat(data).isNotEmpty(); 172 // Even though both processes might have died, the non-fg one (victim) 173 // must have been first. 174 assertThat(data.get(0).getAtom().hasLmkKillOccurred()).isTrue(); 175 LmkKillOccurred atom = data.get(0).getAtom().getLmkKillOccurred(); 176 assertThat(atom.getUid()).isEqualTo(appUid); 177 assertThat(atom.getProcessName()) 178 .isEqualTo(DeviceUtils.STATSD_ATOM_TEST_PKG + ":lmk_victim"); 179 assertThat(atom.getOomAdjScore()).isAtLeast(500); 180 assertThat(atom.getRssInBytes() + atom.getSwapInBytes()).isGreaterThan(0); 181 } 182 } 183 testAppCrashOccurred()184 public void testAppCrashOccurred() throws Exception { 185 final int atomTag = Atom.APP_CRASH_OCCURRED_FIELD_NUMBER; 186 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 187 atomTag, /*uidInAttributionChain=*/false); 188 189 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 190 "StatsdCtsForegroundActivity", "action", "action.crash"); 191 192 // Sorted list of events in order in which they occurred. 193 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 194 195 assertThat(data).hasSize(1); 196 AppCrashOccurred atom = data.get(0).getAtom().getAppCrashOccurred(); 197 // UID should belong to the run activity, not any system service. 198 assertThat(atom.getUid()).isGreaterThan(10000); 199 assertThat(atom.getEventType()).isEqualTo("crash"); 200 assertThat(atom.getIsInstantApp().getNumber()) 201 .isEqualTo(AppCrashOccurred.InstantApp.FALSE_VALUE); 202 assertThat(atom.getForegroundState().getNumber()) 203 .isEqualTo(AppCrashOccurred.ForegroundState.FOREGROUND_VALUE); 204 assertThat(atom.getPackageName()).isEqualTo(DeviceUtils.STATSD_ATOM_TEST_PKG); 205 assertThat(atom.getErrorSource()).isEqualTo(ErrorSource.DATA_APP); 206 assertFalse(atom.getIsIncremental()); 207 assertTrue((1 - atom.getLoadingProgress()) < 0.001); 208 assertEquals(-1, atom.getMillisSinceOldestPendingRead()); 209 } 210 211 public void testAppCrashOccurredNative() throws Exception { 212 if (DeviceUtils.hasFeature(getDevice(), FEATURE_TV) 213 && DeviceUtils.isDebuggable(getDevice())) { 214 // Skip TVs that are debuggable because ActivityManager does not properly terminate 215 // the activity in the event of a native crash. 216 return; 217 } 218 final int atomTag = Atom.APP_CRASH_OCCURRED_FIELD_NUMBER; 219 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 220 atomTag, /*uidInAttributionChain=*/false); 221 222 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 223 "StatsdCtsForegroundActivity", "action", "action.native_crash"); 224 225 // Sorted list of events in order in which they occurred. 226 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 227 228 assertThat(data).hasSize(1); 229 AppCrashOccurred atom = data.get(0).getAtom().getAppCrashOccurred(); 230 // UID should belong to the run activity, not any system service. 231 assertThat(atom.getUid()).isGreaterThan(10000); 232 assertThat(atom.getEventType()).isEqualTo("native_crash"); 233 assertThat(atom.getIsInstantApp().getNumber()) 234 .isEqualTo(AppCrashOccurred.InstantApp.FALSE_VALUE); 235 assertThat(atom.getForegroundState().getNumber()) 236 .isEqualTo(AppCrashOccurred.ForegroundState.FOREGROUND_VALUE); 237 assertThat(atom.getPackageName()).isEqualTo(DeviceUtils.STATSD_ATOM_TEST_PKG); 238 assertThat(atom.getErrorSource()).isEqualTo(ErrorSource.DATA_APP); 239 // TODO(b/172866626): add tests for incremental packages that crashed during loading 240 assertFalse(atom.getIsIncremental()); 241 assertTrue((1 - atom.getLoadingProgress()) < 0.001); 242 assertEquals(-1, atom.getMillisSinceOldestPendingRead()); 243 } 244 245 246 public void testAudioState() throws Exception { 247 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_AUDIO_OUTPUT)) return; 248 249 final int atomTag = Atom.AUDIO_STATE_CHANGED_FIELD_NUMBER; 250 final String name = "testAudioState"; 251 252 Set<Integer> onState = new HashSet<>( 253 Arrays.asList(AudioStateChanged.State.ON_VALUE)); 254 Set<Integer> offState = new HashSet<>( 255 Arrays.asList(AudioStateChanged.State.OFF_VALUE)); 256 257 // Add state sets to the list in order. 258 List<Set<Integer>> stateSet = Arrays.asList(onState, offState); 259 260 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 261 atomTag, /*uidInAttributionChain=*/true); 262 263 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", name); 264 265 Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); 266 // Sorted list of events in order in which they occurred. 267 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 268 269 // Because the timestamp is truncated, we skip checking time differences between state 270 // changes. 271 AtomTestUtils.assertStatesOccurred(stateSet, data, 0, 272 atom -> atom.getAudioStateChanged().getState().getNumber()); 273 274 // Check that timestamp is truncated 275 for (EventMetricData metric : data) { 276 long elapsedTimestampNs = metric.getElapsedTimestampNanos(); 277 AtomTestUtils.assertTimestampIsTruncated(elapsedTimestampNs); 278 } 279 } 280 281 public void testCameraState() throws Exception { 282 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_CAMERA) && !DeviceUtils.hasFeature( 283 getDevice(), FEATURE_CAMERA_FRONT)) { 284 return; 285 } 286 287 final int atomTag = Atom.CAMERA_STATE_CHANGED_FIELD_NUMBER; 288 Set<Integer> cameraOn = new HashSet<>(Arrays.asList(CameraStateChanged.State.ON_VALUE)); 289 Set<Integer> cameraOff = new HashSet<>(Arrays.asList(CameraStateChanged.State.OFF_VALUE)); 290 291 // Add state sets to the list in order. 292 List<Set<Integer>> stateSet = Arrays.asList(cameraOn, cameraOff); 293 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 294 atomTag, /*useAttributionChain=*/ true); 295 296 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testCameraState"); 297 298 // Sorted list of events in order in which they occurred. 299 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 300 301 // Assert that the events happened in the expected order. 302 AtomTestUtils.assertStatesOccurred(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, 303 atom -> atom.getCameraStateChanged().getState().getNumber()); 304 } 305 testDeviceCalculatedPowerUse()306 public void testDeviceCalculatedPowerUse() throws Exception { 307 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY)) return; 308 309 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 310 Atom.DEVICE_CALCULATED_POWER_USE_FIELD_NUMBER); 311 DeviceUtils.unplugDevice(getDevice()); 312 313 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 314 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testSimpleCpu"); 315 Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); 316 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 317 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 318 319 Atom atom = ReportUtils.getGaugeMetricAtoms(getDevice()).get(0); 320 assertThat(atom.getDeviceCalculatedPowerUse().getComputedPowerNanoAmpSecs()) 321 .isGreaterThan(0L); 322 DeviceUtils.resetBatteryStatus(getDevice()); 323 } 324 325 testDeviceCalculatedPowerBlameUid()326 public void testDeviceCalculatedPowerBlameUid() throws Exception { 327 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY)) return; 328 if (!DeviceUtils.hasBattery(getDevice())) { 329 return; 330 } 331 String kernelVersion = getDevice().executeShellCommand("uname -r"); 332 if (kernelVersion.contains("3.18")) { 333 LogUtil.CLog.d("Skipping calculated power blame uid test."); 334 return; 335 } 336 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 337 Atom.DEVICE_CALCULATED_POWER_BLAME_UID_FIELD_NUMBER); 338 DeviceUtils.unplugDevice(getDevice()); 339 340 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 341 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testSimpleCpu"); 342 Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); 343 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 344 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 345 346 List<Atom> atomList = ReportUtils.getGaugeMetricAtoms(getDevice()); 347 boolean uidFound = false; 348 int uid = DeviceUtils.getStatsdTestAppUid(getDevice()); 349 long uidPower = 0; 350 for (Atom atom : atomList) { 351 DeviceCalculatedPowerBlameUid item = atom.getDeviceCalculatedPowerBlameUid(); 352 if (item.getUid() == uid) { 353 assertWithMessage(String.format("Found multiple power values for uid %d", uid)) 354 .that(uidFound).isFalse(); 355 uidFound = true; 356 uidPower = item.getPowerNanoAmpSecs(); 357 } 358 } 359 assertWithMessage(String.format("No power value for uid %d", uid)).that(uidFound).isTrue(); 360 assertWithMessage(String.format("Non-positive power value for uid %d", uid)) 361 .that(uidPower).isGreaterThan(0L); 362 DeviceUtils.resetBatteryStatus(getDevice()); 363 } 364 testFlashlightState()365 public void testFlashlightState() throws Exception { 366 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_CAMERA_FLASH)) return; 367 368 final int atomTag = Atom.FLASHLIGHT_STATE_CHANGED_FIELD_NUMBER; 369 final String name = "testFlashlight"; 370 371 Set<Integer> flashlightOn = new HashSet<>( 372 Arrays.asList(FlashlightStateChanged.State.ON_VALUE)); 373 Set<Integer> flashlightOff = new HashSet<>( 374 Arrays.asList(FlashlightStateChanged.State.OFF_VALUE)); 375 376 // Add state sets to the list in order. 377 List<Set<Integer>> stateSet = Arrays.asList(flashlightOn, flashlightOff); 378 379 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 380 atomTag, /*useUidAttributionChain=*/true); 381 382 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", name); 383 384 // Sorted list of events in order in which they occurred. 385 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 386 387 // Assert that the events happened in the expected order. 388 AtomTestUtils.assertStatesOccurred(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, 389 atom -> atom.getFlashlightStateChanged().getState().getNumber()); 390 } 391 testForegroundServiceState()392 public void testForegroundServiceState() throws Exception { 393 final int atomTag = Atom.FOREGROUND_SERVICE_STATE_CHANGED_FIELD_NUMBER; 394 final String name = "testForegroundService"; 395 396 Set<Integer> enterForeground = new HashSet<>( 397 Arrays.asList(ForegroundServiceStateChanged.State.ENTER_VALUE)); 398 Set<Integer> exitForeground = new HashSet<>( 399 Arrays.asList(ForegroundServiceStateChanged.State.EXIT_VALUE)); 400 401 // Add state sets to the list in order. 402 List<Set<Integer>> stateSet = Arrays.asList(enterForeground, exitForeground); 403 404 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 405 atomTag, /*useUidAttributionChain=*/false); 406 407 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", name); 408 409 // Sorted list of events in order in which they occurred. 410 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 411 412 // Assert that the events happened in the expected order. 413 AtomTestUtils.assertStatesOccurred(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, 414 atom -> atom.getForegroundServiceStateChanged().getState().getNumber()); 415 } 416 417 testForegroundServiceAccessAppOp()418 public void testForegroundServiceAccessAppOp() throws Exception { 419 final int atomTag = Atom.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED_FIELD_NUMBER; 420 final String name = "testForegroundServiceAccessAppOp"; 421 422 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 423 atomTag, /*useUidAttributionChain=*/false); 424 425 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", name); 426 427 // Sorted list of events in order in which they occurred. 428 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 429 430 assertWithMessage("Wrong atom size").that(data.size()).isEqualTo(3); 431 for (int i = 0; i < data.size(); i++) { 432 ForegroundServiceAppOpSessionEnded atom 433 = data.get(i).getAtom().getForegroundServiceAppOpSessionEnded(); 434 final int opName = atom.getAppOpName().getNumber(); 435 final int acceptances = atom.getCountOpsAccepted(); 436 final int rejections = atom.getCountOpsRejected(); 437 final int count = acceptances + rejections; 438 int expectedCount = 0; 439 switch (opName) { 440 case AppOpEnum.APP_OP_CAMERA_VALUE: 441 expectedCount = 3; 442 break; 443 case AppOpEnum.APP_OP_FINE_LOCATION_VALUE: 444 expectedCount = 1; 445 break; 446 case AppOpEnum.APP_OP_RECORD_AUDIO_VALUE: 447 expectedCount = 2; 448 break; 449 case AppOpEnum.APP_OP_COARSE_LOCATION_VALUE: 450 // fall-through 451 default: 452 fail("Unexpected opName " + opName); 453 } 454 assertWithMessage("Wrong count for " + opName).that(count).isEqualTo(expectedCount); 455 } 456 } 457 testGpsScan()458 public void testGpsScan() throws Exception { 459 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_LOCATION_GPS)) return; 460 // Whitelist this app against background location request throttling 461 String origWhitelist = getDevice().executeShellCommand( 462 "settings get global location_background_throttle_package_whitelist").trim(); 463 getDevice().executeShellCommand(String.format( 464 "settings put global location_background_throttle_package_whitelist %s", 465 DeviceUtils.STATSD_ATOM_TEST_PKG)); 466 467 try { 468 final int atom = Atom.GPS_SCAN_STATE_CHANGED_FIELD_NUMBER; 469 final int key = GpsScanStateChanged.STATE_FIELD_NUMBER; 470 final int stateOn = GpsScanStateChanged.State.ON_VALUE; 471 final int stateOff = GpsScanStateChanged.State.OFF_VALUE; 472 final int minTimeDiffMillis = 500; 473 final int maxTimeDiffMillis = 60_000; 474 475 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), 476 DeviceUtils.STATSD_ATOM_TEST_PKG, 477 atom, /*useUidAttributionChain=*/true); 478 479 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", 480 "testGpsScan"); 481 482 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 483 assertThat(data).hasSize(2); 484 GpsScanStateChanged a0 = data.get(0).getAtom().getGpsScanStateChanged(); 485 GpsScanStateChanged a1 = data.get(1).getAtom().getGpsScanStateChanged(); 486 AtomTestUtils.assertTimeDiffBetween(data.get(0), data.get(1), minTimeDiffMillis, 487 maxTimeDiffMillis); 488 assertThat(a0.getState().getNumber()).isEqualTo(stateOn); 489 assertThat(a1.getState().getNumber()).isEqualTo(stateOff); 490 } finally { 491 if ("null".equals(origWhitelist) || "".equals(origWhitelist)) { 492 getDevice().executeShellCommand( 493 "settings delete global location_background_throttle_package_whitelist"); 494 } else { 495 getDevice().executeShellCommand(String.format( 496 "settings put global location_background_throttle_package_whitelist %s", 497 origWhitelist)); 498 } 499 } 500 } 501 testMediaCodecActivity()502 public void testMediaCodecActivity() throws Exception { 503 if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH)) return; 504 final int atomTag = Atom.MEDIA_CODEC_STATE_CHANGED_FIELD_NUMBER; 505 506 // 5 seconds. Starting video tends to be much slower than most other 507 // tests on slow devices. This is unfortunate, because it leaves a 508 // really big slop in assertStatesOccurred. It would be better if 509 // assertStatesOccurred had a tighter range on large timeouts. 510 final int waitTime = 5000; 511 512 // From {@link VideoPlayerActivity#DELAY_MILLIS} 513 final int videoDuration = 2000; 514 515 Set<Integer> onState = new HashSet<>( 516 Arrays.asList(MediaCodecStateChanged.State.ON_VALUE)); 517 Set<Integer> offState = new HashSet<>( 518 Arrays.asList(MediaCodecStateChanged.State.OFF_VALUE)); 519 520 // Add state sets to the list in order. 521 List<Set<Integer>> stateSet = Arrays.asList(onState, offState); 522 523 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 524 atomTag, /*useUidAttributionChain=*/true); 525 526 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 527 "VideoPlayerActivity", "action", "action.play_video", 528 waitTime); 529 530 // Sorted list of events in order in which they occurred. 531 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 532 533 // Assert that the events happened in the expected order. 534 AtomTestUtils.assertStatesOccurred(stateSet, data, videoDuration, 535 atom -> atom.getMediaCodecStateChanged().getState().getNumber()); 536 } 537 testOverlayState()538 public void testOverlayState() throws Exception { 539 if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH)) return; 540 final int atomTag = Atom.OVERLAY_STATE_CHANGED_FIELD_NUMBER; 541 542 Set<Integer> entered = new HashSet<>( 543 Arrays.asList(OverlayStateChanged.State.ENTERED_VALUE)); 544 Set<Integer> exited = new HashSet<>( 545 Arrays.asList(OverlayStateChanged.State.EXITED_VALUE)); 546 547 // Add state sets to the list in order. 548 List<Set<Integer>> stateSet = Arrays.asList(entered, exited); 549 550 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 551 atomTag, /*useUidAttributionChain=*/false); 552 553 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 554 "StatsdCtsForegroundActivity", "action", "action.show_application_overlay", 555 5_000); 556 557 // Sorted list of events in order in which they occurred. 558 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 559 560 // Assert that the events happened in the expected order. 561 // The overlay box should appear about 2sec after the app start 562 AtomTestUtils.assertStatesOccurred(stateSet, data, 0, 563 atom -> atom.getOverlayStateChanged().getState().getNumber()); 564 } 565 testPictureInPictureState()566 public void testPictureInPictureState() throws Exception { 567 String supported = getDevice().executeShellCommand("am supports-multiwindow"); 568 if (DeviceUtils.hasFeature(getDevice(), DeviceUtils.FEATURE_WATCH) || 569 !DeviceUtils.hasFeature(getDevice(), FEATURE_PICTURE_IN_PICTURE) || 570 !supported.contains("true")) { 571 LogUtil.CLog.d("Skipping picture in picture atom test."); 572 return; 573 } 574 575 StatsdConfig.Builder config = ConfigUtils.createConfigBuilder( 576 DeviceUtils.STATSD_ATOM_TEST_PKG); 577 FieldValueMatcher.Builder uidFvm = ConfigUtils.createUidFvm(/*uidInAttributionChain=*/false, 578 DeviceUtils.STATSD_ATOM_TEST_PKG); 579 580 // PictureInPictureStateChanged atom is used prior to rvc-qpr 581 ConfigUtils.addEventMetric(config, Atom.PICTURE_IN_PICTURE_STATE_CHANGED_FIELD_NUMBER, 582 Collections.singletonList(uidFvm)); 583 // Picture-in-picture logs' been migrated to UiEvent since rvc-qpr 584 FieldValueMatcher.Builder pkgMatcher = ConfigUtils.createFvm( 585 UiEventReported.PACKAGE_NAME_FIELD_NUMBER) 586 .setEqString(DeviceUtils.STATSD_ATOM_TEST_PKG); 587 ConfigUtils.addEventMetric(config, Atom.UI_EVENT_REPORTED_FIELD_NUMBER, 588 Arrays.asList(pkgMatcher)); 589 ConfigUtils.uploadConfig(getDevice(), config); 590 591 LogUtil.CLog.d("Playing video in Picture-in-Picture mode"); 592 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 593 "VideoPlayerActivity", "action", "action.play_video_picture_in_picture_mode"); 594 595 // Sorted list of events in order in which they occurred. 596 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 597 598 // Filter out the PictureInPictureStateChanged and UiEventReported atom 599 List<EventMetricData> pictureInPictureStateChangedData = data.stream() 600 .filter(e -> e.getAtom().hasPictureInPictureStateChanged()) 601 .collect(Collectors.toList()); 602 List<EventMetricData> uiEventReportedData = data.stream() 603 .filter(e -> e.getAtom().hasUiEventReported()) 604 .collect(Collectors.toList()); 605 606 assertThat(pictureInPictureStateChangedData).isEmpty(); 607 assertThat(uiEventReportedData).isNotEmpty(); 608 609 // See PipUiEventEnum for definitions 610 final int enterPipEventId = 603; 611 // Assert that log for entering PiP happens exactly once, we do not use 612 // assertStateOccurred here since PiP may log something else when activity finishes. 613 List<EventMetricData> entered = uiEventReportedData.stream() 614 .filter(e -> e.getAtom().getUiEventReported().getEventId() == enterPipEventId) 615 .collect(Collectors.toList()); 616 assertThat(entered).hasSize(1); 617 } 618 619 //Note: this test does not have uid, but must run on the device testScreenBrightness()620 public void testScreenBrightness() throws Exception { 621 int initialBrightness = getScreenBrightness(); 622 boolean isInitialManual = isScreenBrightnessModeManual(); 623 setScreenBrightnessMode(true); 624 setScreenBrightness(150); 625 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 626 627 final int atomTag = Atom.SCREEN_BRIGHTNESS_CHANGED_FIELD_NUMBER; 628 629 Set<Integer> screenMin = new HashSet<>(Arrays.asList(47)); 630 Set<Integer> screen100 = new HashSet<>(Arrays.asList(100)); 631 Set<Integer> screen140 = new HashSet<>(Arrays.asList(140)); 632 // Set<Integer> screenMax = new HashSet<>(Arrays.asList(255)); 633 634 // Add state sets to the list in order. 635 List<Set<Integer>> stateSet = Arrays.asList(screenMin, screen100, screen140); 636 637 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 638 atomTag); 639 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testScreenBrightness"); 640 641 // Sorted list of events in order in which they occurred. 642 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 643 644 // Restore initial screen brightness 645 setScreenBrightness(initialBrightness); 646 setScreenBrightnessMode(isInitialManual); 647 648 AtomTestUtils.popUntilFind(data, screenMin, 649 atom -> atom.getScreenBrightnessChanged().getLevel()); 650 AtomTestUtils.popUntilFindFromEnd(data, screen140, 651 atom -> atom.getScreenBrightnessChanged().getLevel()); 652 // Assert that the events happened in the expected order. 653 AtomTestUtils.assertStatesOccurred(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, 654 atom -> atom.getScreenBrightnessChanged().getLevel()); 655 } 656 testSyncState()657 public void testSyncState() throws Exception { 658 final int atomTag = Atom.SYNC_STATE_CHANGED_FIELD_NUMBER; 659 Set<Integer> syncOn = new HashSet<>(Arrays.asList(SyncStateChanged.State.ON_VALUE)); 660 Set<Integer> syncOff = new HashSet<>(Arrays.asList(SyncStateChanged.State.OFF_VALUE)); 661 662 // Add state sets to the list in order. 663 List<Set<Integer>> stateSet = Arrays.asList(syncOn, syncOff, syncOn, syncOff); 664 665 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 666 atomTag, /*useUidAttributionChain=*/true); 667 DeviceUtils.allowImmediateSyncs(getDevice()); 668 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testSyncState"); 669 670 // Sorted list of events in order in which they occurred. 671 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 672 673 // Assert that the events happened in the expected order. 674 AtomTestUtils.assertStatesOccurred(stateSet, data, 675 /* wait = */ 0 /* don't verify time differences between state changes */, 676 atom -> atom.getSyncStateChanged().getState().getNumber()); 677 } 678 testVibratorState()679 public void testVibratorState() throws Exception { 680 if (!DeviceUtils.checkDeviceFor(getDevice(), "checkVibratorSupported")) return; 681 682 final int atomTag = Atom.VIBRATOR_STATE_CHANGED_FIELD_NUMBER; 683 final String name = "testVibratorState"; 684 685 Set<Integer> onState = new HashSet<>( 686 Arrays.asList(VibratorStateChanged.State.ON_VALUE)); 687 Set<Integer> offState = new HashSet<>( 688 Arrays.asList(VibratorStateChanged.State.OFF_VALUE)); 689 690 // Add state sets to the list in order. 691 List<Set<Integer>> stateSet = Arrays.asList(onState, offState); 692 693 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 694 atomTag, /*useUidAttributionChain=*/true); 695 696 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", name); 697 698 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); 699 // Sorted list of events in order in which they occurred. 700 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 701 702 AtomTestUtils.assertStatesOccurred(stateSet, data, 300, 703 atom -> atom.getVibratorStateChanged().getState().getNumber()); 704 } 705 testWakelockState()706 public void testWakelockState() throws Exception { 707 final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER; 708 Set<Integer> wakelockOn = new HashSet<>(Arrays.asList( 709 WakelockStateChanged.State.ACQUIRE_VALUE, 710 WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE)); 711 Set<Integer> wakelockOff = new HashSet<>(Arrays.asList( 712 WakelockStateChanged.State.RELEASE_VALUE, 713 WakelockStateChanged.State.CHANGE_RELEASE_VALUE)); 714 715 final String EXPECTED_TAG = "StatsdPartialWakelock"; 716 final WakeLockLevelEnum EXPECTED_LEVEL = WakeLockLevelEnum.PARTIAL_WAKE_LOCK; 717 718 // Add state sets to the list in order. 719 List<Set<Integer>> stateSet = Arrays.asList(wakelockOn, wakelockOff); 720 721 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 722 atomTag, /*useUidAttributionChain=*/true); 723 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testWakelockState"); 724 725 // Sorted list of events in order in which they occurred. 726 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 727 728 // Assert that the events happened in the expected order. 729 AtomTestUtils.assertStatesOccurred(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, 730 atom -> atom.getWakelockStateChanged().getState().getNumber()); 731 732 for (EventMetricData event : data) { 733 String tag = event.getAtom().getWakelockStateChanged().getTag(); 734 WakeLockLevelEnum type = event.getAtom().getWakelockStateChanged().getType(); 735 assertThat(tag).isEqualTo(EXPECTED_TAG); 736 assertThat(type).isEqualTo(EXPECTED_LEVEL); 737 } 738 } 739 testANROccurred()740 public void testANROccurred() throws Exception { 741 final int atomTag = Atom.ANR_OCCURRED_FIELD_NUMBER; 742 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 743 atomTag, /*useUidAttributionChain=*/false); 744 745 try (AutoCloseable a = DeviceUtils.withActivity(getDevice(), 746 DeviceUtils.STATSD_ATOM_TEST_PKG, "ANRActivity", null, null)) { 747 Thread.sleep(AtomTestUtils.WAIT_TIME_LONG * 2); 748 getDevice().executeShellCommand( 749 "am broadcast -a action_anr -p " + DeviceUtils.STATSD_ATOM_TEST_PKG); 750 Thread.sleep(20_000); 751 } 752 753 // Sorted list of events in order in which they occurred. 754 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 755 756 assertThat(data).hasSize(1); 757 assertThat(data.get(0).getAtom().hasAnrOccurred()).isTrue(); 758 ANROccurred atom = data.get(0).getAtom().getAnrOccurred(); 759 assertThat(atom.getIsInstantApp().getNumber()) 760 .isEqualTo(ANROccurred.InstantApp.FALSE_VALUE); 761 assertThat(atom.getForegroundState().getNumber()) 762 .isEqualTo(ANROccurred.ForegroundState.FOREGROUND_VALUE); 763 assertThat(atom.getErrorSource()).isEqualTo(ErrorSource.DATA_APP); 764 assertThat(atom.getPackageName()).isEqualTo(DeviceUtils.STATSD_ATOM_TEST_PKG); 765 assertFalse(atom.getIsIncremental()); 766 assertTrue((1 - atom.getLoadingProgress()) < 0.001); 767 assertEquals(-1, atom.getMillisSinceOldestPendingRead()); 768 } 769 770 public void testWriteRawTestAtom() throws Exception { 771 final int atomTag = Atom.TEST_ATOM_REPORTED_FIELD_NUMBER; 772 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 773 atomTag, /*useUidAttributionChain=*/true); 774 775 DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testWriteRawTestAtom"); 776 777 Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); 778 // Sorted list of events in order in which they occurred. 779 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 780 assertThat(data).hasSize(4); 781 782 TestAtomReported atom = data.get(0).getAtom().getTestAtomReported(); 783 List<AttributionNode> attrChain = atom.getAttributionNodeList(); 784 assertThat(attrChain).hasSize(2); 785 assertThat(attrChain.get(0).getUid()).isEqualTo(1234); 786 assertThat(attrChain.get(0).getTag()).isEqualTo("tag1"); 787 assertThat(attrChain.get(1).getUid()).isEqualTo( 788 DeviceUtils.getStatsdTestAppUid(getDevice())); 789 assertThat(attrChain.get(1).getTag()).isEqualTo("tag2"); 790 791 assertThat(atom.getIntField()).isEqualTo(42); 792 assertThat(atom.getLongField()).isEqualTo(Long.MAX_VALUE); 793 assertThat(atom.getFloatField()).isEqualTo(3.14f); 794 assertThat(atom.getStringField()).isEqualTo("This is a basic test!"); 795 assertThat(atom.getBooleanField()).isFalse(); 796 assertThat(atom.getState().getNumber()).isEqualTo(TestAtomReported.State.ON_VALUE); 797 assertThat(atom.getBytesField().getExperimentIdList()) 798 .containsExactly(1L, 2L, 3L).inOrder(); 799 800 801 atom = data.get(1).getAtom().getTestAtomReported(); 802 attrChain = atom.getAttributionNodeList(); 803 assertThat(attrChain).hasSize(2); 804 assertThat(attrChain.get(0).getUid()).isEqualTo(9999); 805 assertThat(attrChain.get(0).getTag()).isEqualTo("tag9999"); 806 assertThat(attrChain.get(1).getUid()).isEqualTo( 807 DeviceUtils.getStatsdTestAppUid(getDevice())); 808 assertThat(attrChain.get(1).getTag()).isEmpty(); 809 810 assertThat(atom.getIntField()).isEqualTo(100); 811 assertThat(atom.getLongField()).isEqualTo(Long.MIN_VALUE); 812 assertThat(atom.getFloatField()).isEqualTo(-2.5f); 813 assertThat(atom.getStringField()).isEqualTo("Test null uid"); 814 assertThat(atom.getBooleanField()).isTrue(); 815 assertThat(atom.getState().getNumber()).isEqualTo(TestAtomReported.State.UNKNOWN_VALUE); 816 assertThat(atom.getBytesField().getExperimentIdList()) 817 .containsExactly(1L, 2L, 3L).inOrder(); 818 819 atom = data.get(2).getAtom().getTestAtomReported(); 820 attrChain = atom.getAttributionNodeList(); 821 assertThat(attrChain).hasSize(1); 822 assertThat(attrChain.get(0).getUid()).isEqualTo( 823 DeviceUtils.getStatsdTestAppUid(getDevice())); 824 assertThat(attrChain.get(0).getTag()).isEqualTo("tag1"); 825 826 assertThat(atom.getIntField()).isEqualTo(-256); 827 assertThat(atom.getLongField()).isEqualTo(-1234567890L); 828 assertThat(atom.getFloatField()).isEqualTo(42.01f); 829 assertThat(atom.getStringField()).isEqualTo("Test non chained"); 830 assertThat(atom.getBooleanField()).isTrue(); 831 assertThat(atom.getState().getNumber()).isEqualTo(TestAtomReported.State.OFF_VALUE); 832 assertThat(atom.getBytesField().getExperimentIdList()) 833 .containsExactly(1L, 2L, 3L).inOrder(); 834 835 atom = data.get(3).getAtom().getTestAtomReported(); 836 attrChain = atom.getAttributionNodeList(); 837 assertThat(attrChain).hasSize(1); 838 assertThat(attrChain.get(0).getUid()).isEqualTo( 839 DeviceUtils.getStatsdTestAppUid(getDevice())); 840 assertThat(attrChain.get(0).getTag()).isEmpty(); 841 842 assertThat(atom.getIntField()).isEqualTo(0); 843 assertThat(atom.getLongField()).isEqualTo(0L); 844 assertThat(atom.getFloatField()).isEqualTo(0f); 845 assertThat(atom.getStringField()).isEmpty(); 846 assertThat(atom.getBooleanField()).isTrue(); 847 assertThat(atom.getState().getNumber()).isEqualTo(TestAtomReported.State.OFF_VALUE); 848 assertThat(atom.getBytesField().getExperimentIdList()).isEmpty(); 849 } 850 851 public void testAppForegroundBackground() throws Exception { 852 Set<Integer> onStates = new HashSet<>(Arrays.asList( 853 AppUsageEventOccurred.EventType.MOVE_TO_FOREGROUND_VALUE)); 854 Set<Integer> offStates = new HashSet<>(Arrays.asList( 855 AppUsageEventOccurred.EventType.MOVE_TO_BACKGROUND_VALUE)); 856 857 List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order 858 ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 859 Atom.APP_USAGE_EVENT_OCCURRED_FIELD_NUMBER, /*useUidAttributionChain=*/false); 860 861 // Overlay may need to sit there a while. 862 final int waitTime = 10_500; 863 DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 864 "StatsdCtsForegroundActivity", "action", ACTION_SHOW_APPLICATION_OVERLAY, waitTime); 865 866 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 867 Function<Atom, Integer> appUsageStateFunction = 868 atom -> atom.getAppUsageEventOccurred().getEventType().getNumber(); 869 // clear out initial appusage states 870 AtomTestUtils.popUntilFind(data, onStates, appUsageStateFunction); 871 AtomTestUtils.assertStatesOccurred(stateSet, data, 0, appUsageStateFunction); 872 } 873 /* 874 public void testAppForceStopUsageEvent() throws Exception { 875 Set<Integer> onStates = new HashSet<>(Arrays.asList( 876 AppUsageEventOccurred.EventType.MOVE_TO_FOREGROUND_VALUE)); 877 Set<Integer> offStates = new HashSet<>(Arrays.asList( 878 AppUsageEventOccurred.EventType.MOVE_TO_BACKGROUND_VALUE)); 879 880 List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order 881 createAndUploadConfig(Atom.APP_USAGE_EVENT_OCCURRED_FIELD_NUMBER, false); 882 Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS); 883 884 getDevice().executeShellCommand(String.format( 885 "am start -n '%s' -e %s %s", 886 "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity", 887 "action", ACTION_LONG_SLEEP_WHILE_TOP)); 888 final int waitTime = EXTRA_WAIT_TIME_MS + 5_000; 889 Thread.sleep(waitTime); 890 891 getDevice().executeShellCommand(String.format( 892 "am force-stop %s", 893 "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity")); 894 Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS); 895 896 List<EventMetricData> data = getEventMetricDataList(); 897 Function<Atom, Integer> appUsageStateFunction = 898 atom -> atom.getAppUsageEventOccurred().getEventType().getNumber(); 899 popUntilFind(data, onStates, appUsageStateFunction); // clear out initial appusage states. 900 assertStatesOccurred(stateSet, data, 0, appUsageStateFunction); 901 } 902 */ 903 getScreenBrightness()904 private int getScreenBrightness() throws Exception { 905 return Integer.parseInt( 906 getDevice().executeShellCommand("settings get system screen_brightness").trim()); 907 } 908 isScreenBrightnessModeManual()909 private boolean isScreenBrightnessModeManual() throws Exception { 910 String mode = getDevice().executeShellCommand("settings get system screen_brightness_mode"); 911 return Integer.parseInt(mode.trim()) == 0; 912 } 913 setScreenBrightnessMode(boolean manual)914 private void setScreenBrightnessMode(boolean manual) throws Exception { 915 getDevice().executeShellCommand( 916 "settings put system screen_brightness_mode " + (manual ? 0 : 1)); 917 } 918 setScreenBrightness(int brightness)919 private void setScreenBrightness(int brightness) throws Exception { 920 getDevice().executeShellCommand("settings put system screen_brightness " + brightness); 921 } 922 } 923