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 com.android.server.cts; 17 18 import com.android.tradefed.log.LogUtil; 19 20 import java.util.Random; 21 22 /** 23 * Test for "dumpsys batterystats -c 24 * 25 * Validates reporting of battery stats based on different events 26 */ 27 public class BatteryStatsValidationTest extends ProtoDumpTestCase { 28 private static final String TAG = "BatteryStatsValidationTest"; 29 30 private static final String DEVICE_SIDE_TEST_APK = "CtsBatteryStatsApp.apk"; 31 private static final String DEVICE_SIDE_TEST_PACKAGE 32 = "com.android.server.cts.device.batterystats"; 33 private static final String DEVICE_SIDE_BG_SERVICE_COMPONENT 34 = "com.android.server.cts.device.batterystats/.BatteryStatsBackgroundService"; 35 private static final String DEVICE_SIDE_FG_ACTIVITY_COMPONENT 36 = "com.android.server.cts.device.batterystats/.BatteryStatsForegroundActivity"; 37 private static final String DEVICE_SIDE_JOB_COMPONENT 38 = "com.android.server.cts.device.batterystats/.SimpleJobService"; 39 private static final String DEVICE_SIDE_SYNC_COMPONENT 40 = "com.android.server.cts.device.batterystats.provider/" 41 + "com.android.server.cts.device.batterystats"; 42 43 // These constants are those in PackageManager. 44 public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le"; 45 public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; 46 public static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps"; 47 48 private static final int STATE_TIME_TOP_INDEX = 4; 49 private static final int STATE_TIME_FOREGROUND_SERVICE_INDEX = 5; 50 private static final int STATE_TIME_FOREGROUND_INDEX = 6; 51 private static final int STATE_TIME_BACKGROUND_INDEX = 7; 52 private static final int STATE_TIME_CACHED_INDEX = 10; 53 54 private static final long TIME_SPENT_IN_TOP = 2000; 55 private static final long TIME_SPENT_IN_FOREGROUND = 2000; 56 private static final long TIME_SPENT_IN_BACKGROUND = 2000; 57 private static final long TIME_SPENT_IN_CACHED = 4000; 58 private static final long SCREEN_STATE_CHANGE_TIMEOUT = 4000; 59 private static final long SCREEN_STATE_POLLING_INTERVAL = 500; 60 61 // Constants from BatteryStatsBgVsFgActions.java (not directly accessible here). 62 public static final String KEY_ACTION = "action"; 63 public static final String ACTION_BLE_SCAN_OPTIMIZED = "action.ble_scan_optimized"; 64 public static final String ACTION_BLE_SCAN_UNOPTIMIZED = "action.ble_scan_unoptimized"; 65 public static final String ACTION_GPS = "action.gps"; 66 public static final String ACTION_JOB_SCHEDULE = "action.jobs"; 67 public static final String ACTION_SYNC = "action.sync"; 68 public static final String ACTION_SLEEP_WHILE_BACKGROUND = "action.sleep_background"; 69 public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top"; 70 public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay"; 71 72 public static final String KEY_REQUEST_CODE = "request_code"; 73 public static final String BG_VS_FG_TAG = "BatteryStatsBgVsFgActions"; 74 75 // Constants from BatteryMangager. 76 public static final int BATTERY_STATUS_DISCHARGING = 3; 77 78 @Override setUp()79 protected void setUp() throws Exception { 80 super.setUp(); 81 82 // Uninstall to clear the history in case it's still on the device. 83 getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE); 84 } 85 86 @Override tearDown()87 protected void tearDown() throws Exception { 88 getDevice().uninstallPackage(DEVICE_SIDE_TEST_PACKAGE); 89 90 batteryOffScreenOn(); 91 super.tearDown(); 92 } 93 screenOff()94 protected void screenOff() throws Exception { 95 getDevice().executeShellCommand("dumpsys batterystats enable pretend-screen-off"); 96 } 97 98 /** 99 * This will turn the screen on for real, not just disabling pretend-screen-off 100 */ turnScreenOnForReal()101 protected void turnScreenOnForReal() throws Exception { 102 getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP"); 103 getDevice().executeShellCommand("wm dismiss-keyguard"); 104 } 105 106 /** 107 * This will send the screen to sleep 108 */ turnScreenOffForReal()109 protected void turnScreenOffForReal() throws Exception { 110 getDevice().executeShellCommand("input keyevent KEYCODE_SLEEP"); 111 } 112 batteryOnScreenOn()113 protected void batteryOnScreenOn() throws Exception { 114 getDevice().executeShellCommand("dumpsys battery unplug"); 115 getDevice().executeShellCommand("dumpsys battery set status " + BATTERY_STATUS_DISCHARGING); 116 getDevice().executeShellCommand("dumpsys batterystats disable pretend-screen-off"); 117 } 118 batteryOnScreenOff()119 protected void batteryOnScreenOff() throws Exception { 120 getDevice().executeShellCommand("dumpsys battery unplug"); 121 getDevice().executeShellCommand("dumpsys battery set status " + BATTERY_STATUS_DISCHARGING); 122 getDevice().executeShellCommand("dumpsys batterystats enable pretend-screen-off"); 123 } 124 batteryOffScreenOn()125 protected void batteryOffScreenOn() throws Exception { 126 getDevice().executeShellCommand("dumpsys battery reset"); 127 getDevice().executeShellCommand("dumpsys batterystats disable pretend-screen-off"); 128 } 129 forceStop()130 private void forceStop() throws Exception { 131 getDevice().executeShellCommand("am force-stop " + DEVICE_SIDE_TEST_PACKAGE); 132 } 133 resetBatteryStats()134 private void resetBatteryStats() throws Exception { 135 getDevice().executeShellCommand("dumpsys batterystats --reset"); 136 } 137 testAlarms()138 public void testAlarms() throws Exception { 139 batteryOnScreenOff(); 140 141 installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); 142 143 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsAlarmTest", "testAlarms"); 144 145 assertValueRange("wua", "*walarm*:com.android.server.cts.device.batterystats.ALARM", 146 5, 3, 3); 147 148 batteryOffScreenOn(); 149 } 150 testWakeLockDuration()151 public void testWakeLockDuration() throws Exception { 152 batteryOnScreenOff(); 153 154 installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); 155 156 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWakeLockTests", 157 "testHoldShortWakeLock"); 158 159 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWakeLockTests", 160 "testHoldLongWakeLock"); 161 162 assertValueRange("wl", "BSShortWakeLock", 15, (long) (500 * 0.9), 500 * 2); // partial max duration 163 assertValueRange("wl", "BSLongWakeLock", 15, (long) (3000 * 0.9), 3000 * 2); // partial max duration 164 165 batteryOffScreenOn(); 166 } 167 startSimpleActivity()168 private void startSimpleActivity() throws Exception { 169 getDevice().executeShellCommand( 170 "am start -n com.android.server.cts.device.batterystats/.SimpleActivity"); 171 } 172 testServiceForegroundDuration()173 public void testServiceForegroundDuration() throws Exception { 174 batteryOnScreenOff(); 175 installPackage(DEVICE_SIDE_TEST_APK, true); 176 177 startSimpleActivity(); 178 assertValueRange("st", "", STATE_TIME_FOREGROUND_SERVICE_INDEX, 0, 179 0); // No foreground service time before test 180 final long startTime = System.nanoTime(); 181 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsProcessStateTests", 182 "testForegroundService"); 183 assertValueRange("st", "", STATE_TIME_FOREGROUND_SERVICE_INDEX, (long) (2000 * 0.8), 184 (System.nanoTime() - startTime) / 1000000); 185 batteryOffScreenOn(); 186 } 187 testUidForegroundDuration()188 public void testUidForegroundDuration() throws Exception { 189 batteryOnScreenOff(); 190 installPackage(DEVICE_SIDE_TEST_APK, true); 191 // No foreground time before test 192 assertValueRange("st", "", STATE_TIME_FOREGROUND_INDEX, 0, 0); 193 turnScreenOnForReal(); 194 assertScreenOn(); 195 executeForeground(ACTION_SHOW_APPLICATION_OVERLAY, 2000); 196 Thread.sleep(TIME_SPENT_IN_FOREGROUND); // should be in foreground for about this long 197 assertApproximateTimeInState(STATE_TIME_FOREGROUND_INDEX, TIME_SPENT_IN_FOREGROUND); 198 batteryOffScreenOn(); 199 } 200 testUidBackgroundDuration()201 public void testUidBackgroundDuration() throws Exception { 202 batteryOnScreenOff(); 203 installPackage(DEVICE_SIDE_TEST_APK, true); 204 // No background time before test 205 assertValueRange("st", "", STATE_TIME_BACKGROUND_INDEX, 0, 0); 206 executeBackground(ACTION_SLEEP_WHILE_BACKGROUND, 4000); 207 assertApproximateTimeInState(STATE_TIME_BACKGROUND_INDEX, TIME_SPENT_IN_BACKGROUND); 208 batteryOffScreenOn(); 209 } 210 testTopDuration()211 public void testTopDuration() throws Exception { 212 batteryOnScreenOff(); 213 installPackage(DEVICE_SIDE_TEST_APK, true); 214 // No top time before test 215 assertValueRange("st", "", STATE_TIME_TOP_INDEX, 0, 0); 216 turnScreenOnForReal(); 217 assertScreenOn(); 218 executeForeground(ACTION_SLEEP_WHILE_TOP, 4000); 219 assertApproximateTimeInState(STATE_TIME_TOP_INDEX, TIME_SPENT_IN_TOP); 220 batteryOffScreenOn(); 221 } 222 testCachedDuration()223 public void testCachedDuration() throws Exception { 224 batteryOnScreenOff(); 225 installPackage(DEVICE_SIDE_TEST_APK, true); 226 // No cached time before test 227 assertValueRange("st", "", STATE_TIME_CACHED_INDEX, 0, 0); 228 startSimpleActivity(); 229 Thread.sleep(TIME_SPENT_IN_CACHED); // process should be in cached state for about this long 230 assertApproximateTimeInState(STATE_TIME_CACHED_INDEX, TIME_SPENT_IN_CACHED); 231 batteryOffScreenOn(); 232 } 233 assertScreenOff()234 private void assertScreenOff() throws Exception { 235 final long deadLine = System.currentTimeMillis() + SCREEN_STATE_CHANGE_TIMEOUT; 236 boolean screenAwake = true; 237 do { 238 final String dumpsysPower = getDevice().executeShellCommand("dumpsys power").trim(); 239 for (String line : dumpsysPower.split("\n")) { 240 if (line.contains("Display Power")) { 241 screenAwake = line.trim().endsWith("ON"); 242 break; 243 } 244 } 245 Thread.sleep(SCREEN_STATE_POLLING_INTERVAL); 246 } while (screenAwake && System.currentTimeMillis() < deadLine); 247 assertFalse("Screen could not be turned off", screenAwake); 248 } 249 assertScreenOn()250 private void assertScreenOn() throws Exception { 251 // this also checks that the keyguard is dismissed 252 final long deadLine = System.currentTimeMillis() + SCREEN_STATE_CHANGE_TIMEOUT; 253 boolean screenAwake; 254 do { 255 final String dumpsysWindowPolicy = 256 getDevice().executeShellCommand("dumpsys window policy").trim(); 257 boolean keyguardStateLines = false; 258 screenAwake = true; 259 for (String line : dumpsysWindowPolicy.split("\n")) { 260 if (line.contains("KeyguardServiceDelegate")) { 261 keyguardStateLines = true; 262 } else if (keyguardStateLines && line.contains("showing=")) { 263 screenAwake &= line.trim().endsWith("false"); 264 } else if (keyguardStateLines && line.contains("screenState=")) { 265 screenAwake &= line.trim().endsWith("SCREEN_STATE_ON"); 266 } 267 } 268 Thread.sleep(SCREEN_STATE_POLLING_INTERVAL); 269 } while (!screenAwake && System.currentTimeMillis() < deadLine); 270 assertTrue("Screen could not be turned on", screenAwake); 271 } 272 testBleScans()273 public void testBleScans() throws Exception { 274 if (noBattery() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) { 275 return; 276 } 277 278 batteryOnScreenOff(); 279 installPackage(DEVICE_SIDE_TEST_APK, true); 280 turnScreenOnForReal(); 281 assertScreenOn(); 282 283 // Background test. 284 executeBackground(ACTION_BLE_SCAN_UNOPTIMIZED, 40_000); 285 assertValueRange("blem", "", 5, 1, 1); // ble_scan_count 286 assertValueRange("blem", "", 6, 1, 1); // ble_scan_count_bg 287 288 // Foreground test. 289 executeForeground(ACTION_BLE_SCAN_UNOPTIMIZED, 40_000); 290 assertValueRange("blem", "", 5, 2, 2); // ble_scan_count 291 assertValueRange("blem", "", 6, 1, 1); // ble_scan_count_bg 292 293 batteryOffScreenOn(); 294 } 295 296 testUnoptimizedBleScans()297 public void testUnoptimizedBleScans() throws Exception { 298 if (noBattery() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) { 299 return; 300 } 301 batteryOnScreenOff(); 302 installPackage(DEVICE_SIDE_TEST_APK, true); 303 turnScreenOnForReal(); 304 assertScreenOn(); 305 // Ble scan time in BatteryStatsBgVsFgActions is 2 seconds, but be lenient. 306 final int minTime = 1500; // min single scan time in ms 307 final int maxTime = 3000; // max single scan time in ms 308 309 // Optimized - Background. 310 executeBackground(ACTION_BLE_SCAN_OPTIMIZED, 40_000); 311 assertValueRange("blem", "", 7, 1*minTime, 1*maxTime); // actualTime 312 assertValueRange("blem", "", 8, 1*minTime, 1*maxTime); // actualTimeBg 313 assertValueRange("blem", "", 11, 0, 0); // unoptimizedScanTotalTime 314 assertValueRange("blem", "", 12, 0, 0); // unoptimizedScanTotalTimeBg 315 assertValueRange("blem", "", 13, 0, 0); // unoptimizedScanMaxTime 316 assertValueRange("blem", "", 14, 0, 0); // unoptimizedScanMaxTimeBg 317 318 // Optimized - Foreground. 319 executeForeground(ACTION_BLE_SCAN_OPTIMIZED, 40_000); 320 assertValueRange("blem", "", 7, 2*minTime, 2*maxTime); // actualTime 321 assertValueRange("blem", "", 8, 1*minTime, 1*maxTime); // actualTimeBg 322 assertValueRange("blem", "", 11, 0, 0); // unoptimizedScanTotalTime 323 assertValueRange("blem", "", 12, 0, 0); // unoptimizedScanTotalTimeBg 324 assertValueRange("blem", "", 13, 0, 0); // unoptimizedScanMaxTime 325 assertValueRange("blem", "", 14, 0, 0); // unoptimizedScanMaxTimeBg 326 327 // Unoptimized - Background. 328 executeBackground(ACTION_BLE_SCAN_UNOPTIMIZED, 40_000); 329 assertValueRange("blem", "", 7, 3*minTime, 3*maxTime); // actualTime 330 assertValueRange("blem", "", 8, 2*minTime, 2*maxTime); // actualTimeBg 331 assertValueRange("blem", "", 11, 1*minTime, 1*maxTime); // unoptimizedScanTotalTime 332 assertValueRange("blem", "", 12, 1*minTime, 1*maxTime); // unoptimizedScanTotalTimeBg 333 assertValueRange("blem", "", 13, 1*minTime, 1*maxTime); // unoptimizedScanMaxTime 334 assertValueRange("blem", "", 14, 1*minTime, 1*maxTime); // unoptimizedScanMaxTimeBg 335 336 // Unoptimized - Foreground. 337 executeForeground(ACTION_BLE_SCAN_UNOPTIMIZED, 40_000); 338 assertValueRange("blem", "", 7, 4*minTime, 4*maxTime); // actualTime 339 assertValueRange("blem", "", 8, 2*minTime, 2*maxTime); // actualTimeBg 340 assertValueRange("blem", "", 11, 2*minTime, 2*maxTime); // unoptimizedScanTotalTime 341 assertValueRange("blem", "", 12, 1*minTime, 1*maxTime); // unoptimizedScanTotalTimeBg 342 assertValueRange("blem", "", 13, 1*minTime, 1*maxTime); // unoptimizedScanMaxTime 343 assertValueRange("blem", "", 14, 1*minTime, 1*maxTime); // unoptimizedScanMaxTimeBg 344 345 batteryOffScreenOn(); 346 } 347 testGpsUpdates()348 public void testGpsUpdates() throws Exception { 349 if (noBattery() || !hasFeature(FEATURE_LOCATION_GPS, true)) { 350 return; 351 } 352 353 final String gpsSensorNumber = "-10000"; 354 355 batteryOnScreenOff(); 356 installPackage(DEVICE_SIDE_TEST_APK, true); 357 // Whitelist this app against background location request throttling 358 String origWhitelist = getDevice().executeShellCommand( 359 "settings get global location_background_throttle_package_whitelist").trim(); 360 getDevice().executeShellCommand(String.format( 361 "settings put global location_background_throttle_package_whitelist %s", 362 DEVICE_SIDE_TEST_PACKAGE)); 363 364 try { 365 // Background test. 366 executeBackground(ACTION_GPS, 60_000); 367 assertValueRange("sr", gpsSensorNumber, 6, 1, 1); // count 368 assertValueRange("sr", gpsSensorNumber, 7, 1, 1); // background_count 369 370 // Foreground test. 371 executeForeground(ACTION_GPS, 60_000); 372 assertValueRange("sr", gpsSensorNumber, 6, 2, 2); // count 373 assertValueRange("sr", gpsSensorNumber, 7, 1, 1); // background_count 374 } finally { 375 if ("null".equals(origWhitelist) || "".equals(origWhitelist)) { 376 getDevice().executeShellCommand( 377 "settings delete global location_background_throttle_package_whitelist"); 378 } else { 379 getDevice().executeShellCommand(String.format( 380 "settings put global location_background_throttle_package_whitelist %s", 381 origWhitelist)); 382 } 383 batteryOffScreenOn(); 384 } 385 } 386 testJobBgVsFg()387 public void testJobBgVsFg() throws Exception { 388 if (noBattery()) { 389 return; 390 } 391 batteryOnScreenOff(); 392 installPackage(DEVICE_SIDE_TEST_APK, true); 393 turnScreenOnForReal(); 394 assertScreenOn(); 395 allowImmediateSyncs(); 396 397 // Background test. 398 executeBackground(ACTION_JOB_SCHEDULE, 60_000); 399 assertValueRange("jb", "", 6, 1, 1); // count 400 assertValueRange("jb", "", 8, 1, 1); // background_count 401 402 // Foreground test. 403 executeForeground(ACTION_JOB_SCHEDULE, 60_000); 404 assertValueRange("jb", "", 6, 2, 2); // count 405 assertValueRange("jb", "", 8, 1, 1); // background_count 406 407 batteryOffScreenOn(); 408 } 409 testSyncBgVsFg()410 public void testSyncBgVsFg() throws Exception { 411 if (noBattery()) { 412 return; 413 } 414 batteryOnScreenOff(); 415 installPackage(DEVICE_SIDE_TEST_APK, true); 416 turnScreenOnForReal(); 417 assertScreenOn(); 418 allowImmediateSyncs(); 419 420 // Background test. 421 executeBackground(ACTION_SYNC, 60_000); 422 // Allow one or two syncs in this time frame (not just one) due to unpredictable syncs. 423 assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 1, 2); // count 424 assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 8, 1, 2); // background_count 425 426 // Foreground test. 427 executeForeground(ACTION_SYNC, 60_000); 428 assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 2, 4); // count 429 assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 8, 1, 2); // background_count 430 431 batteryOffScreenOn(); 432 } 433 434 /** 435 * Tests whether the on-battery realtime and total realtime values 436 * are properly updated in battery stats. 437 */ testRealtime()438 public void testRealtime() throws Exception { 439 batteryOnScreenOff(); 440 long startingValueRealtime = getLongValue(0, "bt", "", 7); 441 long startingValueBatteryRealtime = getLongValue(0, "bt", "", 5); 442 // After going on battery 443 Thread.sleep(2000); 444 batteryOffScreenOn(); 445 // After going off battery 446 Thread.sleep(2000); 447 448 long currentValueRealtime = getLongValue(0, "bt", "", 7); 449 long currentValueBatteryRealtime = getLongValue(0, "bt", "", 5); 450 451 // Total realtime increase should be 4000ms at least 452 assertTrue(currentValueRealtime >= startingValueRealtime + 4000); 453 // But not too much more 454 assertTrue(currentValueRealtime < startingValueRealtime + 6000); 455 // Battery on realtime should be more than 2000 but less than 4000 456 assertTrue(currentValueBatteryRealtime >= startingValueBatteryRealtime + 2000); 457 assertTrue(currentValueBatteryRealtime < startingValueBatteryRealtime + 4000); 458 } 459 460 /** 461 * Tests the total duration reported for jobs run on the job scheduler. 462 */ 463 public void testJobDuration() throws Exception { 464 batteryOnScreenOff(); 465 466 installPackage(DEVICE_SIDE_TEST_APK, true); 467 allowImmediateSyncs(); 468 469 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsJobDurationTests", 470 "testJobDuration"); 471 472 // Should be approximately 15000 ms (3 x 5000 ms). Use 0.8x and 2x as the lower and upper 473 // bounds to account for possible errors due to thread scheduling and cpu load. 474 assertValueRange("jb", DEVICE_SIDE_JOB_COMPONENT, 5, (long) (15000 * 0.8), 15000 * 2); 475 batteryOffScreenOn(); 476 } 477 478 /** 479 * Tests the total duration and # of syncs reported for sync activities. 480 */ 481 public void testSyncs() throws Exception { 482 batteryOnScreenOff(); 483 484 installPackage(DEVICE_SIDE_TEST_APK, true); 485 allowImmediateSyncs(); 486 487 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsSyncTest", "testRunSyncs"); 488 489 // First, check the count, which should be 10. 490 // (It could be 11, if the initial sync actually happened before getting cancelled.) 491 assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 10L, 11L); 492 493 // Should be approximately, but at least 10 seconds. Use 2x as the upper 494 // bounds to account for possible errors due to thread scheduling and cpu load. 495 assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 5, 10000, 10000 * 2); 496 } 497 498 private int getUid() throws Exception { 499 String uidLine = getDevice().executeShellCommand("cmd package list packages -U " 500 + DEVICE_SIDE_TEST_PACKAGE); 501 String[] uidLineParts = uidLine.split(":"); 502 // 3rd entry is package uid 503 assertTrue(uidLineParts.length > 2); 504 int uid = Integer.parseInt(uidLineParts[2].trim()); 505 assertTrue(uid > 10000); 506 return uid; 507 } 508 assertApproximateTimeInState(int index, long duration)509 private void assertApproximateTimeInState(int index, long duration) throws Exception { 510 assertValueRange("st", "", index, (long) (0.7 * duration), 2 * duration); 511 } 512 513 /** 514 * Verifies that the recorded time for the specified tag and name in the test package 515 * is within the specified range. 516 */ assertValueRange(String tag, String optionalAfterTag, int index, long min, long max)517 private void assertValueRange(String tag, String optionalAfterTag, 518 int index, long min, long max) throws Exception { 519 int uid = getUid(); 520 long value = getLongValue(uid, tag, optionalAfterTag, index); 521 assertTrue("Value " + value + " is less than min " + min, value >= min); 522 assertTrue("Value " + value + " is greater than max " + max, value <= max); 523 } 524 525 /** 526 * Returns a particular long value from a line matched by uid, tag and the optionalAfterTag. 527 */ getLongValue(int uid, String tag, String optionalAfterTag, int index)528 private long getLongValue(int uid, String tag, String optionalAfterTag, int index) 529 throws Exception { 530 String dumpsys = getDevice().executeShellCommand("dumpsys batterystats --checkin"); 531 String[] lines = dumpsys.split("\n"); 532 long value = 0; 533 if (optionalAfterTag == null) { 534 optionalAfterTag = ""; 535 } 536 for (int i = lines.length - 1; i >= 0; i--) { 537 String line = lines[i]; 538 if (line.contains(uid + ",l," + tag + "," + optionalAfterTag) 539 || (!optionalAfterTag.equals("") && 540 line.contains(uid + ",l," + tag + ",\"" + optionalAfterTag))) { 541 String[] wlParts = line.split(","); 542 value = Long.parseLong(wlParts[index]); 543 } 544 } 545 return value; 546 } 547 548 /** 549 * Runs a (background) service to perform the given action, and waits for 550 * the device to report that the action has finished (via a logcat message) before returning. 551 * @param actionValue one of the constants in BatteryStatsBgVsFgActions indicating the desired 552 * action to perform. 553 * @param maxTimeMs max time to wait (in ms) for action to report that it has completed. 554 * @return A string, representing a random integer, assigned to this particular request for the 555 * device to perform the given action. This value can be used to receive 556 * communications via logcat from the device about this action. 557 */ executeBackground(String actionValue, int maxTimeMs)558 private String executeBackground(String actionValue, int maxTimeMs) throws Exception { 559 String requestCode = executeBackground(actionValue); 560 String searchString = getCompletedActionString(actionValue, requestCode); 561 checkLogcatForText(BG_VS_FG_TAG, searchString, maxTimeMs); 562 return requestCode; 563 } 564 565 /** 566 * Runs a (background) service to perform the given action. 567 * @param actionValue one of the constants in BatteryStatsBgVsFgActions indicating the desired 568 * action to perform. 569 * @return A string, representing a random integer, assigned to this particular request for the 570 * device to perform the given action. This value can be used to receive 571 * communications via logcat from the device about this action. 572 */ executeBackground(String actionValue)573 private String executeBackground(String actionValue) throws Exception { 574 allowBackgroundServices(); 575 String requestCode = Integer.toString(new Random().nextInt()); 576 getDevice().executeShellCommand(String.format( 577 "am startservice -n '%s' -e %s %s -e %s %s", 578 DEVICE_SIDE_BG_SERVICE_COMPONENT, 579 KEY_ACTION, actionValue, 580 KEY_REQUEST_CODE, requestCode)); 581 return requestCode; 582 } 583 584 /** Required to successfully start a background service from adb in O. */ allowBackgroundServices()585 private void allowBackgroundServices() throws Exception { 586 getDevice().executeShellCommand(String.format( 587 "cmd deviceidle tempwhitelist %s", DEVICE_SIDE_TEST_PACKAGE)); 588 } 589 590 /** Make the test-app standby-active so it can run syncs and jobs immediately. */ allowImmediateSyncs()591 protected void allowImmediateSyncs() throws Exception { 592 getDevice().executeShellCommand("am set-standby-bucket " 593 + DEVICE_SIDE_TEST_PACKAGE + " active"); 594 } 595 596 /** 597 * Runs an activity (in the foreground) to perform the given action, and waits 598 * for the device to report that the action has finished (via a logcat message) before returning. 599 * @param actionValue one of the constants in BatteryStatsBgVsFgActions indicating the desired 600 * action to perform. 601 * @param maxTimeMs max time to wait (in ms) for action to report that it has completed. 602 * @return A string, representing a random integer, assigned to this particular request for the 603 * device to perform the given action. This value can be used to receive 604 * communications via logcat from the device about this action. 605 */ executeForeground(String actionValue, int maxTimeMs)606 private String executeForeground(String actionValue, int maxTimeMs) throws Exception { 607 String requestCode = executeForeground(actionValue); 608 String searchString = getCompletedActionString(actionValue, requestCode); 609 checkLogcatForText(BG_VS_FG_TAG, searchString, maxTimeMs); 610 return requestCode; 611 } 612 613 /** 614 * Runs an activity (in the foreground) to perform the given action. 615 * @param actionValue one of the constants in BatteryStatsBgVsFgActions indicating the desired 616 * action to perform. 617 * @return A string, representing a random integer, assigned to this particular request for the 618 * device to perform the given action. This value can be used to receive 619 * communications via logcat from the device about this action. 620 */ executeForeground(String actionValue)621 private String executeForeground(String actionValue) throws Exception { 622 String requestCode = Integer.toString(new Random().nextInt()); 623 getDevice().executeShellCommand(String.format( 624 "am start -n '%s' -e %s %s -e %s %s", 625 DEVICE_SIDE_FG_ACTIVITY_COMPONENT, 626 KEY_ACTION, actionValue, 627 KEY_REQUEST_CODE, requestCode)); 628 return requestCode; 629 } 630 631 /** 632 * The string that will be printed in the logcat when the action completes. This needs to be 633 * identical to {@link com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions#tellHostActionFinished}. 634 */ getCompletedActionString(String actionValue, String requestCode)635 private String getCompletedActionString(String actionValue, String requestCode) { 636 return String.format("Completed performing %s for request %s", actionValue, requestCode); 637 } 638 639 /** Determine if device has no battery and is not expected to have proper batterystats. */ noBattery()640 private boolean noBattery() throws Exception { 641 final String batteryinfo = getDevice().executeShellCommand("dumpsys battery"); 642 boolean hasBattery = batteryinfo.contains("present: true"); 643 if (!hasBattery) { 644 LogUtil.CLog.w("Device does not have a battery"); 645 } 646 return !hasBattery; 647 } 648 649 /** 650 * Determines if the device has the given feature. 651 * Prints a warning if its value differs from requiredAnswer. 652 */ hasFeature(String featureName, boolean requiredAnswer)653 private boolean hasFeature(String featureName, boolean requiredAnswer) throws Exception { 654 final String features = getDevice().executeShellCommand("pm list features"); 655 boolean hasIt = features.contains(featureName); 656 if (hasIt != requiredAnswer) { 657 LogUtil.CLog.w("Device does " + (requiredAnswer ? "not " : "") + "have feature " 658 + featureName); 659 } 660 return hasIt; 661 } 662 } 663