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 android.jobscheduler.cts; 18 19 import static android.app.job.JobInfo.NETWORK_TYPE_ANY; 20 import static android.app.job.JobInfo.NETWORK_TYPE_NONE; 21 import static android.jobscheduler.cts.TestAppInterface.TEST_APP_PACKAGE; 22 23 import static com.android.compatibility.common.util.TestUtils.waitUntil; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertFalse; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assume.assumeFalse; 29 import static org.junit.Assume.assumeTrue; 30 31 import android.app.AppOpsManager; 32 import android.app.job.JobInfo; 33 import android.app.job.JobParameters; 34 import android.content.Context; 35 import android.content.pm.PackageManager; 36 import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver; 37 import android.os.PowerManager; 38 import android.os.SystemClock; 39 import android.os.Temperature; 40 import android.os.UserHandle; 41 import android.platform.test.annotations.RequiresDevice; 42 import android.provider.DeviceConfig; 43 import android.provider.Settings; 44 import android.util.Log; 45 46 import androidx.test.InstrumentationRegistry; 47 import androidx.test.filters.LargeTest; 48 import androidx.test.runner.AndroidJUnit4; 49 import androidx.test.uiautomator.UiDevice; 50 51 import com.android.compatibility.common.util.AppOpsUtils; 52 import com.android.compatibility.common.util.AppStandbyUtils; 53 import com.android.compatibility.common.util.BatteryUtils; 54 import com.android.compatibility.common.util.DeviceConfigStateHelper; 55 import com.android.compatibility.common.util.ThermalUtils; 56 57 import org.junit.After; 58 import org.junit.Before; 59 import org.junit.Test; 60 import org.junit.runner.RunWith; 61 62 import java.util.Map; 63 64 /** 65 * Tests related to job throttling -- device idle, app standby and battery saver. 66 */ 67 @RunWith(AndroidJUnit4.class) 68 @LargeTest 69 public class JobThrottlingTest { 70 private static final String TAG = JobThrottlingTest.class.getSimpleName(); 71 private static final long BACKGROUND_JOBS_EXPECTED_DELAY = 3_000; 72 private static final long POLL_INTERVAL = 500; 73 private static final long DEFAULT_WAIT_TIMEOUT = 5000; 74 private static final long SHELL_TIMEOUT = 3_000; 75 // TODO: mark Settings.System.SCREEN_OFF_TIMEOUT as @TestApi 76 private static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout"; 77 78 enum Bucket { 79 ACTIVE, 80 WORKING_SET, 81 FREQUENT, 82 RARE, 83 RESTRICTED, 84 NEVER 85 } 86 87 private Context mContext; 88 private UiDevice mUiDevice; 89 private NetworkingHelper mNetworkingHelper; 90 private PowerManager mPowerManager; 91 private int mTestJobId; 92 private int mTestPackageUid; 93 private boolean mDeviceIdleEnabled; 94 private boolean mDeviceLightIdleEnabled; 95 private boolean mAppStandbyEnabled; 96 private String mInitialActivityManagerConstants; 97 private String mInitialDisplayTimeout; 98 private String mInitialBatteryStatsConstants; 99 private boolean mAutomotiveDevice; 100 private boolean mLeanbackOnly; 101 102 private TestAppInterface mTestAppInterface; 103 private DeviceConfigStateHelper mDeviceConfigStateHelper; 104 private DeviceConfigStateHelper mActivityManagerDeviceConfigStateHelper; 105 private DeviceConfigStateHelper mTareDeviceConfigStateHelper; 106 isDeviceIdleEnabled(UiDevice uiDevice)107 private static boolean isDeviceIdleEnabled(UiDevice uiDevice) throws Exception { 108 final String output = uiDevice.executeShellCommand("cmd deviceidle enabled deep").trim(); 109 return Integer.parseInt(output) != 0; 110 } 111 isDeviceLightIdleEnabled(UiDevice uiDevice)112 private static boolean isDeviceLightIdleEnabled(UiDevice uiDevice) throws Exception { 113 final String output = uiDevice.executeShellCommand("cmd deviceidle enabled light").trim(); 114 return Integer.parseInt(output) != 0; 115 } 116 117 @Before setUp()118 public void setUp() throws Exception { 119 mContext = InstrumentationRegistry.getTargetContext(); 120 mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 121 mNetworkingHelper = 122 new NetworkingHelper(InstrumentationRegistry.getInstrumentation(), mContext); 123 mPowerManager = mContext.getSystemService(PowerManager.class); 124 mTestPackageUid = mContext.getPackageManager().getPackageUid(TEST_APP_PACKAGE, 0); 125 mTestJobId = (int) (SystemClock.uptimeMillis() / 1000); 126 mTestAppInterface = new TestAppInterface(mContext, mTestJobId); 127 assertFalse("Test package already in temp whitelist", isTestAppTempWhitelisted()); 128 makeTestPackageIdle(); 129 mDeviceIdleEnabled = isDeviceIdleEnabled(mUiDevice); 130 mDeviceLightIdleEnabled = isDeviceLightIdleEnabled(mUiDevice); 131 if (mDeviceIdleEnabled || mDeviceLightIdleEnabled) { 132 // Make sure the device isn't dozing since it will affect execution of regular jobs 133 toggleDozeState(false); 134 } 135 mAppStandbyEnabled = AppStandbyUtils.isAppStandbyEnabled(); 136 if (mAppStandbyEnabled) { 137 setTestPackageStandbyBucket(Bucket.ACTIVE); 138 } else { 139 Log.w(TAG, "App standby not enabled on test device"); 140 } 141 mInitialBatteryStatsConstants = Settings.Global.getString(mContext.getContentResolver(), 142 Settings.Global.BATTERY_STATS_CONSTANTS); 143 // Make sure ACTION_CHARGING is sent immediately. 144 Settings.Global.putString(mContext.getContentResolver(), 145 Settings.Global.BATTERY_STATS_CONSTANTS, "battery_charged_delay_ms=0"); 146 // Make sure test jobs can run regardless of bucket. 147 mDeviceConfigStateHelper = 148 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER); 149 mDeviceConfigStateHelper.set( 150 new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) 151 .setInt("min_ready_non_active_jobs_count", 0) 152 .setBoolean("fc_enable_flexibility", false).build()); 153 mActivityManagerDeviceConfigStateHelper = 154 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER); 155 mTareDeviceConfigStateHelper = new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_TARE); 156 toggleAutoRestrictedBucketOnBgRestricted(false); 157 // Make sure the screen doesn't turn off when the test turns it on. 158 mInitialDisplayTimeout = 159 Settings.System.getString(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT); 160 Settings.System.putString(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, "300000"); 161 162 mInitialActivityManagerConstants = Settings.Global.getString(mContext.getContentResolver(), 163 Settings.Global.ACTIVITY_MANAGER_CONSTANTS); 164 // Delete any activity manager constants overrides so that the default transition time 165 // of 60 seconds for UID active to UID idle is used. 166 Settings.Global.putString(mContext.getContentResolver(), 167 Settings.Global.ACTIVITY_MANAGER_CONSTANTS, null); 168 169 // In automotive device, always-on screen and endless battery charging are assumed. 170 mAutomotiveDevice = 171 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 172 // In leanback devices, it is assumed that there is no battery. 173 mLeanbackOnly = 174 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY); 175 if (mAutomotiveDevice || mLeanbackOnly) { 176 setScreenState(true); 177 // TODO(b/159176758): make sure that initial power supply is on. 178 setChargingState(true); 179 } 180 181 // Kill as many things in the background as possible so we avoid LMK interfering with the 182 // test. 183 mUiDevice.executeShellCommand("am kill-all"); 184 } 185 186 @Test testAllowWhileIdleJobInTempwhitelist()187 public void testAllowWhileIdleJobInTempwhitelist() throws Exception { 188 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 189 190 toggleDozeState(true); 191 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 192 sendScheduleJobBroadcast(true); 193 assertFalse("Job started without being tempwhitelisted", 194 mTestAppInterface.awaitJobStart(5_000)); 195 tempWhitelistTestApp(5_000); 196 assertTrue("Job with allow_while_idle flag did not start when the app was tempwhitelisted", 197 mTestAppInterface.awaitJobStart(5_000)); 198 } 199 200 @Test testForegroundJobsStartImmediately()201 public void testForegroundJobsStartImmediately() throws Exception { 202 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 203 204 sendScheduleJobBroadcast(false); 205 runJob(); 206 assertTrue("Job did not start after scheduling", 207 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 208 toggleDozeState(true); 209 assertTrue("Job did not stop on entering doze", 210 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 211 Thread.sleep(TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF); 212 // The adb command will force idle even with the screen on, so we need to turn Doze off 213 // explicitly. 214 toggleDozeState(false); 215 // Turn the screen on to ensure the test app ends up in TOP. 216 setScreenState(true); 217 mTestAppInterface.startAndKeepTestActivity(); 218 assertTrue("Job for foreground app did not start immediately when device exited doze", 219 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 220 } 221 222 @Test testBackgroundJobsDelayed()223 public void testBackgroundJobsDelayed() throws Exception { 224 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 225 226 sendScheduleJobBroadcast(false); 227 runJob(); 228 assertTrue("Job did not start after scheduling", 229 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 230 toggleDozeState(true); 231 assertTrue("Job did not stop on entering doze", 232 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 233 Thread.sleep(TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF); 234 toggleDozeState(false); 235 assertFalse("Job for background app started immediately when device exited doze", 236 mTestAppInterface.awaitJobStart(2000)); 237 Thread.sleep(BACKGROUND_JOBS_EXPECTED_DELAY - 2000); 238 assertTrue("Job for background app did not start after the expected delay of " 239 + BACKGROUND_JOBS_EXPECTED_DELAY + "ms", 240 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 241 } 242 243 @Test testJobStoppedWhenRestricted()244 public void testJobStoppedWhenRestricted() throws Exception { 245 sendScheduleJobBroadcast(false); 246 runJob(); 247 assertTrue("Job did not start after scheduling", 248 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 249 toggleAutoRestrictedBucketOnBgRestricted(true); 250 setTestPackageRestricted(true); 251 assertFalse("Job stopped after test app was restricted with auto-restricted-bucket on", 252 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 253 toggleAutoRestrictedBucketOnBgRestricted(false); 254 assertTrue("Job did not stop after test app was restricted", 255 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 256 assertEquals(JobParameters.STOP_REASON_BACKGROUND_RESTRICTION, 257 mTestAppInterface.getLastParams().getStopReason()); 258 } 259 260 @Test testRestrictedJobStartedWhenUnrestricted()261 public void testRestrictedJobStartedWhenUnrestricted() throws Exception { 262 setTestPackageRestricted(true); 263 sendScheduleJobBroadcast(false); 264 assertFalse("Job started for restricted app", 265 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 266 setTestPackageRestricted(false); 267 assertTrue("Job did not start when app was unrestricted", 268 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 269 } 270 271 @Test testRestrictedJobAllowedWhenUidActive()272 public void testRestrictedJobAllowedWhenUidActive() throws Exception { 273 setTestPackageRestricted(true); 274 sendScheduleJobBroadcast(false); 275 assertFalse("Job started for restricted app", 276 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 277 // Turn the screen on to ensure the app gets into the TOP state. 278 setScreenState(true); 279 mTestAppInterface.startAndKeepTestActivity(true); 280 assertTrue("Job did not start when app had an activity", 281 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 282 283 mTestAppInterface.closeActivity(); 284 // Don't put full minute as the timeout to give some leeway with test timing/processing. 285 assertFalse("Job stopped within grace period after activity closed", 286 mTestAppInterface.awaitJobStop(55_000L)); 287 assertTrue("Job did not stop after grace period ended", 288 mTestAppInterface.awaitJobStop(15_000L)); 289 assertEquals(JobParameters.STOP_REASON_BACKGROUND_RESTRICTION, 290 mTestAppInterface.getLastParams().getStopReason()); 291 } 292 293 @Test testRestrictedJobAllowedWhenAutoRestrictedBucketFeatureOn()294 public void testRestrictedJobAllowedWhenAutoRestrictedBucketFeatureOn() throws Exception { 295 setTestPackageRestricted(true); 296 sendScheduleJobBroadcast(false); 297 assertFalse("Job started for restricted app", 298 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 299 toggleAutoRestrictedBucketOnBgRestricted(true); 300 assertTrue("Job did not start after scheduling", 301 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 302 } 303 304 @Test testEJStoppedWhenRestricted()305 public void testEJStoppedWhenRestricted() throws Exception { 306 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 307 runJob(); 308 assertTrue("Job did not start after scheduling", 309 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 310 toggleAutoRestrictedBucketOnBgRestricted(true); 311 setTestPackageRestricted(true); 312 assertFalse("Job stopped after test app was restricted with auto-restricted-bucket on", 313 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 314 toggleAutoRestrictedBucketOnBgRestricted(false); 315 assertTrue("Job did not stop after test app was restricted", 316 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 317 assertEquals(JobParameters.STOP_REASON_BACKGROUND_RESTRICTION, 318 mTestAppInterface.getLastParams().getStopReason()); 319 } 320 321 @Test testRestrictedEJStartedWhenUnrestricted()322 public void testRestrictedEJStartedWhenUnrestricted() throws Exception { 323 setTestPackageRestricted(true); 324 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 325 assertFalse("Job started for restricted app", 326 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 327 setTestPackageRestricted(false); 328 assertTrue("Job did not start when app was unrestricted", 329 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 330 } 331 332 @Test testRestrictedEJAllowedWhenUidActive()333 public void testRestrictedEJAllowedWhenUidActive() throws Exception { 334 setTestPackageRestricted(true); 335 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 336 assertFalse("Job started for restricted app", 337 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 338 // Turn the screen on to ensure the app gets into the TOP state. 339 setScreenState(true); 340 mTestAppInterface.startAndKeepTestActivity(true); 341 assertTrue("Job did not start when app had an activity", 342 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 343 344 mTestAppInterface.closeActivity(); 345 // Don't put full minute as the timeout to give some leeway with test timing/processing. 346 assertFalse("Job stopped within grace period after activity closed", 347 mTestAppInterface.awaitJobStop(55_000L)); 348 assertTrue("Job did not stop after grace period ended", 349 mTestAppInterface.awaitJobStop(15_000L)); 350 assertEquals(JobParameters.STOP_REASON_BACKGROUND_RESTRICTION, 351 mTestAppInterface.getLastParams().getStopReason()); 352 } 353 354 @Test testRestrictedEJAllowedWhenAutoRestrictedBucketFeatureOn()355 public void testRestrictedEJAllowedWhenAutoRestrictedBucketFeatureOn() throws Exception { 356 setTestPackageRestricted(true); 357 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 358 assertFalse("Job started for restricted app", 359 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 360 361 toggleAutoRestrictedBucketOnBgRestricted(true); 362 assertTrue("Job did not start when app was background unrestricted", 363 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 364 } 365 366 @Test testBackgroundRegJobsThermal()367 public void testBackgroundRegJobsThermal() throws Exception { 368 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 369 runJob(); 370 assertTrue("Job did not start after scheduling", 371 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 372 373 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_LIGHT); 374 assertFalse("Job stopped below thermal throttling threshold", 375 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 376 377 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_SEVERE); 378 assertTrue("Job did not stop on thermal throttling", 379 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 380 final long jobStopTime = System.currentTimeMillis(); 381 382 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_CRITICAL); 383 runJob(); 384 assertFalse("Job started above thermal throttling threshold", 385 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 386 387 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_EMERGENCY); 388 runJob(); 389 assertFalse("Job started above thermal throttling threshold", 390 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 391 392 Thread.sleep(Math.max(0, TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF 393 - (System.currentTimeMillis() - jobStopTime))); 394 ThermalUtils.overrideThermalNotThrottling(); 395 runJob(); 396 assertTrue("Job did not start back from throttling", 397 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 398 } 399 400 @Test testBackgroundEJsThermal()401 public void testBackgroundEJsThermal() throws Exception { 402 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, true); 403 runJob(); 404 assertTrue("Job did not start after scheduling", 405 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 406 407 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_MODERATE); 408 assertFalse("Job stopped below thermal throttling threshold", 409 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 410 411 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_SEVERE); 412 assertTrue("Job did not stop on thermal throttling", 413 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 414 final long jobStopTime = System.currentTimeMillis(); 415 416 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_CRITICAL); 417 runJob(); 418 assertFalse("Job started above thermal throttling threshold", 419 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 420 421 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_EMERGENCY); 422 runJob(); 423 assertFalse("Job started above thermal throttling threshold", 424 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 425 426 Thread.sleep(Math.max(0, TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF 427 - (System.currentTimeMillis() - jobStopTime))); 428 ThermalUtils.overrideThermalNotThrottling(); 429 runJob(); 430 assertTrue("Job did not start back from throttling", 431 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 432 } 433 434 @Test testBackgroundUIJsThermal()435 public void testBackgroundUIJsThermal() throws Exception { 436 try (TestNotificationListener.NotificationHelper notificationHelper = 437 new TestNotificationListener.NotificationHelper( 438 mContext, TestAppInterface.TEST_APP_PACKAGE)) { 439 mTestAppInterface.postUiInitiatingNotification( 440 Map.of(TestJobSchedulerReceiver.EXTRA_AS_USER_INITIATED, true), 441 Map.of(TestJobSchedulerReceiver.EXTRA_REQUIRED_NETWORK_TYPE, NETWORK_TYPE_ANY)); 442 notificationHelper.clickNotification(); 443 444 assertTrue("Job did not start after scheduling", 445 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 446 447 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_MODERATE); 448 assertFalse("Job stopped below thermal throttling threshold", 449 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 450 451 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_SEVERE); 452 assertTrue("Job did not stop on thermal throttling", 453 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 454 final long jobStopTime = System.currentTimeMillis(); 455 456 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_CRITICAL); 457 runJob(); 458 assertFalse("Job started above thermal throttling threshold", 459 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 460 461 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_EMERGENCY); 462 runJob(); 463 assertFalse("Job started above thermal throttling threshold", 464 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 465 466 Thread.sleep(Math.max(0, TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF 467 - (System.currentTimeMillis() - jobStopTime))); 468 ThermalUtils.overrideThermalNotThrottling(); 469 runJob(); 470 assertTrue("Job did not start back from throttling", 471 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 472 } 473 } 474 475 @Test testForegroundJobsThermal()476 public void testForegroundJobsThermal() throws Exception { 477 // Turn the screen on to ensure the app gets into the TOP state. 478 setScreenState(true); 479 mTestAppInterface.startAndKeepTestActivity(true); 480 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 481 runJob(); 482 assertTrue("Job did not start after scheduling", 483 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 484 485 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_MODERATE); 486 assertFalse("Job stopped below thermal throttling threshold", 487 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 488 489 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_SEVERE); 490 assertFalse("Job stopped despite being TOP app", 491 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 492 493 ThermalUtils.overrideThermalStatus(Temperature.THROTTLING_CRITICAL); 494 assertFalse("Job stopped despite being TOP app", 495 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 496 } 497 498 /** Tests that apps in the RESTRICTED bucket still get their one parole session per day. */ 499 @Test testJobsInRestrictedBucket_ParoleSession()500 public void testJobsInRestrictedBucket_ParoleSession() throws Exception { 501 assumeTrue("app standby not enabled", mAppStandbyEnabled); 502 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 503 504 // This test is designed for the old quota system. 505 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 506 507 // Disable coalescing 508 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 509 510 setScreenState(true); 511 512 setChargingState(false); 513 setTestPackageStandbyBucket(Bucket.RESTRICTED); 514 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 515 sendScheduleJobBroadcast(false); 516 runJob(); 517 assertTrue("Parole job didn't start in RESTRICTED bucket", 518 mTestAppInterface.awaitJobStart(3_000)); 519 520 sendScheduleJobBroadcast(false); 521 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 522 } 523 524 /** 525 * Tests that apps in the RESTRICTED bucket have their parole sessions properly counted even 526 * when charging (but not idle). 527 */ 528 @Test testJobsInRestrictedBucket_CorrectParoleWhileCharging()529 public void testJobsInRestrictedBucket_CorrectParoleWhileCharging() throws Exception { 530 assumeTrue("app standby not enabled", mAppStandbyEnabled); 531 assumeFalse("not testable in automotive device", mAutomotiveDevice); 532 assumeFalse("not testable in leanback device", mLeanbackOnly); 533 534 // This test is designed for the old quota system. 535 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 536 537 // Disable coalescing 538 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 539 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "1"); 540 541 setScreenState(true); 542 setChargingState(true); 543 BatteryUtils.runDumpsysBatterySetLevel(100); 544 545 setTestPackageStandbyBucket(Bucket.RESTRICTED); 546 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 547 sendScheduleJobBroadcast(false); 548 runJob(); 549 assertTrue("Parole job didn't start in RESTRICTED bucket", 550 mTestAppInterface.awaitJobStart(3_000)); 551 552 sendScheduleJobBroadcast(false); 553 assertFalse("New job started in RESTRICTED bucket after parole used", 554 mTestAppInterface.awaitJobStart(3_000)); 555 } 556 557 /** 558 * Tests that apps in the RESTRICTED bucket that have used their one parole session per day 559 * don't get to run again until the device is charging + idle. 560 */ 561 @Test testJobsInRestrictedBucket_DeferredUntilFreeResources()562 public void testJobsInRestrictedBucket_DeferredUntilFreeResources() throws Exception { 563 assumeTrue("app standby not enabled", mAppStandbyEnabled); 564 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 565 566 // This test is designed for the old quota system. 567 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 568 569 // Disable coalescing 570 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 571 572 setScreenState(true); 573 574 setChargingState(false); 575 setTestPackageStandbyBucket(Bucket.RESTRICTED); 576 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 577 sendScheduleJobBroadcast(false); 578 runJob(); 579 assertTrue("Parole job didn't start in RESTRICTED bucket", 580 mTestAppInterface.awaitJobStart(3_000)); 581 582 sendScheduleJobBroadcast(false); 583 assertFalse("New job started in RESTRICTED bucket after parole used", 584 mTestAppInterface.awaitJobStart(3_000)); 585 586 setChargingState(true); 587 BatteryUtils.runDumpsysBatterySetLevel(100); 588 assertFalse("New job started in RESTRICTED bucket after parole when charging but not idle", 589 mTestAppInterface.awaitJobStart(3_000)); 590 591 setScreenState(false); 592 triggerJobIdle(); 593 assertTrue("Job didn't start in RESTRICTED bucket when charging + idle", 594 mTestAppInterface.awaitJobStart(3_000)); 595 596 // Make sure job can be stopped and started again when charging + idle 597 sendScheduleJobBroadcast(false); 598 runJob(); 599 assertTrue("Job didn't restart in RESTRICTED bucket when charging + idle", 600 mTestAppInterface.awaitJobStart(3_000)); 601 } 602 603 @Test testJobsInRestrictedBucket_NoRequiredNetwork()604 public void testJobsInRestrictedBucket_NoRequiredNetwork() throws Exception { 605 assumeTrue("app standby not enabled", mAppStandbyEnabled); 606 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 607 assumeFalse("not testable, since ethernet is connected", hasEthernetConnection()); 608 609 // This test is designed for the old quota system. 610 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 611 612 // Disable coalescing and the parole session 613 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 614 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0"); 615 616 mNetworkingHelper.setAllNetworksEnabled(false); 617 setScreenState(true); 618 619 setChargingState(false); 620 setTestPackageStandbyBucket(Bucket.RESTRICTED); 621 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 622 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 623 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 624 625 // Slowly add back required bucket constraints. 626 627 // Battery charging and high. 628 setChargingState(true); 629 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 630 BatteryUtils.runDumpsysBatterySetLevel(100); 631 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 632 633 // Device is idle. 634 setScreenState(false); 635 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 636 triggerJobIdle(); 637 assertTrue("New job didn't start in RESTRICTED bucket", 638 mTestAppInterface.awaitJobStart(3_000)); 639 } 640 641 @RequiresDevice // Emulators don't always have access to wifi/network 642 @Test testJobsInRestrictedBucket_WithRequiredNetwork()643 public void testJobsInRestrictedBucket_WithRequiredNetwork() throws Exception { 644 assumeTrue("app standby not enabled", mAppStandbyEnabled); 645 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 646 assumeFalse("not testable, since ethernet is connected", hasEthernetConnection()); 647 assumeTrue(mNetworkingHelper.hasWifiFeature()); 648 mNetworkingHelper.ensureSavedWifiNetwork(); 649 650 // This test is designed for the old quota system. 651 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 652 653 // Disable coalescing and the parole session 654 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 655 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0"); 656 657 mNetworkingHelper.setAllNetworksEnabled(false); 658 setScreenState(true); 659 660 setChargingState(false); 661 setTestPackageStandbyBucket(Bucket.RESTRICTED); 662 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 663 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_ANY, false); 664 runJob(); 665 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 666 667 // Slowly add back required bucket constraints. 668 669 // Battery charging and high. 670 setChargingState(true); 671 runJob(); 672 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 673 BatteryUtils.runDumpsysBatterySetLevel(100); 674 runJob(); 675 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 676 677 // Device is idle. 678 setScreenState(false); 679 runJob(); 680 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 681 triggerJobIdle(); 682 runJob(); 683 assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000)); 684 685 // Add network 686 mNetworkingHelper.setAllNetworksEnabled(true); 687 mNetworkingHelper.setWifiMeteredState(false); 688 runJob(); 689 assertTrue("New job didn't start in RESTRICTED bucket", 690 mTestAppInterface.awaitJobStart(5_000)); 691 } 692 693 @Test testJobsInNeverApp()694 public void testJobsInNeverApp() throws Exception { 695 assumeTrue("app standby not enabled", mAppStandbyEnabled); 696 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 697 698 // This test is designed for the old quota system. 699 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 700 701 setChargingState(false); 702 setTestPackageStandbyBucket(Bucket.NEVER); 703 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 704 sendScheduleJobBroadcast(false); 705 assertFalse("New job started in NEVER bucket", mTestAppInterface.awaitJobStart(3_000)); 706 } 707 708 @Test testUidActiveBypassesStandby()709 public void testUidActiveBypassesStandby() throws Exception { 710 assumeTrue("app standby not enabled", mAppStandbyEnabled); 711 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 712 713 // This test is designed for the old quota system. 714 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 715 716 setChargingState(false); 717 setTestPackageStandbyBucket(Bucket.NEVER); 718 tempWhitelistTestApp(6_000); 719 Thread.sleep(DEFAULT_WAIT_TIMEOUT); 720 sendScheduleJobBroadcast(false); 721 assertTrue("New job in uid-active app failed to start in NEVER standby", 722 mTestAppInterface.awaitJobStart(4_000)); 723 } 724 725 @Test testBatterySaverOff()726 public void testBatterySaverOff() throws Exception { 727 BatteryUtils.assumeBatterySaverFeature(); 728 729 setChargingState(false); 730 BatteryUtils.enableBatterySaver(false); 731 sendScheduleJobBroadcast(false); 732 assertTrue("New job failed to start with battery saver OFF", 733 mTestAppInterface.awaitJobStart(3_000)); 734 } 735 736 @Test testBatterySaverOn()737 public void testBatterySaverOn() throws Exception { 738 BatteryUtils.assumeBatterySaverFeature(); 739 740 setChargingState(false); 741 BatteryUtils.enableBatterySaver(true); 742 sendScheduleJobBroadcast(false); 743 assertFalse("New job started with battery saver ON", 744 mTestAppInterface.awaitJobStart(3_000)); 745 } 746 747 @Test testUidActiveBypassesBatterySaverOn()748 public void testUidActiveBypassesBatterySaverOn() throws Exception { 749 BatteryUtils.assumeBatterySaverFeature(); 750 751 setChargingState(false); 752 BatteryUtils.enableBatterySaver(true); 753 tempWhitelistTestApp(6_000); 754 sendScheduleJobBroadcast(false); 755 assertTrue("New job in uid-active app failed to start with battery saver ON", 756 mTestAppInterface.awaitJobStart(3_000)); 757 } 758 759 @Test testBatterySaverOnThenUidActive()760 public void testBatterySaverOnThenUidActive() throws Exception { 761 BatteryUtils.assumeBatterySaverFeature(); 762 763 // Enable battery saver, and schedule a job. It shouldn't run. 764 setChargingState(false); 765 BatteryUtils.enableBatterySaver(true); 766 sendScheduleJobBroadcast(false); 767 assertFalse("New job started with battery saver ON", 768 mTestAppInterface.awaitJobStart(3_000)); 769 770 // Then make the UID active. Now the job should run. 771 tempWhitelistTestApp(120_000); 772 assertTrue("New job in uid-active app failed to start with battery saver OFF", 773 mTestAppInterface.awaitJobStart(120_000)); 774 } 775 776 @Test testExpeditedJobBypassesBatterySaverOn()777 public void testExpeditedJobBypassesBatterySaverOn() throws Exception { 778 BatteryUtils.assumeBatterySaverFeature(); 779 780 setChargingState(false); 781 BatteryUtils.enableBatterySaver(true); 782 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 783 assertTrue("New expedited job failed to start with battery saver ON", 784 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 785 } 786 787 @Test testExpeditedJobBypassesBatterySaver_toggling()788 public void testExpeditedJobBypassesBatterySaver_toggling() throws Exception { 789 BatteryUtils.assumeBatterySaverFeature(); 790 791 setChargingState(false); 792 BatteryUtils.enableBatterySaver(false); 793 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 794 assertTrue("New expedited job failed to start with battery saver ON", 795 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 796 BatteryUtils.enableBatterySaver(true); 797 assertFalse("Job stopped when battery saver turned on", 798 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 799 } 800 801 @Test testExpeditedJobBypassesDeviceIdle()802 public void testExpeditedJobBypassesDeviceIdle() throws Exception { 803 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 804 805 toggleDozeState(true); 806 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 807 runJob(); 808 assertTrue("Job did not start after scheduling", 809 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 810 } 811 812 @Test testExpeditedJobBypassesDeviceIdle_toggling()813 public void testExpeditedJobBypassesDeviceIdle_toggling() throws Exception { 814 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 815 816 toggleDozeState(false); 817 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 818 runJob(); 819 assertTrue("Job did not start after scheduling", 820 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 821 toggleDozeState(true); 822 assertFalse("Job stopped when device enabled turned on", 823 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 824 } 825 826 @Test testExpeditedJobDeferredAfterTimeoutInDoze()827 public void testExpeditedJobDeferredAfterTimeoutInDoze() throws Exception { 828 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 829 // Intentionally set a value below 1 minute to ensure the range checks work. 830 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", Long.toString(30_000L)); 831 832 toggleDozeState(true); 833 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 834 runJob(); 835 assertTrue("Job did not start after scheduling", 836 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 837 // Don't put full minute as the timeout to give some leeway with test timing/processing. 838 assertFalse("Job stopped before min runtime limit", 839 mTestAppInterface.awaitJobStop(55_000L)); 840 assertTrue("Job did not stop after timeout", mTestAppInterface.awaitJobStop(15_000L)); 841 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 842 mTestAppInterface.getLastParams().getStopReason()); 843 // Should be rescheduled. 844 assertJobNotReady(); 845 assertJobWaiting(); 846 Thread.sleep(TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF); 847 runJob(); 848 assertFalse("Job started after timing out in Doze", 849 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 850 851 // Should start when Doze is turned off. 852 toggleDozeState(false); 853 assertTrue("Job did not start after Doze turned off", 854 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 855 } 856 857 @Test testExpeditedJobDeferredAfterTimeoutInBatterySaver()858 public void testExpeditedJobDeferredAfterTimeoutInBatterySaver() throws Exception { 859 BatteryUtils.assumeBatterySaverFeature(); 860 861 // Intentionally set a value below 1 minute to ensure the range checks work. 862 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", Long.toString(47_000L)); 863 864 setChargingState(false); 865 BatteryUtils.enableBatterySaver(true); 866 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 867 runJob(); 868 assertTrue("Job did not start after scheduling", 869 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 870 // Don't put full minute as the timeout to give some leeway with test timing/processing. 871 assertFalse("Job stopped before min runtime limit", 872 mTestAppInterface.awaitJobStop(55_000L)); 873 assertTrue("Job did not stop after timeout", mTestAppInterface.awaitJobStop(15_000L)); 874 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 875 mTestAppInterface.getLastParams().getStopReason()); 876 // Should be rescheduled. 877 assertJobNotReady(); 878 assertJobWaiting(); 879 Thread.sleep(TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF); 880 runJob(); 881 assertFalse("Job started after timing out in battery saver", 882 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 883 884 // Should start when battery saver is turned off. 885 BatteryUtils.enableBatterySaver(false); 886 assertTrue("Job did not start after battery saver turned off", 887 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 888 } 889 890 @Test testExpeditedJobDeferredAfterTimeout_DozeAndBatterySaver()891 public void testExpeditedJobDeferredAfterTimeout_DozeAndBatterySaver() throws Exception { 892 BatteryUtils.assumeBatterySaverFeature(); 893 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 894 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", Long.toString(60_000L)); 895 896 setChargingState(false); 897 toggleDozeState(true); 898 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 899 runJob(); 900 assertTrue("Job did not start after scheduling", 901 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 902 // Don't put full minute as the timeout to give some leeway with test timing/processing. 903 assertFalse("Job stopped before min runtime limit", 904 mTestAppInterface.awaitJobStop(55_000L)); 905 assertTrue("Job did not stop after timeout", mTestAppInterface.awaitJobStop(15_000L)); 906 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 907 mTestAppInterface.getLastParams().getStopReason()); 908 // Should be rescheduled. 909 assertJobNotReady(); 910 assertJobWaiting(); 911 // Battery saver kicks in before Doze ends. Job shouldn't start while BS is on. 912 BatteryUtils.enableBatterySaver(true); 913 toggleDozeState(false); 914 Thread.sleep(TestJobSchedulerReceiver.JOB_INITIAL_BACKOFF); 915 runJob(); 916 assertFalse("Job started while power restrictions active after timing out", 917 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 918 919 // Should start when battery saver is turned off. 920 BatteryUtils.enableBatterySaver(false); 921 assertTrue("Job did not start after power restrictions turned off", 922 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 923 } 924 925 @Test testLongExpeditedJobStoppedByDoze()926 public void testLongExpeditedJobStoppedByDoze() throws Exception { 927 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 928 // Intentionally set a value below 1 minute to ensure the range checks work. 929 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", Long.toString(59_000L)); 930 931 toggleDozeState(false); 932 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 933 runJob(); 934 assertTrue("Job did not start after scheduling", 935 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 936 // Should get to run past min runtime. 937 assertFalse("Job stopped after min runtime", mTestAppInterface.awaitJobStop(90_000L)); 938 939 // Should stop when Doze is turned on. 940 toggleDozeState(true); 941 assertTrue("Job did not stop after Doze turned on", 942 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 943 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 944 mTestAppInterface.getLastParams().getStopReason()); 945 } 946 947 @Test testLongExpeditedJobStoppedByBatterySaver()948 public void testLongExpeditedJobStoppedByBatterySaver() throws Exception { 949 BatteryUtils.assumeBatterySaverFeature(); 950 951 // Intentionally set a value below 1 minute to ensure the range checks work. 952 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", Long.toString(0L)); 953 954 setChargingState(false); 955 BatteryUtils.enableBatterySaver(false); 956 mTestAppInterface.scheduleJob(false, JobInfo.NETWORK_TYPE_NONE, true); 957 runJob(); 958 assertTrue("Job did not start after scheduling", 959 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 960 // Should get to run past min runtime. 961 assertFalse("Job stopped after runtime", mTestAppInterface.awaitJobStop(90_000L)); 962 963 // Should stop when battery saver is turned on. 964 BatteryUtils.enableBatterySaver(true); 965 assertTrue("Job did not stop after battery saver turned on", 966 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 967 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 968 mTestAppInterface.getLastParams().getStopReason()); 969 } 970 971 @Test testUserInitiatedJobBypassesBatterySaverOn()972 public void testUserInitiatedJobBypassesBatterySaverOn() throws Exception { 973 BatteryUtils.assumeBatterySaverFeature(); 974 mNetworkingHelper.setAllNetworksEnabled(true); 975 976 try (TestNotificationListener.NotificationHelper notificationHelper = 977 new TestNotificationListener.NotificationHelper( 978 mContext, TestAppInterface.TEST_APP_PACKAGE)) { 979 setChargingState(false); 980 BatteryUtils.enableBatterySaver(true); 981 982 mTestAppInterface.postUiInitiatingNotification( 983 Map.of( 984 TestJobSchedulerReceiver.EXTRA_AS_USER_INITIATED, true 985 ), 986 Map.of(TestJobSchedulerReceiver.EXTRA_REQUIRED_NETWORK_TYPE, NETWORK_TYPE_ANY)); 987 notificationHelper.clickNotification(); 988 989 assertTrue("New user-initiated job failed to start with battery saver ON", 990 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 991 } 992 } 993 994 @Test testUserInitiatedJobBypassesBatterySaver_toggling()995 public void testUserInitiatedJobBypassesBatterySaver_toggling() throws Exception { 996 BatteryUtils.assumeBatterySaverFeature(); 997 mNetworkingHelper.setAllNetworksEnabled(true); 998 999 try (TestNotificationListener.NotificationHelper notificationHelper = 1000 new TestNotificationListener.NotificationHelper( 1001 mContext, TestAppInterface.TEST_APP_PACKAGE)) { 1002 setChargingState(false); 1003 BatteryUtils.enableBatterySaver(false); 1004 1005 mTestAppInterface.postUiInitiatingNotification( 1006 Map.of( 1007 TestJobSchedulerReceiver.EXTRA_AS_USER_INITIATED, true 1008 ), 1009 Map.of(TestJobSchedulerReceiver.EXTRA_REQUIRED_NETWORK_TYPE, NETWORK_TYPE_ANY)); 1010 notificationHelper.clickNotification(); 1011 1012 assertTrue("New user-initiated job failed to start with battery saver ON", 1013 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1014 1015 BatteryUtils.enableBatterySaver(true); 1016 assertFalse("Job stopped when battery saver turned on", 1017 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1018 } 1019 } 1020 1021 @Test testUserInitiatedJobBypassesDeviceIdle()1022 public void testUserInitiatedJobBypassesDeviceIdle() throws Exception { 1023 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 1024 mNetworkingHelper.setAllNetworksEnabled(true); 1025 1026 try (TestNotificationListener.NotificationHelper notificationHelper = 1027 new TestNotificationListener.NotificationHelper( 1028 mContext, TestAppInterface.TEST_APP_PACKAGE)) { 1029 toggleDozeState(true); 1030 1031 mTestAppInterface.postUiInitiatingNotification( 1032 Map.of( 1033 TestJobSchedulerReceiver.EXTRA_AS_USER_INITIATED, true 1034 ), 1035 Map.of(TestJobSchedulerReceiver.EXTRA_REQUIRED_NETWORK_TYPE, NETWORK_TYPE_ANY)); 1036 notificationHelper.clickNotification(); 1037 1038 assertTrue("Job did not start after scheduling", 1039 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1040 } 1041 } 1042 1043 @Test testUserInitiatedJobBypassesDeviceIdle_toggling()1044 public void testUserInitiatedJobBypassesDeviceIdle_toggling() throws Exception { 1045 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 1046 mNetworkingHelper.setAllNetworksEnabled(true); 1047 1048 try (TestNotificationListener.NotificationHelper notificationHelper = 1049 new TestNotificationListener.NotificationHelper( 1050 mContext, TestAppInterface.TEST_APP_PACKAGE)) { 1051 toggleDozeState(false); 1052 1053 mTestAppInterface.postUiInitiatingNotification( 1054 Map.of( 1055 TestJobSchedulerReceiver.EXTRA_AS_USER_INITIATED, true 1056 ), 1057 Map.of(TestJobSchedulerReceiver.EXTRA_REQUIRED_NETWORK_TYPE, NETWORK_TYPE_ANY)); 1058 notificationHelper.clickNotification(); 1059 1060 assertTrue("Job did not start after scheduling", 1061 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1062 1063 toggleDozeState(true); 1064 assertFalse("Job stopped when device enabled turned on", 1065 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1066 } 1067 } 1068 1069 @Test testRestrictingStopReason_RestrictedBucket_connectivity()1070 public void testRestrictingStopReason_RestrictedBucket_connectivity() throws Exception { 1071 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1072 // Tests cannot disable ethernet network. 1073 assumeFalse("not testable, since ethernet is connected", hasEthernetConnection()); 1074 1075 assumeTrue(BatteryUtils.hasBattery()); 1076 assumeTrue(mNetworkingHelper.hasWifiFeature()); 1077 mNetworkingHelper.ensureSavedWifiNetwork(); 1078 1079 // This test is designed for the old quota system. 1080 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 1081 1082 setTestPackageStandbyBucket(Bucket.RESTRICTED); 1083 1084 // Disable coalescing and the parole session 1085 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 1086 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0"); 1087 1088 // Satisfy all additional constraints. 1089 mNetworkingHelper.setAllNetworksEnabled(true); 1090 mNetworkingHelper.setWifiMeteredState(false); 1091 setChargingState(true); 1092 BatteryUtils.runDumpsysBatterySetLevel(100); 1093 setScreenState(false); 1094 triggerJobIdle(); 1095 1096 // Connectivity 1097 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_ANY, false); 1098 runJob(); 1099 assertTrue("New job didn't start in RESTRICTED bucket", 1100 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1101 mNetworkingHelper.setAllNetworksEnabled(false); 1102 assertTrue("New job didn't stop when connectivity dropped", 1103 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1104 assertEquals(JobParameters.STOP_REASON_CONSTRAINT_CONNECTIVITY, 1105 mTestAppInterface.getLastParams().getStopReason()); 1106 } 1107 1108 @Test testRestrictingStopReason_RestrictedBucket_idle()1109 public void testRestrictingStopReason_RestrictedBucket_idle() throws Exception { 1110 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1111 1112 // This test is designed for the old quota system. 1113 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 1114 1115 setTestPackageStandbyBucket(Bucket.RESTRICTED); 1116 1117 // Disable coalescing and the parole session 1118 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 1119 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0"); 1120 1121 // Satisfy all additional constraints. 1122 setChargingState(true); 1123 BatteryUtils.runDumpsysBatterySetLevel(100); 1124 setScreenState(false); 1125 triggerJobIdle(); 1126 1127 // Idle 1128 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 1129 runJob(); 1130 assertTrue("New job didn't start in RESTRICTED bucket", 1131 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1132 setScreenState(true); 1133 assertTrue("New job didn't stop when device no longer idle", 1134 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1135 assertEquals(JobParameters.STOP_REASON_APP_STANDBY, 1136 mTestAppInterface.getLastParams().getStopReason()); 1137 } 1138 1139 @Test testRestrictingStopReason_RestrictedBucket_charging()1140 public void testRestrictingStopReason_RestrictedBucket_charging() throws Exception { 1141 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1142 // Can't toggle charging state if there's no battery. 1143 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 1144 1145 // This test is designed for the old quota system. 1146 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 1147 1148 setTestPackageStandbyBucket(Bucket.RESTRICTED); 1149 1150 // Disable coalescing and the parole session 1151 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 1152 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0"); 1153 1154 // Satisfy all additional constraints. 1155 setChargingState(true); 1156 BatteryUtils.runDumpsysBatterySetLevel(100); 1157 setScreenState(false); 1158 triggerJobIdle(); 1159 1160 // Charging 1161 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 1162 runJob(); 1163 assertTrue("New job didn't start in RESTRICTED bucket", 1164 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1165 setChargingState(false); 1166 assertTrue("New job didn't stop when device no longer charging", 1167 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1168 assertEquals(JobParameters.STOP_REASON_APP_STANDBY, 1169 mTestAppInterface.getLastParams().getStopReason()); 1170 } 1171 1172 @Test testRestrictingStopReason_RestrictedBucket_batteryNotLow()1173 public void testRestrictingStopReason_RestrictedBucket_batteryNotLow() throws Exception { 1174 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1175 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 1176 1177 // This test is designed for the old quota system. 1178 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 1179 1180 setTestPackageStandbyBucket(Bucket.RESTRICTED); 1181 1182 // Disable coalescing and the parole session 1183 mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0"); 1184 mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0"); 1185 1186 // Satisfy all additional constraints. 1187 setChargingState(true); 1188 BatteryUtils.runDumpsysBatterySetLevel(100); 1189 setScreenState(false); 1190 triggerJobIdle(); 1191 1192 // Battery not low 1193 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 1194 runJob(); 1195 assertTrue("New job didn't start in RESTRICTED bucket", 1196 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1197 BatteryUtils.runDumpsysBatterySetLevel(1); 1198 assertTrue("New job didn't stop when battery too low", 1199 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1200 assertEquals(JobParameters.STOP_REASON_APP_STANDBY, 1201 mTestAppInterface.getLastParams().getStopReason()); 1202 } 1203 1204 @Test testRestrictingStopReason_Quota()1205 public void testRestrictingStopReason_Quota() throws Exception { 1206 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1207 assumeTrue("device doesn't have battery", BatteryUtils.hasBattery()); 1208 1209 // This test is designed for the old quota system. 1210 mTareDeviceConfigStateHelper.set("enable_tare_mode", "0"); 1211 1212 // Reduce allowed time for testing. 1213 mDeviceConfigStateHelper.set("qc_allowed_time_per_period_rare_ms", "60000"); 1214 setChargingState(false); 1215 setTestPackageStandbyBucket(Bucket.RARE); 1216 1217 sendScheduleJobBroadcast(false); 1218 runJob(); 1219 assertTrue("New job didn't start", 1220 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1221 1222 Thread.sleep(60000); 1223 1224 assertTrue("New job didn't stop after using up quota", 1225 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1226 assertEquals(JobParameters.STOP_REASON_QUOTA, 1227 mTestAppInterface.getLastParams().getStopReason()); 1228 } 1229 1230 /* 1231 Tests currently disabled because they require changes inside the framework to lower the minimum 1232 EJ quota to one minute (from 5 minutes). 1233 TODO(224533485): make JS testable enough to enable these tests 1234 1235 @Test 1236 public void testRestrictingStopReason_ExpeditedQuota_startOnCharging() throws Exception { 1237 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1238 assumeFalse("not testable in automotive device", mAutomotiveDevice); // Test needs battery 1239 assumeFalse("not testable in leanback device", mLeanbackOnly); // Test needs battery 1240 1241 // Reduce allowed time for testing. System to cap the time above 30 seconds. 1242 mDeviceConfigStateHelper.set("qc_ej_limit_rare_ms", "30000"); 1243 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", "30000"); 1244 // Start with charging so JobScheduler thinks the job can run for the maximum amount of 1245 // time. We turn off charging later so quota clearly comes into effect. 1246 setChargingState(true); 1247 setTestPackageStandbyBucket(Bucket.RARE); 1248 1249 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, true); 1250 runJob(); 1251 assertTrue("New job didn't start", 1252 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1253 assertTrue(mTestAppInterface.getLastParams().isExpeditedJob()); 1254 setChargingState(false); 1255 1256 assertFalse("Job stopped before using up quota", 1257 mTestAppInterface.awaitJobStop(45_000)); 1258 Thread.sleep(15_000); 1259 1260 assertTrue("Job didn't stop after using up quota", 1261 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1262 assertEquals(JobParameters.STOP_REASON_QUOTA, 1263 mTestAppInterface.getLastParams().getStopReason()); 1264 } 1265 1266 @Test 1267 public void testRestrictingStopReason_ExpeditedQuota_noCharging() throws Exception { 1268 assumeTrue("app standby not enabled", mAppStandbyEnabled); 1269 assumeFalse("not testable in automotive device", mAutomotiveDevice); // Test needs battery 1270 assumeFalse("not testable in leanback device", mLeanbackOnly); // Test needs battery 1271 1272 // Reduce allowed time for testing. 1273 mDeviceConfigStateHelper.set("qc_ej_limit_rare_ms", "30000"); 1274 mDeviceConfigStateHelper.set("runtime_min_ej_guarantee_ms", "30000"); 1275 setChargingState(false); 1276 setTestPackageStandbyBucket(Bucket.RARE); 1277 1278 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, true); 1279 runJob(); 1280 assertTrue("New job didn't start", 1281 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1282 assertTrue(mTestAppInterface.getLastParams().isExpeditedJob()); 1283 1284 assertFalse("Job stopped before using up quota", 1285 mTestAppInterface.awaitJobStop(45_000)); 1286 Thread.sleep(15_000); 1287 1288 assertTrue("Job didn't stop after using up quota", 1289 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1290 // Charging state was false when the job started, so the trigger the timeout before 1291 // QuotaController officially marks the quota finished. 1292 final int stopReason = mTestAppInterface.getLastParams().getStopReason(); 1293 assertTrue(stopReason == JobParameters.STOP_REASON_TIMEOUT 1294 || stopReason == JobParameters.STOP_REASON_QUOTA); 1295 } 1296 */ 1297 1298 @Test testRestrictingStopReason_BatterySaver()1299 public void testRestrictingStopReason_BatterySaver() throws Exception { 1300 BatteryUtils.assumeBatterySaverFeature(); 1301 1302 setChargingState(false); 1303 BatteryUtils.enableBatterySaver(false); 1304 sendScheduleJobBroadcast(false); 1305 runJob(); 1306 assertTrue("Job did not start after scheduling", 1307 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1308 1309 BatteryUtils.enableBatterySaver(true); 1310 assertTrue("Job did not stop on entering battery saver", 1311 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1312 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 1313 mTestAppInterface.getLastParams().getStopReason()); 1314 } 1315 1316 @Test testRestrictingStopReason_Doze()1317 public void testRestrictingStopReason_Doze() throws Exception { 1318 assumeTrue("device idle not enabled", mDeviceIdleEnabled); 1319 1320 toggleDozeState(false); 1321 mTestAppInterface.scheduleJob(false, NETWORK_TYPE_NONE, false); 1322 runJob(); 1323 assertTrue("Job did not start after scheduling", 1324 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT)); 1325 1326 toggleDozeState(true); 1327 assertTrue("Job did not stop on entering doze", 1328 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT)); 1329 assertEquals(JobParameters.STOP_REASON_DEVICE_STATE, 1330 mTestAppInterface.getLastParams().getStopReason()); 1331 } 1332 1333 @After tearDown()1334 public void tearDown() throws Exception { 1335 AppOpsUtils.reset(TEST_APP_PACKAGE); 1336 // Lock thermal service to not throttling 1337 ThermalUtils.overrideThermalNotThrottling(); 1338 if (mDeviceIdleEnabled || mDeviceLightIdleEnabled) { 1339 resetDozeState(); 1340 } 1341 mTestAppInterface.cleanup(); 1342 mUiDevice.executeShellCommand("cmd jobscheduler monitor-battery off"); 1343 BatteryUtils.runDumpsysBatteryReset(); 1344 BatteryUtils.resetBatterySaver(); 1345 Settings.Global.putString(mContext.getContentResolver(), 1346 Settings.Global.BATTERY_STATS_CONSTANTS, mInitialBatteryStatsConstants); 1347 removeTestAppFromTempWhitelist(); 1348 1349 mNetworkingHelper.tearDown(); 1350 mDeviceConfigStateHelper.restoreOriginalValues(); 1351 mActivityManagerDeviceConfigStateHelper.restoreOriginalValues(); 1352 mTareDeviceConfigStateHelper.restoreOriginalValues(); 1353 1354 mUiDevice.executeShellCommand( 1355 "cmd jobscheduler reset-execution-quota -u " + UserHandle.myUserId() 1356 + " " + TEST_APP_PACKAGE); 1357 1358 Settings.System.putString( 1359 mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, mInitialDisplayTimeout); 1360 1361 Settings.Global.putString(mContext.getContentResolver(), 1362 Settings.Global.ACTIVITY_MANAGER_CONSTANTS, mInitialActivityManagerConstants); 1363 } 1364 setTestPackageRestricted(boolean restricted)1365 private void setTestPackageRestricted(boolean restricted) throws Exception { 1366 AppOpsUtils.setOpMode(TEST_APP_PACKAGE, "RUN_ANY_IN_BACKGROUND", 1367 restricted ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED); 1368 } 1369 toggleAutoRestrictedBucketOnBgRestricted(boolean enable)1370 private void toggleAutoRestrictedBucketOnBgRestricted(boolean enable) { 1371 mActivityManagerDeviceConfigStateHelper.set("bg_auto_restricted_bucket_on_bg_restricted", 1372 Boolean.toString(enable)); 1373 } 1374 isTestAppTempWhitelisted()1375 private boolean isTestAppTempWhitelisted() throws Exception { 1376 final String output = mUiDevice.executeShellCommand("cmd deviceidle tempwhitelist").trim(); 1377 for (String line : output.split("\n")) { 1378 if (line.contains("UID=" + UserHandle.getAppId(mTestPackageUid))) { 1379 return true; 1380 } 1381 } 1382 return false; 1383 } 1384 sendScheduleJobBroadcast(boolean allowWhileIdle)1385 private void sendScheduleJobBroadcast(boolean allowWhileIdle) throws Exception { 1386 mTestAppInterface.scheduleJob(allowWhileIdle, NETWORK_TYPE_NONE, false); 1387 } 1388 resetDozeState()1389 private void resetDozeState() throws Exception { 1390 mUiDevice.executeShellCommand("cmd deviceidle unforce"); 1391 } 1392 toggleDozeState(final boolean idle)1393 private void toggleDozeState(final boolean idle) throws Exception { 1394 final String changeCommand; 1395 if (idle) { 1396 changeCommand = "force-idle " + (mDeviceIdleEnabled ? "deep" : "light"); 1397 } else { 1398 changeCommand = "force-active"; 1399 } 1400 mUiDevice.executeShellCommand("cmd deviceidle " + changeCommand); 1401 assertTrue("Could not change device idle state to " + idle, 1402 waitUntilTrue(SHELL_TIMEOUT, () -> { 1403 if (idle) { 1404 return mDeviceIdleEnabled 1405 ? mPowerManager.isDeviceIdleMode() 1406 : mPowerManager.isDeviceLightIdleMode(); 1407 } else { 1408 return !mPowerManager.isDeviceIdleMode() 1409 && !mPowerManager.isDeviceLightIdleMode(); 1410 } 1411 })); 1412 } 1413 tempWhitelistTestApp(long duration)1414 private void tempWhitelistTestApp(long duration) throws Exception { 1415 mUiDevice.executeShellCommand("cmd deviceidle tempwhitelist -d " + duration 1416 + " -u " + UserHandle.myUserId() 1417 + " " + TEST_APP_PACKAGE); 1418 } 1419 makeTestPackageIdle()1420 private void makeTestPackageIdle() throws Exception { 1421 mUiDevice.executeShellCommand("am make-uid-idle --user current " + TEST_APP_PACKAGE); 1422 } 1423 setTestPackageStandbyBucket(Bucket bucket)1424 void setTestPackageStandbyBucket(Bucket bucket) throws Exception { 1425 setTestPackageStandbyBucket(mUiDevice, bucket); 1426 } 1427 setTestPackageStandbyBucket(UiDevice uiDevice, Bucket bucket)1428 static void setTestPackageStandbyBucket(UiDevice uiDevice, Bucket bucket) throws Exception { 1429 final String bucketName; 1430 switch (bucket) { 1431 case ACTIVE: 1432 bucketName = "active"; 1433 break; 1434 case WORKING_SET: 1435 bucketName = "working"; 1436 break; 1437 case FREQUENT: 1438 bucketName = "frequent"; 1439 break; 1440 case RARE: 1441 bucketName = "rare"; 1442 break; 1443 case RESTRICTED: 1444 bucketName = "restricted"; 1445 break; 1446 case NEVER: 1447 bucketName = "never"; 1448 break; 1449 default: 1450 throw new IllegalArgumentException("Requested unknown bucket " + bucket); 1451 } 1452 uiDevice.executeShellCommand("am set-standby-bucket " + TEST_APP_PACKAGE 1453 + " " + bucketName); 1454 } 1455 removeTestAppFromTempWhitelist()1456 private boolean removeTestAppFromTempWhitelist() throws Exception { 1457 mUiDevice.executeShellCommand("cmd deviceidle tempwhitelist" 1458 + " -u " + UserHandle.myUserId() 1459 + " -r " + TEST_APP_PACKAGE); 1460 return waitUntilTrue(SHELL_TIMEOUT, () -> !isTestAppTempWhitelisted()); 1461 } 1462 1463 /** 1464 * Set the screen state. 1465 */ setScreenState(boolean on)1466 private void setScreenState(boolean on) throws Exception { 1467 if (on) { 1468 mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); 1469 mUiDevice.executeShellCommand("wm dismiss-keyguard"); 1470 } else { 1471 mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); 1472 } 1473 // Wait a little bit to make sure the screen state has changed. 1474 Thread.sleep(4_000); 1475 } 1476 setChargingState(boolean isCharging)1477 private void setChargingState(boolean isCharging) throws Exception { 1478 mUiDevice.executeShellCommand("cmd jobscheduler monitor-battery on"); 1479 1480 final String command; 1481 if (isCharging) { 1482 mUiDevice.executeShellCommand("cmd battery set ac 1"); 1483 final int curLevel = Integer.parseInt( 1484 mUiDevice.executeShellCommand("dumpsys battery get level").trim()); 1485 command = "cmd battery set -f level " + Math.min(100, curLevel + 1); 1486 } else { 1487 command = "cmd battery unplug -f"; 1488 } 1489 int seq = Integer.parseInt(mUiDevice.executeShellCommand(command).trim()); 1490 1491 // Wait for the battery update to be processed by job scheduler before proceeding. 1492 waitUntil("JobScheduler didn't update charging status to " + isCharging, 15 /* seconds */, 1493 () -> { 1494 int curSeq; 1495 boolean curCharging; 1496 curSeq = Integer.parseInt(mUiDevice.executeShellCommand( 1497 "cmd jobscheduler get-battery-seq").trim()); 1498 curCharging = Boolean.parseBoolean(mUiDevice.executeShellCommand( 1499 "cmd jobscheduler get-battery-charging").trim()); 1500 return curSeq >= seq && curCharging == isCharging; 1501 }); 1502 } 1503 1504 /** 1505 * Trigger job idle (not device idle); 1506 */ triggerJobIdle()1507 private void triggerJobIdle() throws Exception { 1508 mUiDevice.executeShellCommand("cmd activity idle-maintenance"); 1509 // Wait a moment to let that happen before proceeding. 1510 Thread.sleep(2_000); 1511 } 1512 1513 /** Asks (not forces) JobScheduler to run the job if constraints are met. */ runJob()1514 private void runJob() throws Exception { 1515 // Since connectivity is a functional constraint, calling the "run" command without force 1516 // will only get the job to run if the constraint is satisfied. 1517 mUiDevice.executeShellCommand("cmd jobscheduler run -s" 1518 + " -u " + UserHandle.myUserId() + " " + TEST_APP_PACKAGE + " " + mTestJobId); 1519 } 1520 hasEthernetConnection()1521 private boolean hasEthernetConnection() { 1522 return mNetworkingHelper.hasEthernetConnection(); 1523 } 1524 getJobState()1525 private String getJobState() throws Exception { 1526 return mUiDevice.executeShellCommand("cmd jobscheduler get-job-state --user cur " 1527 + TEST_APP_PACKAGE + " " + mTestJobId).trim(); 1528 } 1529 assertJobWaiting()1530 private void assertJobWaiting() throws Exception { 1531 String state = getJobState(); 1532 assertTrue("Job unexpectedly not waiting, in state: " + state, state.contains("waiting")); 1533 } 1534 assertJobNotReady()1535 private void assertJobNotReady() throws Exception { 1536 String state = getJobState(); 1537 assertFalse("Job unexpectedly ready, in state: " + state, state.contains("ready")); 1538 } 1539 assertJobReady()1540 private void assertJobReady() throws Exception { 1541 String state = getJobState(); 1542 assertTrue("Job unexpectedly not ready, in state: " + state, state.contains("ready")); 1543 } 1544 waitUntilTrue(long maxWait, Condition condition)1545 private boolean waitUntilTrue(long maxWait, Condition condition) throws Exception { 1546 final long deadLine = SystemClock.uptimeMillis() + maxWait; 1547 do { 1548 Thread.sleep(POLL_INTERVAL); 1549 } while (!condition.isTrue() && SystemClock.uptimeMillis() < deadLine); 1550 return condition.isTrue(); 1551 } 1552 1553 private interface Condition { isTrue()1554 boolean isTrue() throws Exception; 1555 } 1556 } 1557