Merge "Fix QC alarm spamming." into rvc-dev am: 7a97fd74d4 am: 7f53da43bd am: 6ac36921c6

Change-Id: I76081530de61935ae9033a85cc3d7d792a4ec22b
This commit is contained in:
Kweku Adams
2020-04-29 17:47:51 +00:00
committed by Automerger Merge Worker
3 changed files with 105 additions and 9 deletions

View File

@@ -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);

View File

@@ -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.

View File

@@ -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.
*/