Dump most recent constraint changes per job.

Track the most recent constraint changes for each job and log them in
the dump to aid in debugging.

Bug: 171305774
Test: visually inspect dump
Change-Id: If77d38e0d613224adfa6cca884edef275b32932d
This commit is contained in:
Kweku Adams
2021-02-18 14:17:42 -08:00
parent 1a0c0a51f4
commit 27e5995ec9
12 changed files with 292 additions and 205 deletions

View File

@@ -17,6 +17,7 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -59,6 +60,8 @@ public final class BackgroundJobsController extends StateController {
private final AppStateTrackerImpl mAppStateTracker;
private final UpdateJobFunctor mUpdateJobFunctor = new UpdateJobFunctor();
public BackgroundJobsController(JobSchedulerService service) {
super(service);
@@ -69,7 +72,7 @@ public final class BackgroundJobsController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
updateSingleJobRestrictionLocked(jobStatus, sElapsedRealtimeClock.millis(), UNKNOWN);
}
@Override
@@ -79,7 +82,7 @@ public final class BackgroundJobsController extends StateController {
@Override
public void evaluateStateLocked(JobStatus jobStatus) {
updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
updateSingleJobRestrictionLocked(jobStatus, sElapsedRealtimeClock.millis(), UNKNOWN);
}
@Override
@@ -163,33 +166,34 @@ public final class BackgroundJobsController extends StateController {
}
private void updateJobRestrictionsLocked(int filterUid, int newActiveState) {
final UpdateJobFunctor updateTrackedJobs = new UpdateJobFunctor(newActiveState);
mUpdateJobFunctor.prepare(newActiveState);
final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
final JobStore store = mService.getJobStore();
if (filterUid > 0) {
store.forEachJobForSourceUid(filterUid, updateTrackedJobs);
store.forEachJobForSourceUid(filterUid, mUpdateJobFunctor);
} else {
store.forEachJob(updateTrackedJobs);
store.forEachJob(mUpdateJobFunctor);
}
final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
if (DEBUG) {
Slog.d(TAG, String.format(
"Job status updated: %d/%d checked/total jobs, %d us",
updateTrackedJobs.mCheckedCount,
updateTrackedJobs.mTotalCount,
mUpdateJobFunctor.mCheckedCount,
mUpdateJobFunctor.mTotalCount,
(time / 1000)
));
));
}
if (updateTrackedJobs.mChanged) {
if (mUpdateJobFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
}
}
boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, int activeState) {
boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, final long nowElapsed,
int activeState) {
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
@@ -205,26 +209,32 @@ public final class BackgroundJobsController extends StateController {
if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) {
jobStatus.maybeLogBucketMismatch();
}
boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
boolean didChange =
jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun);
didChange |= jobStatus.setUidActive(isActive);
return didChange;
}
private final class UpdateJobFunctor implements Consumer<JobStatus> {
final int activeState;
int mActiveState;
boolean mChanged = false;
int mTotalCount = 0;
int mCheckedCount = 0;
long mUpdateTimeElapsed = 0;
public UpdateJobFunctor(int newActiveState) {
activeState = newActiveState;
void prepare(int newActiveState) {
mActiveState = newActiveState;
mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
mChanged = false;
mTotalCount = 0;
mCheckedCount = 0;
}
@Override
public void accept(JobStatus jobStatus) {
mTotalCount++;
mCheckedCount++;
if (updateSingleJobRestrictionLocked(jobStatus, activeState)) {
if (updateSingleJobRestrictionLocked(jobStatus, mUpdateTimeElapsed, mActiveState)) {
mChanged = true;
}
}

View File

@@ -65,10 +65,12 @@ public final class BatteryController extends RestrictingController {
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasPowerConstraint()) {
final long nowElapsed = sElapsedRealtimeClock.millis();
mTrackedTasks.add(taskStatus);
taskStatus.setTrackingController(JobStatus.TRACKING_BATTERY);
taskStatus.setChargingConstraintSatisfied(mChargeTracker.isOnStablePower());
taskStatus.setBatteryNotLowConstraintSatisfied(mChargeTracker.isBatteryNotLow());
taskStatus.setChargingConstraintSatisfied(nowElapsed, mChargeTracker.isOnStablePower());
taskStatus.setBatteryNotLowConstraintSatisfied(
nowElapsed, mChargeTracker.isBatteryNotLow());
}
}
@@ -97,14 +99,15 @@ public final class BatteryController extends RestrictingController {
if (DEBUG) {
Slog.d(TAG, "maybeReportNewChargingStateLocked: " + stablePower);
}
final long nowElapsed = sElapsedRealtimeClock.millis();
boolean reportChange = false;
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
boolean previous = ts.setChargingConstraintSatisfied(stablePower);
boolean previous = ts.setChargingConstraintSatisfied(nowElapsed, stablePower);
if (previous != stablePower) {
reportChange = true;
}
previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow);
previous = ts.setBatteryNotLowConstraintSatisfied(nowElapsed, batteryNotLow);
if (previous != batteryNotLow) {
reportChange = true;
}

View File

@@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.annotation.Nullable;
import android.app.job.JobInfo;
@@ -461,11 +462,12 @@ public final class ConnectivityController extends RestrictingController implemen
final Network network = mConnManager.getActiveNetworkForUid(
jobStatus.getSourceUid(), jobStatus.shouldIgnoreNetworkBlocking());
final NetworkCapabilities capabilities = getNetworkCapabilities(network);
return updateConstraintsSatisfied(jobStatus, network, capabilities);
return updateConstraintsSatisfied(jobStatus, sElapsedRealtimeClock.millis(),
network, capabilities);
}
private boolean updateConstraintsSatisfied(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities) {
private boolean updateConstraintsSatisfied(JobStatus jobStatus, final long nowElapsed,
Network network, NetworkCapabilities capabilities) {
// TODO: consider matching against non-active networks
final boolean ignoreBlocked = jobStatus.shouldIgnoreNetworkBlocking();
@@ -476,7 +478,7 @@ public final class ConnectivityController extends RestrictingController implemen
final boolean satisfied = isSatisfied(jobStatus, network, capabilities, mConstants);
final boolean changed = jobStatus
.setConnectivityConstraintSatisfied(connected && satisfied);
.setConnectivityConstraintSatisfied(nowElapsed, connected && satisfied);
// Pass along the evaluated network for job to use; prevents race
// conditions as default routes change over time, and opens the door to
@@ -530,6 +532,7 @@ public final class ConnectivityController extends RestrictingController implemen
NetworkCapabilities exemptedNetworkCapabilities = null;
boolean exemptedNetworkMatch = false;
final long nowElapsed = sElapsedRealtimeClock.millis();
boolean changed = false;
for (int i = jobs.size() - 1; i >= 0; i--) {
final JobStatus js = jobs.valueAt(i);
@@ -555,7 +558,7 @@ public final class ConnectivityController extends RestrictingController implemen
// job hasn't yet been evaluated against the currently
// active network; typically when we just lost a network.
if (match || !Objects.equals(js.network, net)) {
changed |= updateConstraintsSatisfied(js, net, netCap);
changed |= updateConstraintsSatisfied(js, nowElapsed, net, netCap);
}
}
return changed;

View File

@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.annotation.UserIdInt;
import android.app.job.JobInfo;
import android.database.ContentObserver;
@@ -74,6 +76,7 @@ public final class ContentObserverController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasContentTriggerConstraint()) {
final long nowElapsed = sElapsedRealtimeClock.millis();
if (taskStatus.contentObserverJobInstance == null) {
taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
}
@@ -110,7 +113,7 @@ public final class ContentObserverController extends StateController {
}
taskStatus.changedAuthorities = null;
taskStatus.changedUris = null;
taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
taskStatus.setContentTriggerConstraintSatisfied(nowElapsed, havePendingUris);
}
if (lastJob != null && lastJob.contentObserverJobInstance != null) {
// And now we can detach the instance state from the last job.
@@ -295,7 +298,8 @@ public final class ContentObserverController extends StateController {
boolean reportChange = false;
synchronized (mLock) {
if (mTriggerPending) {
if (mJobStatus.setContentTriggerConstraintSatisfied(true)) {
final long nowElapsed = sElapsedRealtimeClock.millis();
if (mJobStatus.setContentTriggerConstraintSatisfied(nowElapsed, true)) {
reportChange = true;
}
unscheduleLocked();

View File

@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -104,8 +106,10 @@ public final class DeviceIdleJobsController extends StateController {
+ Arrays.toString(mPowerSaveTempWhitelistAppIds));
}
boolean changed = false;
final long nowElapsed = sElapsedRealtimeClock.millis();
for (int i = 0; i < mAllowInIdleJobs.size(); i++) {
changed |= updateTaskStateLocked(mAllowInIdleJobs.valueAt(i));
changed |=
updateTaskStateLocked(mAllowInIdleJobs.valueAt(i), nowElapsed);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -147,6 +151,7 @@ public final class DeviceIdleJobsController extends StateController {
}
mDeviceIdleMode = enabled;
if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
mDeviceIdleUpdateFunctor.prepare();
if (enabled) {
mHandler.removeMessages(PROCESS_BACKGROUND_JOBS);
mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
@@ -180,7 +185,7 @@ public final class DeviceIdleJobsController extends StateController {
Slog.d(TAG, "uid " + uid + " going " + (active ? "active" : "inactive"));
}
mForegroundUids.put(uid, active);
mDeviceIdleUpdateFunctor.mChanged = false;
mDeviceIdleUpdateFunctor.prepare();
mService.getJobStore().forEachJobForSourceUid(uid, mDeviceIdleUpdateFunctor);
if (mDeviceIdleUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
@@ -203,12 +208,12 @@ public final class DeviceIdleJobsController extends StateController {
UserHandle.getAppId(job.getSourceUid()));
}
private boolean updateTaskStateLocked(JobStatus task) {
private boolean updateTaskStateLocked(JobStatus task, final long nowElapsed) {
final boolean allowInIdle = ((task.getFlags()&JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0)
&& (mForegroundUids.get(task.getSourceUid()) || isTempWhitelistedLocked(task));
final boolean whitelisted = isWhitelistedLocked(task);
final boolean enableTask = !mDeviceIdleMode || whitelisted || allowInIdle;
return task.setDeviceNotDozingConstraintSatisfied(enableTask, whitelisted);
return task.setDeviceNotDozingConstraintSatisfied(nowElapsed, enableTask, whitelisted);
}
@Override
@@ -216,7 +221,7 @@ public final class DeviceIdleJobsController extends StateController {
if ((jobStatus.getFlags()&JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) {
mAllowInIdleJobs.add(jobStatus);
}
updateTaskStateLocked(jobStatus);
updateTaskStateLocked(jobStatus, sElapsedRealtimeClock.millis());
}
@Override
@@ -282,10 +287,16 @@ public final class DeviceIdleJobsController extends StateController {
final class DeviceIdleUpdateFunctor implements Consumer<JobStatus> {
boolean mChanged;
long mUpdateTimeElapsed = 0;
void prepare() {
mChanged = false;
mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
}
@Override
public void accept(JobStatus jobStatus) {
mChanged |= updateTaskStateLocked(jobStatus);
mChanged |= updateTaskStateLocked(jobStatus, mUpdateTimeElapsed);
}
}
@@ -300,7 +311,7 @@ public final class DeviceIdleJobsController extends StateController {
case PROCESS_BACKGROUND_JOBS:
// Just process all the jobs, the ones in foreground should already be running.
synchronized (mLock) {
mDeviceIdleUpdateFunctor.mChanged = false;
mDeviceIdleUpdateFunctor.prepare();
mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
if (mDeviceIdleUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();

View File

@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
@@ -58,9 +60,10 @@ public final class IdleController extends RestrictingController implements Idlen
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasIdleConstraint()) {
final long nowElapsed = sElapsedRealtimeClock.millis();
mTrackedTasks.add(taskStatus);
taskStatus.setTrackingController(JobStatus.TRACKING_IDLE);
taskStatus.setIdleConstraintSatisfied(mIdleTracker.isIdle());
taskStatus.setIdleConstraintSatisfied(nowElapsed, mIdleTracker.isIdle());
}
}
@@ -90,8 +93,9 @@ public final class IdleController extends RestrictingController implements Idlen
@Override
public void reportNewIdleState(boolean isIdle) {
synchronized (mLock) {
final long nowElapsed = sElapsedRealtimeClock.millis();
for (int i = mTrackedTasks.size()-1; i >= 0; i--) {
mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(isIdle);
mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(nowElapsed, isIdle);
}
}
mStateChangedListener.onControllerStateChanged();

View File

@@ -73,6 +73,8 @@ public final class JobStatus {
private static final String TAG = "JobScheduler.JobStatus";
static final boolean DEBUG = JobSchedulerService.DEBUG;
private static final int NUM_CONSTRAINT_CHANGE_HISTORY = 10;
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
@@ -350,6 +352,10 @@ public final class JobStatus {
*/
private Pair<Long, Long> mPersistedUtcTimes;
private int mConstraintChangeHistoryIndex = 0;
private final long[] mConstraintUpdatedTimesElapsed = new long[NUM_CONSTRAINT_CHANGE_HISTORY];
private final int[] mConstraintStatusHistory = new int[NUM_CONSTRAINT_CHANGE_HISTORY];
/**
* For use only by ContentObserverController: state it is maintaining about content URIs
* being observed.
@@ -1090,28 +1096,28 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
boolean setChargingConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
boolean setChargingConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_CHARGING, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setBatteryNotLowConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
boolean setBatteryNotLowConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setStorageNotLowConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
boolean setStorageNotLowConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setTimingDelayConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
boolean setTimingDelayConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setDeadlineConstraintSatisfied(boolean state) {
if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) {
boolean setDeadlineConstraintSatisfied(final long nowElapsed, boolean state) {
if (setConstraintSatisfied(CONSTRAINT_DEADLINE, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyDeadlineSatisfied = !job.isPeriodic() && hasDeadlineConstraint() && state;
return true;
@@ -1120,24 +1126,25 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
boolean setIdleConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_IDLE, state);
boolean setIdleConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_IDLE, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setConnectivityConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
boolean setConnectivityConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setContentTriggerConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
boolean setContentTriggerConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, nowElapsed, state);
}
/** @return true if the constraint was changed, false otherwise. */
boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
boolean setDeviceNotDozingConstraintSatisfied(final long nowElapsed,
boolean state, boolean whitelisted) {
dozeWhitelisted = whitelisted;
if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) {
if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyNotDozing = state || canRunInDoze();
return true;
@@ -1146,8 +1153,8 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) {
boolean setBackgroundNotRestrictedConstraintSatisfied(final long nowElapsed, boolean state) {
if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyNotRestrictedInBg = state;
return true;
@@ -1156,8 +1163,8 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
boolean setQuotaConstraintSatisfied(boolean state) {
if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, state)) {
boolean setQuotaConstraintSatisfied(final long nowElapsed, boolean state) {
if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyWithinQuota = state;
return true;
@@ -1166,8 +1173,8 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
boolean setExpeditedJobQuotaConstraintSatisfied(boolean state) {
if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, state)) {
boolean setExpeditedJobQuotaConstraintSatisfied(final long nowElapsed, boolean state) {
if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, nowElapsed, state)) {
// The constraint was changed. Update the ready flag.
mReadyWithinExpeditedQuota = state;
// DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
@@ -1190,7 +1197,7 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
boolean setConstraintSatisfied(int constraint, boolean state) {
boolean setConstraintSatisfied(int constraint, final long nowElapsed, boolean state) {
boolean old = (satisfiedConstraints&constraint) != 0;
if (old == state) {
return false;
@@ -1212,6 +1219,12 @@ public final class JobStatus {
: FrameworkStatsLog
.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
}
mConstraintUpdatedTimesElapsed[mConstraintChangeHistoryIndex] = nowElapsed;
mConstraintStatusHistory[mConstraintChangeHistoryIndex] = satisfiedConstraints;
mConstraintChangeHistoryIndex =
(mConstraintChangeHistoryIndex + 1) % NUM_CONSTRAINT_CHANGE_HISTORY;
return true;
}
@@ -1700,7 +1713,7 @@ public final class JobStatus {
}
// Dumpsys infrastructure
public void dump(IndentingPrintWriter pw, boolean full, long elapsedRealtimeMillis) {
public void dump(IndentingPrintWriter pw, boolean full, long nowElapsed) {
UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
@@ -1830,6 +1843,22 @@ public final class JobStatus {
dumpConstraints(pw,
((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
pw.println();
pw.println("Constraint history:");
pw.increaseIndent();
for (int h = 0; h < NUM_CONSTRAINT_CHANGE_HISTORY; ++h) {
final int idx = (h + mConstraintChangeHistoryIndex) % NUM_CONSTRAINT_CHANGE_HISTORY;
if (mConstraintUpdatedTimesElapsed[idx] == 0) {
continue;
}
TimeUtils.formatDuration(mConstraintUpdatedTimesElapsed[idx], nowElapsed, pw);
// dumpConstraints prepends with a space, so no need to add a space after the =
pw.print(" =");
dumpConstraints(pw, mConstraintStatusHistory[idx]);
pw.println();
}
pw.decreaseIndent();
if (dozeWhitelisted) {
pw.println("Doze whitelisted: true");
}
@@ -1910,26 +1939,25 @@ public final class JobStatus {
pw.increaseIndent();
if (whenStandbyDeferred != 0) {
pw.print("Deferred since: ");
TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
TimeUtils.formatDuration(whenStandbyDeferred, nowElapsed, pw);
pw.println();
}
if (mFirstForceBatchedTimeElapsed != 0) {
pw.print("Time since first force batch attempt: ");
TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw);
TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, nowElapsed, pw);
pw.println();
}
pw.decreaseIndent();
pw.print("Enqueue time: ");
TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
TimeUtils.formatDuration(enqueueTime, nowElapsed, pw);
pw.println();
pw.print("Run time: earliest=");
formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, nowElapsed);
pw.print(", latest=");
formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, nowElapsed);
pw.print(", original latest=");
formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis,
NO_LATEST_RUNTIME, elapsedRealtimeMillis);
formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis, NO_LATEST_RUNTIME, nowElapsed);
pw.println();
if (numFailures != 0) {
pw.print("Num failures: "); pw.println(numFailures);

View File

@@ -626,6 +626,7 @@ public final class QuotaController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
final long nowElapsed = sElapsedRealtimeClock.millis();
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
@@ -636,11 +637,11 @@ public final class QuotaController extends StateController {
jobs.add(jobStatus);
jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
setConstraintSatisfied(jobStatus, isWithinQuota);
setConstraintSatisfied(jobStatus, nowElapsed, isWithinQuota);
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
setExpeditedConstraintSatisfied(jobStatus, nowElapsed, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1397,7 +1398,8 @@ public final class QuotaController extends StateController {
synchronized (mLock) {
final ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
quota.transactOnDebitsLocked(-credit);
if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
@@ -1499,11 +1501,12 @@ public final class QuotaController extends StateController {
private void maybeUpdateAllConstraintsLocked() {
boolean changed = false;
final long nowElapsed = sElapsedRealtimeClock.millis();
for (int u = 0; u < mTrackedJobs.numMaps(); ++u) {
final int userId = mTrackedJobs.keyAt(u);
for (int p = 0; p < mTrackedJobs.numElementsForKey(userId); ++p) {
final String packageName = mTrackedJobs.keyAt(u, p);
changed |= maybeUpdateConstraintForPkgLocked(userId, packageName);
changed |= maybeUpdateConstraintForPkgLocked(nowElapsed, userId, packageName);
}
}
if (changed) {
@@ -1516,7 +1519,7 @@ public final class QuotaController extends StateController {
*
* @return true if at least one job had its bit changed
*/
private boolean maybeUpdateConstraintForPkgLocked(final int userId,
private boolean maybeUpdateConstraintForPkgLocked(final long nowElapsed, final int userId,
@NonNull final String packageName) {
ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, packageName);
if (jobs == null || jobs.size() == 0) {
@@ -1533,21 +1536,21 @@ public final class QuotaController extends StateController {
if (isTopStartedJobLocked(js)) {
// Job was started while the app was in the TOP state so we should allow it to
// finish.
changed |= js.setQuotaConstraintSatisfied(true);
changed |= js.setQuotaConstraintSatisfied(nowElapsed, true);
} else if (realStandbyBucket != ACTIVE_INDEX
&& realStandbyBucket == js.getEffectiveStandbyBucket()) {
// An app in the ACTIVE bucket may be out of quota while the job could be in quota
// for some reason. Therefore, avoid setting the real value here and check each job
// individually.
changed |= setConstraintSatisfied(js, realInQuota);
changed |= setConstraintSatisfied(js, nowElapsed, realInQuota);
} else {
// This job is somehow exempted. Need to determine its own quota status.
changed |= setConstraintSatisfied(js, isWithinQuotaLocked(js));
changed |= setConstraintSatisfied(js, nowElapsed, isWithinQuotaLocked(js));
}
if (js.isRequestedExpeditedJob()) {
boolean isWithinEJQuota = isWithinEJQuotaLocked(js);
changed |= setExpeditedConstraintSatisfied(js, isWithinEJQuota);
changed |= setExpeditedConstraintSatisfied(js, nowElapsed, isWithinEJQuota);
outOfEJQuota |= !isWithinEJQuota;
}
}
@@ -1566,14 +1569,21 @@ public final class QuotaController extends StateController {
private final SparseArrayMap<String, Integer> mToScheduleStartAlarms =
new SparseArrayMap<>();
public boolean wasJobChanged;
long mUpdateTimeElapsed = 0;
void prepare() {
mUpdateTimeElapsed = sElapsedRealtimeClock.millis();
}
@Override
public void accept(JobStatus jobStatus) {
wasJobChanged |= setConstraintSatisfied(jobStatus, isWithinQuotaLocked(jobStatus));
wasJobChanged |= setConstraintSatisfied(
jobStatus, mUpdateTimeElapsed, isWithinQuotaLocked(jobStatus));
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
wasJobChanged |= setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
wasJobChanged |= setExpeditedConstraintSatisfied(
jobStatus, mUpdateTimeElapsed, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1611,6 +1621,7 @@ public final class QuotaController extends StateController {
private final UidConstraintUpdater mUpdateUidConstraints = new UidConstraintUpdater();
private boolean maybeUpdateConstraintForUidLocked(final int uid) {
mUpdateUidConstraints.prepare();
mService.getJobStore().forEachJobForSourceUid(uid, mUpdateUidConstraints);
mUpdateUidConstraints.postProcess();
@@ -1716,21 +1727,22 @@ public final class QuotaController extends StateController {
mInQuotaAlarmListener.addAlarmLocked(userId, packageName, inQuotaTimeElapsed);
}
private boolean setConstraintSatisfied(@NonNull JobStatus jobStatus, boolean isWithinQuota) {
private boolean setConstraintSatisfied(@NonNull JobStatus jobStatus, long nowElapsed,
boolean isWithinQuota) {
if (!isWithinQuota && jobStatus.getWhenStandbyDeferred() == 0) {
// Mark that the job is being deferred due to buckets.
jobStatus.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
jobStatus.setWhenStandbyDeferred(nowElapsed);
}
return jobStatus.setQuotaConstraintSatisfied(isWithinQuota);
return jobStatus.setQuotaConstraintSatisfied(nowElapsed, isWithinQuota);
}
/**
* If the satisfaction changes, this will tell connectivity & background jobs controller to
* also re-evaluate their state.
*/
private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus,
private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus, long nowElapsed,
boolean isWithinQuota) {
if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinQuota)) {
if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(nowElapsed, isWithinQuota)) {
mBackgroundJobsController.evaluateStateLocked(jobStatus);
mConnectivityController.evaluateStateLocked(jobStatus);
if (isWithinQuota && jobStatus.isReady()) {
@@ -2188,7 +2200,8 @@ public final class QuotaController extends StateController {
final ShrinkableDebits quota =
getEJQuotaLocked(mPkg.userId, mPkg.packageName);
quota.transactOnDebitsLocked(-mEJRewardTopAppMs * numTimeChunks);
if (maybeUpdateConstraintForPkgLocked(mPkg.userId, mPkg.packageName)) {
if (maybeUpdateConstraintForPkgLocked(nowElapsed,
mPkg.userId, mPkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
@@ -2292,7 +2305,8 @@ public final class QuotaController extends StateController {
if (timer != null && timer.isActive()) {
timer.rescheduleCutoff();
}
if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
}
@@ -2417,7 +2431,8 @@ public final class QuotaController extends StateController {
if (timeRemainingMs <= 50) {
// Less than 50 milliseconds left. Start process of shutting down jobs.
if (DEBUG) Slog.d(TAG, pkg + " has reached its quota.");
if (maybeUpdateConstraintForPkgLocked(pkg.userId, pkg.packageName)) {
if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
pkg.userId, pkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
} else {
@@ -2444,7 +2459,8 @@ public final class QuotaController extends StateController {
pkg.userId, pkg.packageName);
if (timeRemainingMs <= 0) {
if (DEBUG) Slog.d(TAG, pkg + " has reached its EJ quota.");
if (maybeUpdateConstraintForPkgLocked(pkg.userId, pkg.packageName)) {
if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
pkg.userId, pkg.packageName)) {
mStateChangedListener.onControllerStateChanged();
}
} else {
@@ -2475,7 +2491,8 @@ public final class QuotaController extends StateController {
if (DEBUG) {
Slog.d(TAG, "Checking pkg " + string(userId, packageName));
}
if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
userId, packageName)) {
mStateChangedListener.onControllerStateChanged();
}
break;

View File

@@ -61,9 +61,11 @@ public final class StorageController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasStorageNotLowConstraint()) {
final long nowElapsed = sElapsedRealtimeClock.millis();
mTrackedTasks.add(taskStatus);
taskStatus.setTrackingController(JobStatus.TRACKING_STORAGE);
taskStatus.setStorageNotLowConstraintSatisfied(mStorageTracker.isStorageNotLow());
taskStatus.setStorageNotLowConstraintSatisfied(
nowElapsed, mStorageTracker.isStorageNotLow());
}
}
@@ -76,12 +78,13 @@ public final class StorageController extends StateController {
}
private void maybeReportNewStorageState() {
final long nowElapsed = sElapsedRealtimeClock.millis();
final boolean storageNotLow = mStorageTracker.isStorageNotLow();
boolean reportChange = false;
synchronized (mLock) {
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
reportChange |= ts.setStorageNotLowConstraintSatisfied(storageNotLow);
reportChange |= ts.setStorageNotLowConstraintSatisfied(nowElapsed, storageNotLow);
}
}
if (storageNotLow) {

View File

@@ -258,9 +258,9 @@ public final class TimeController extends StateController {
if (jobDeadline <= nowElapsedMillis) {
if (job.hasTimingDelayConstraint()) {
job.setTimingDelayConstraintSatisfied(true);
job.setTimingDelayConstraintSatisfied(nowElapsedMillis, true);
}
job.setDeadlineConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(nowElapsedMillis, true);
return true;
}
return false;
@@ -332,7 +332,7 @@ public final class TimeController extends StateController {
private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
final long jobDelayTime = job.getEarliestRunTime();
if (jobDelayTime <= nowElapsedMillis) {
job.setTimingDelayConstraintSatisfied(true);
job.setTimingDelayConstraintSatisfied(nowElapsedMillis, true);
return true;
}
return false;

View File

@@ -25,6 +25,7 @@ import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NOT_LOW;
import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING;
@@ -101,7 +102,7 @@ public class JobStatusTest {
Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
JobSchedulerService.sUptimeMillisClock =
Clock.fixed(SystemClock.uptimeClock().instant(), ZoneOffset.UTC);
JobSchedulerService.sElapsedRealtimeClock =
sElapsedRealtimeClock =
Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
}
@@ -204,7 +205,7 @@ public class JobStatusTest {
@Test
public void testFraction() throws Exception {
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
final long now = sElapsedRealtimeClock.millis();
assertEquals(1, createJobStatus(0, Long.MAX_VALUE).getFractionRunTime(), DELTA);
@@ -261,15 +262,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setChargingConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
job.setChargingConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
markImplicitConstraintsSatisfied(job, false);
job.setChargingConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
job.setChargingConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
}
@@ -282,15 +283,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setIdleConstraintSatisfied(false);
job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
job.setIdleConstraintSatisfied(true);
job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
markImplicitConstraintsSatisfied(job, false);
job.setIdleConstraintSatisfied(false);
job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
job.setIdleConstraintSatisfied(true);
job.setIdleConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_IDLE));
}
@@ -303,15 +304,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setBatteryNotLowConstraintSatisfied(false);
job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
job.setBatteryNotLowConstraintSatisfied(true);
job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
markImplicitConstraintsSatisfied(job, false);
job.setBatteryNotLowConstraintSatisfied(false);
job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
job.setBatteryNotLowConstraintSatisfied(true);
job.setBatteryNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BATTERY_NOT_LOW));
}
@@ -324,15 +325,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setStorageNotLowConstraintSatisfied(false);
job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
job.setStorageNotLowConstraintSatisfied(true);
job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
markImplicitConstraintsSatisfied(job, false);
job.setStorageNotLowConstraintSatisfied(false);
job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
job.setStorageNotLowConstraintSatisfied(true);
job.setStorageNotLowConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_STORAGE_NOT_LOW));
}
@@ -345,15 +346,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setTimingDelayConstraintSatisfied(false);
job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
job.setTimingDelayConstraintSatisfied(true);
job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
markImplicitConstraintsSatisfied(job, false);
job.setTimingDelayConstraintSatisfied(false);
job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
job.setTimingDelayConstraintSatisfied(true);
job.setTimingDelayConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_TIMING_DELAY));
}
@@ -366,15 +367,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setDeadlineConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setDeadlineConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
markImplicitConstraintsSatisfied(job, false);
job.setDeadlineConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setDeadlineConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
}
@@ -387,15 +388,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setConnectivityConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
job.setConnectivityConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
markImplicitConstraintsSatisfied(job, false);
job.setConnectivityConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
job.setConnectivityConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
}
@@ -410,15 +411,15 @@ public class JobStatusTest {
final JobStatus job = createJobStatus(jobInfo);
markImplicitConstraintsSatisfied(job, true);
job.setContentTriggerConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setContentTriggerConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
markImplicitConstraintsSatisfied(job, false);
job.setContentTriggerConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setContentTriggerConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
}
@@ -436,15 +437,15 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, false);
job.setChargingConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setChargingConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
// Still false because implicit constraints aren't satisfied.
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
@@ -452,61 +453,61 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, true);
job.setChargingConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Turn on constraints one at a time.
job.setChargingConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setChargingConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setChargingConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// With two of the 3 constraints satisfied (and implicit constraints also satisfied), only
// the unsatisfied constraint should return true.
job.setChargingConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setChargingConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setChargingConstraintSatisfied(false);
job.setConnectivityConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
job.setChargingConstraintSatisfied(true);
job.setConnectivityConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setConnectivityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONNECTIVITY));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
@@ -526,15 +527,15 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, false);
job.setChargingConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setChargingConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
// Still false because implicit constraints aren't satisfied.
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
@@ -542,18 +543,18 @@ public class JobStatusTest {
markImplicitConstraintsSatisfied(job, true);
job.setChargingConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
// Turn on constraints one at a time.
job.setChargingConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
// Deadline should force isReady to be true, but isn't needed for the job to be
// considered ready.
@@ -561,17 +562,17 @@ public class JobStatusTest {
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setChargingConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setChargingConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
// Since the deadline constraint is satisfied, none of the other explicit constraints are
// needed.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
@@ -581,33 +582,33 @@ public class JobStatusTest {
// With two of the 3 constraints satisfied (and implicit constraints also satisfied), only
// the unsatisfied constraint should return true.
job.setChargingConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(false);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setChargingConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(false);
job.setDeadlineConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setChargingConstraintSatisfied(false);
job.setContentTriggerConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEADLINE));
job.setChargingConstraintSatisfied(true);
job.setContentTriggerConstraintSatisfied(true);
job.setDeadlineConstraintSatisfied(true);
job.setChargingConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setContentTriggerConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
job.setDeadlineConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CHARGING));
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_CONTENT_TRIGGER));
// Once implicit constraint are satisfied, deadline constraint should always return true.
@@ -621,15 +622,15 @@ public class JobStatusTest {
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
markImplicitConstraintsSatisfied(job, false);
job.setDeviceNotDozingConstraintSatisfied(false, false);
job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), false, false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
job.setDeviceNotDozingConstraintSatisfied(true, false);
job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), true, false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
markImplicitConstraintsSatisfied(job, true);
job.setDeviceNotDozingConstraintSatisfied(false, false);
job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), false, false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
job.setDeviceNotDozingConstraintSatisfied(true, false);
job.setDeviceNotDozingConstraintSatisfied(sElapsedRealtimeClock.millis(), true, false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_DEVICE_NOT_DOZING));
}
@@ -640,15 +641,15 @@ public class JobStatusTest {
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
markImplicitConstraintsSatisfied(job, false);
job.setQuotaConstraintSatisfied(false);
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
job.setQuotaConstraintSatisfied(true);
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
markImplicitConstraintsSatisfied(job, true);
job.setQuotaConstraintSatisfied(false);
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
job.setQuotaConstraintSatisfied(true);
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_WITHIN_QUOTA));
}
@@ -659,22 +660,24 @@ public class JobStatusTest {
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build());
markImplicitConstraintsSatisfied(job, false);
job.setBackgroundNotRestrictedConstraintSatisfied(false);
job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
job.setBackgroundNotRestrictedConstraintSatisfied(true);
job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertFalse(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
markImplicitConstraintsSatisfied(job, true);
job.setBackgroundNotRestrictedConstraintSatisfied(false);
job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), false);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
job.setBackgroundNotRestrictedConstraintSatisfied(true);
job.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
assertTrue(job.wouldBeReadyWithConstraint(CONSTRAINT_BACKGROUND_NOT_RESTRICTED));
}
private void markImplicitConstraintsSatisfied(JobStatus job, boolean isSatisfied) {
job.setQuotaConstraintSatisfied(isSatisfied);
job.setDeviceNotDozingConstraintSatisfied(isSatisfied, false);
job.setBackgroundNotRestrictedConstraintSatisfied(isSatisfied);
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
job.setDeviceNotDozingConstraintSatisfied(
sElapsedRealtimeClock.millis(), isSatisfied, false);
job.setBackgroundNotRestrictedConstraintSatisfied(
sElapsedRealtimeClock.millis(), isSatisfied);
}
private static JobStatus createJobStatus(long earliestRunTimeElapsedMillis,

View File

@@ -359,8 +359,9 @@ public class QuotaControllerTest {
// Make sure tests aren't passing just because the default bucket is likely ACTIVE.
js.setStandbyBucket(FREQUENT_INDEX);
// Make sure Doze and background-not-restricted don't affect tests.
js.setDeviceNotDozingConstraintSatisfied(/* state */ true, /* allowlisted */false);
js.setBackgroundNotRestrictedConstraintSatisfied(true);
js.setDeviceNotDozingConstraintSatisfied(/* nowElapsed */ sElapsedRealtimeClock.millis(),
/* state */ true, /* allowlisted */false);
js.setBackgroundNotRestrictedConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
return js;
}