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