summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kweku Adams <kwekua@google.com> 2020-04-29 16:50:27 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-04-29 16:50:27 +0000
commit7a97fd74d4ee561bee976319f46f2d1e498155e9 (patch)
treea3d8992bd3f3c936d3921ba702b00e924c38f26b
parent272cae6e102daa3a3f8d843ab7d6b813a6b2356b (diff)
parentb99b582f490139187ef1d1acde4dcec611c3b8d9 (diff)
Merge "Fix QC alarm spamming." into rvc-dev
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java36
-rw-r--r--services/core/java/com/android/server/utils/quota/CountQuotaTracker.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java71
3 files changed, 105 insertions, 9 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 8c55b50957da..d108f0b698f7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -241,10 +241,11 @@ public final class QuotaController extends StateController {
+ "bgJobCountInMaxPeriod=" + bgJobCountInMaxPeriod + ", "
+ "sessionCountInWindow=" + sessionCountInWindow + ", "
+ "inQuotaTime=" + inQuotaTimeElapsed + ", "
- + "jobCountExpirationTime=" + jobRateLimitExpirationTimeElapsed + ", "
- + "jobCountInRateLimitingWindow=" + jobCountInRateLimitingWindow + ", "
- + "sessionCountExpirationTime=" + sessionRateLimitExpirationTimeElapsed + ", "
- + "sessionCountInRateLimitingWindow=" + sessionCountInRateLimitingWindow;
+ + "rateLimitJobCountExpirationTime=" + jobRateLimitExpirationTimeElapsed + ", "
+ + "rateLimitJobCountWindow=" + jobCountInRateLimitingWindow + ", "
+ + "rateLimitSessionCountExpirationTime="
+ + sessionRateLimitExpirationTimeElapsed + ", "
+ + "rateLimitSessionCountWindow=" + sessionCountInRateLimitingWindow;
}
@Override
@@ -863,12 +864,19 @@ public final class QuotaController extends StateController {
stats.executionTimeInMaxPeriodMs = 0;
stats.bgJobCountInMaxPeriod = 0;
stats.sessionCountInWindow = 0;
- stats.inQuotaTimeElapsed = 0;
+ if (stats.jobCountLimit == 0 || stats.sessionCountLimit == 0) {
+ // App won't be in quota until configuration changes.
+ stats.inQuotaTimeElapsed = Long.MAX_VALUE;
+ } else {
+ stats.inQuotaTimeElapsed = 0;
+ }
Timer timer = mPkgTimers.get(userId, packageName);
final long nowElapsed = sElapsedRealtimeClock.millis();
stats.expirationTimeElapsed = nowElapsed + MAX_PERIOD_MS;
if (timer != null && timer.isActive()) {
+ // Exclude active sessions from the session count so that new jobs aren't prevented
+ // from starting due to an app hitting the session limit.
stats.executionTimeInWindowMs =
stats.executionTimeInMaxPeriodMs = timer.getCurrentDuration(nowElapsed);
stats.bgJobCountInWindow = stats.bgJobCountInMaxPeriod = timer.getBgJobCount();
@@ -883,6 +891,10 @@ public final class QuotaController extends StateController {
stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed,
nowElapsed - mMaxExecutionTimeIntoQuotaMs + MAX_PERIOD_MS);
}
+ if (stats.bgJobCountInWindow >= stats.jobCountLimit) {
+ stats.inQuotaTimeElapsed = Math.max(stats.inQuotaTimeElapsed,
+ nowElapsed + stats.windowSizeMs);
+ }
}
List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
@@ -1303,6 +1315,13 @@ public final class QuotaController extends StateController {
inQuotaTimeElapsed = Math.max(inQuotaTimeElapsed,
stats.sessionRateLimitExpirationTimeElapsed);
}
+ if (inQuotaTimeElapsed <= sElapsedRealtimeClock.millis()) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ Slog.wtf(TAG,
+ "In quota time is " + (nowElapsed - inQuotaTimeElapsed) + "ms old. Now="
+ + nowElapsed + ", inQuotaTime=" + inQuotaTimeElapsed + ": " + stats);
+ inQuotaTimeElapsed = nowElapsed + 5 * MINUTE_IN_MILLIS;
+ }
mInQuotaAlarmListener.addAlarmLocked(userId, packageName, inQuotaTimeElapsed);
}
@@ -1916,8 +1935,8 @@ public final class QuotaController extends StateController {
@GuardedBy("mLock")
private void setNextAlarmLocked(long earliestTriggerElapsed) {
if (mAlarmQueue.size() > 0) {
- final long nextTriggerTimeElapsed = Math.max(earliestTriggerElapsed,
- mAlarmQueue.peek().second);
+ final Pair<Package, Long> alarm = mAlarmQueue.peek();
+ final long nextTriggerTimeElapsed = Math.max(earliestTriggerElapsed, alarm.second);
// Only schedule the alarm if one of the following is true:
// 1. There isn't one currently scheduled
// 2. The new alarm is significantly earlier than the previous alarm. If it's
@@ -1928,7 +1947,8 @@ public final class QuotaController extends StateController {
|| nextTriggerTimeElapsed < mTriggerTimeElapsed - 3 * MINUTE_IN_MILLIS
|| mTriggerTimeElapsed < nextTriggerTimeElapsed) {
if (DEBUG) {
- Slog.d(TAG, "Scheduling start alarm at " + nextTriggerTimeElapsed);
+ Slog.d(TAG, "Scheduling start alarm at " + nextTriggerTimeElapsed
+ + " for app " + alarm.first);
}
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextTriggerTimeElapsed,
ALARM_TAG_QUOTA_CHECK, this, mHandler);
diff --git a/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java b/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
index 7fe4bf849443..b77df2d18859 100644
--- a/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
+++ b/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
@@ -408,7 +408,12 @@ public class CountQuotaTracker extends QuotaTracker {
void updateExecutionStatsLocked(final int userId, @NonNull final String packageName,
@Nullable final String tag, @NonNull ExecutionStats stats) {
stats.countInWindow = 0;
- stats.inQuotaTimeElapsed = 0;
+ if (stats.countLimit == 0) {
+ // UPTC won't be in quota until configuration changes.
+ stats.inQuotaTimeElapsed = Long.MAX_VALUE;
+ } else {
+ stats.inQuotaTimeElapsed = 0;
+ }
// This can be used to determine when an app will have enough quota to transition from
// out-of-quota to in-quota.
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index bc0b184cd359..c8ec7b5503d1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -620,6 +620,77 @@ public class QuotaControllerTest {
assertEquals(expectedStats, inputStats);
}
+ @Test
+ public void testUpdateExecutionStatsLocked_WithTimer() {
+ final long now = sElapsedRealtimeClock.millis();
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+
+ ExecutionStats expectedStats = new ExecutionStats();
+ ExecutionStats inputStats = new ExecutionStats();
+ inputStats.windowSizeMs = expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS;
+ inputStats.jobCountLimit = expectedStats.jobCountLimit = mQcConstants.MAX_JOB_COUNT_RARE;
+ inputStats.sessionCountLimit = expectedStats.sessionCountLimit =
+ mQcConstants.MAX_SESSION_COUNT_RARE;
+ // Active timer isn't counted as session yet.
+ expectedStats.sessionCountInWindow = 0;
+ // Timer only, under quota.
+ for (int i = 1; i < mQcConstants.MAX_JOB_COUNT_RARE; ++i) {
+ JobStatus jobStatus = createJobStatus("testUpdateExecutionStatsLocked_WithTimer", i);
+ setStandbyBucket(RARE_INDEX, jobStatus); // 24 hour window
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(7000);
+
+ expectedStats.expirationTimeElapsed = sElapsedRealtimeClock.millis();
+ expectedStats.executionTimeInWindowMs = expectedStats.executionTimeInMaxPeriodMs =
+ 7000 * i;
+ expectedStats.bgJobCountInWindow = expectedStats.bgJobCountInMaxPeriod = i;
+ mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats);
+ assertEquals(expectedStats, inputStats);
+ assertTrue(mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
+ RARE_INDEX));
+ }
+
+ // Add old session. Make sure values are combined correctly.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(sElapsedRealtimeClock.millis() - (6 * HOUR_IN_MILLIS),
+ 10 * MINUTE_IN_MILLIS, 5));
+ expectedStats.sessionCountInWindow = 1;
+
+ expectedStats.expirationTimeElapsed = sElapsedRealtimeClock.millis() + 18 * HOUR_IN_MILLIS;
+ expectedStats.executionTimeInWindowMs += 10 * MINUTE_IN_MILLIS;
+ expectedStats.executionTimeInMaxPeriodMs += 10 * MINUTE_IN_MILLIS;
+ expectedStats.bgJobCountInWindow += 5;
+ expectedStats.bgJobCountInMaxPeriod += 5;
+ // Active timer is under quota, so out of quota due to old session.
+ expectedStats.inQuotaTimeElapsed =
+ sElapsedRealtimeClock.millis() + 18 * HOUR_IN_MILLIS + 10 * MINUTE_IN_MILLIS;
+ mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats);
+ assertEquals(expectedStats, inputStats);
+ assertFalse(
+ mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX));
+
+ // Quota should be exceeded due to activity in active timer.
+ JobStatus jobStatus = createJobStatus("testUpdateExecutionStatsLocked_WithTimer", 0);
+ setStandbyBucket(RARE_INDEX, jobStatus); // 24 hour window
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(10000);
+
+ expectedStats.executionTimeInWindowMs += 10000;
+ expectedStats.executionTimeInMaxPeriodMs += 10000;
+ expectedStats.bgJobCountInWindow++;
+ expectedStats.bgJobCountInMaxPeriod++;
+ // Out of quota due to activity in active timer, so in quota time should be when enough
+ // time has passed since active timer.
+ expectedStats.inQuotaTimeElapsed =
+ sElapsedRealtimeClock.millis() + expectedStats.windowSizeMs;
+ mQuotaController.updateExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, inputStats);
+ assertEquals(expectedStats, inputStats);
+ assertFalse(
+ mQuotaController.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX));
+ }
+
/**
* Tests that getExecutionStatsLocked returns the correct stats.
*/