Merge "Ensure apps can schedule/start EJs when temp allowlisted." into sc-dev
This commit is contained in:
@@ -813,12 +813,21 @@ public final class QuotaController extends StateController {
|
||||
// 1. it's already running (already executing expedited jobs should be allowed to finish)
|
||||
// 2. the app is currently in the foreground
|
||||
// 3. the app overall is within its quota
|
||||
// 4. It's on the temp allowlist (or within the grace period)
|
||||
if (isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) {
|
||||
return true;
|
||||
}
|
||||
final long tempAllowlistGracePeriodEndElapsed =
|
||||
mTempAllowlistGraceCache.get(jobStatus.getSourceUid());
|
||||
final boolean hasTempAllowlistExemption = mTempAllowlistCache.get(jobStatus.getSourceUid())
|
||||
|| sElapsedRealtimeClock.millis() < tempAllowlistGracePeriodEndElapsed;
|
||||
if (hasTempAllowlistExemption) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Timer ejTimer = mEJPkgTimers.get(jobStatus.getSourceUserId(),
|
||||
jobStatus.getSourcePackageName());
|
||||
// Any already executing expedited jbos should be allowed to finish.
|
||||
// Any already executing expedited jobs should be allowed to finish.
|
||||
if (ejTimer != null && ejTimer.isRunning(jobStatus)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1879,6 +1879,144 @@ public class QuotaControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWithinEJQuotaLocked_NeverApp() {
|
||||
JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_NeverApp", 1);
|
||||
setStandbyBucket(NEVER_INDEX, js);
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWithinEJQuotaLocked_Charging() {
|
||||
setCharging();
|
||||
JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_Charging", 1);
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWithinEJQuotaLocked_UnderDuration() {
|
||||
setDischarging();
|
||||
JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_UnderDuration", 1);
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWithinEJQuotaLocked_OverDuration() {
|
||||
setDischarging();
|
||||
JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_OverDuration", 1);
|
||||
setStandbyBucket(FREQUENT_INDEX, js);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 10 * MINUTE_IN_MILLIS);
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5), true);
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWithinEJQuotaLocked_TimingSession() {
|
||||
setDischarging();
|
||||
setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ACTIVE_MS, 20 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_WORKING_MS, 15 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 13 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 8 * MINUTE_IN_MILLIS);
|
||||
|
||||
JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_TimingSession", 1);
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - ((60 - i) * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS,
|
||||
2), true);
|
||||
|
||||
synchronized (mQuotaController.mLock) {
|
||||
setStandbyBucket(ACTIVE_INDEX, js);
|
||||
assertEquals("Active has incorrect quota status with " + (i + 1) + " sessions",
|
||||
i < 19, mQuotaController.isWithinEJQuotaLocked(js));
|
||||
|
||||
setStandbyBucket(WORKING_INDEX, js);
|
||||
assertEquals("Working has incorrect quota status with " + (i + 1) + " sessions",
|
||||
i < 14, mQuotaController.isWithinEJQuotaLocked(js));
|
||||
|
||||
setStandbyBucket(FREQUENT_INDEX, js);
|
||||
assertEquals("Frequent has incorrect quota status with " + (i + 1) + " sessions",
|
||||
i < 12, mQuotaController.isWithinEJQuotaLocked(js));
|
||||
|
||||
setStandbyBucket(RARE_INDEX, js);
|
||||
assertEquals("Rare has incorrect quota status with " + (i + 1) + " sessions",
|
||||
i < 9, mQuotaController.isWithinEJQuotaLocked(js));
|
||||
|
||||
setStandbyBucket(RESTRICTED_INDEX, js);
|
||||
assertEquals("Restricted has incorrect quota status with " + (i + 1) + " sessions",
|
||||
i < 7, mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Timers properly track sessions when an app is added and removed from the temp
|
||||
* allowlist.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWithinEJQuotaLocked_TempAllowlisting() {
|
||||
setDischarging();
|
||||
JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_TempAllowlisting", 1);
|
||||
setStandbyBucket(FREQUENT_INDEX, js);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 10 * MINUTE_IN_MILLIS);
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5), true);
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
|
||||
setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
|
||||
final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
|
||||
Handler handler = mQuotaController.getHandler();
|
||||
spyOn(handler);
|
||||
|
||||
// Apps on the temp allowlist should be able to schedule & start EJs, even if they're out
|
||||
// of quota (as long as they are in the temp allowlist grace period).
|
||||
mTempAllowlistListener.onAppAdded(mSourceUid);
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
advanceElapsedClock(10 * SECOND_IN_MILLIS);
|
||||
mTempAllowlistListener.onAppRemoved(mSourceUid);
|
||||
advanceElapsedClock(10 * SECOND_IN_MILLIS);
|
||||
// Still in grace period
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
advanceElapsedClock(6 * SECOND_IN_MILLIS);
|
||||
// Out of grace period.
|
||||
synchronized (mQuotaController.mLock) {
|
||||
assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaybeScheduleCleanupAlarmLocked() {
|
||||
// No sessions saved yet.
|
||||
@@ -3880,6 +4018,55 @@ public class QuotaControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRemainingEJExecutionTimeLocked_IncrementalTimingSessions() {
|
||||
setDischarging();
|
||||
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ACTIVE_MS, 20 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_WORKING_MS, 15 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 13 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
|
||||
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 5 * MINUTE_IN_MILLIS);
|
||||
|
||||
for (int i = 1; i <= 25; ++i) {
|
||||
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
|
||||
createTimingSession(now - ((60 - i) * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS,
|
||||
2), true);
|
||||
|
||||
synchronized (mQuotaController.mLock) {
|
||||
setStandbyBucket(ACTIVE_INDEX);
|
||||
assertEquals("Active has incorrect remaining EJ time with " + i + " sessions",
|
||||
(20 - i) * MINUTE_IN_MILLIS,
|
||||
mQuotaController.getRemainingEJExecutionTimeLocked(
|
||||
SOURCE_USER_ID, SOURCE_PACKAGE));
|
||||
|
||||
setStandbyBucket(WORKING_INDEX);
|
||||
assertEquals("Working has incorrect remaining EJ time with " + i + " sessions",
|
||||
(15 - i) * MINUTE_IN_MILLIS,
|
||||
mQuotaController.getRemainingEJExecutionTimeLocked(
|
||||
SOURCE_USER_ID, SOURCE_PACKAGE));
|
||||
|
||||
setStandbyBucket(FREQUENT_INDEX);
|
||||
assertEquals("Frequent has incorrect remaining EJ time with " + i + " sessions",
|
||||
(13 - i) * MINUTE_IN_MILLIS,
|
||||
mQuotaController.getRemainingEJExecutionTimeLocked(
|
||||
SOURCE_USER_ID, SOURCE_PACKAGE));
|
||||
|
||||
setStandbyBucket(RARE_INDEX);
|
||||
assertEquals("Rare has incorrect remaining EJ time with " + i + " sessions",
|
||||
(10 - i) * MINUTE_IN_MILLIS,
|
||||
mQuotaController.getRemainingEJExecutionTimeLocked(
|
||||
SOURCE_USER_ID, SOURCE_PACKAGE));
|
||||
|
||||
setStandbyBucket(RESTRICTED_INDEX);
|
||||
assertEquals("Restricted has incorrect remaining EJ time with " + i + " sessions",
|
||||
(5 - i) * MINUTE_IN_MILLIS,
|
||||
mQuotaController.getRemainingEJExecutionTimeLocked(
|
||||
SOURCE_USER_ID, SOURCE_PACKAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTimeUntilEJQuotaConsumedLocked_NoHistory() {
|
||||
final long[] limits = mQuotaController.getEJLimitsMs();
|
||||
|
||||
Reference in New Issue
Block a user