diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index e44e9022bf5d3..38bb75f33f024 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -25,7 +25,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; -import android.app.AlarmManager; import android.app.AppGlobals; import android.app.IUidObserver; import android.app.job.IJobScheduler; @@ -95,7 +94,6 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob; -import com.android.server.job.JobSchedulerServiceDumpProto.RegisteredJob; import com.android.server.job.controllers.BackgroundJobsController; import com.android.server.job.controllers.BatteryController; import com.android.server.job.controllers.ConnectivityController; @@ -117,7 +115,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; @@ -240,18 +237,7 @@ public class JobSchedulerService extends com.android.server.SystemService final SparseIntArray mBackingUpUids = new SparseIntArray(); /** - * Count standby heartbeats, and keep track of which beat each bucket's jobs will - * next become runnable. Index into this array is by normalized bucket: - * { ACTIVE, WORKING, FREQUENT, RARE, NEVER }. The ACTIVE and NEVER bucket - * milestones are not updated: ACTIVE apps get jobs whenever they ask for them, - * and NEVER apps don't get them at all. - */ - final long[] mNextBucketHeartbeat = { 0, 0, 0, 0, Long.MAX_VALUE }; - long mHeartbeat = 0; - long mLastHeartbeatTime = sElapsedRealtimeClock.millis(); - - /** - * Named indices into the STANDBY_BEATS array, for clarity in referring to + * Named indices into standby bucket arrays, for clarity in referring to * specific buckets' bookkeeping. */ public static final int ACTIVE_INDEX = 0; @@ -260,21 +246,6 @@ public class JobSchedulerService extends com.android.server.SystemService public static final int RARE_INDEX = 3; public static final int NEVER_INDEX = 4; - /** - * Bookkeeping about when jobs last run. We keep our own record in heartbeat time, - * rather than rely on Usage Stats' timestamps, because heartbeat time can be - * manipulated for testing purposes and we need job runnability to track that rather - * than real time. - * - * Outer SparseArray slices by user handle; inner map of package name to heartbeat - * is a HashMap<> rather than ArrayMap<> because we expect O(hundreds) of keys - * and it will be accessed in a known-hot code path. - */ - final SparseArray> mLastJobHeartbeats = new SparseArray<>(); - - static final String HEARTBEAT_TAG = "*job.heartbeat*"; - final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener(); - // -- Pre-allocated temporaries only for use in assignJobsToContextsLocked -- private class ConstantsObserver extends ContentObserver { @@ -311,11 +282,6 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.e(TAG, "Bad jobscheduler settings", e); } } - - if (mConstants.USE_HEARTBEATS) { - // Reset the heartbeat alarm based on the new heartbeat duration - setNextHeartbeatAlarm(); - } } } @@ -465,13 +431,15 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count"; private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time"; private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time"; - private static final String KEY_STANDBY_HEARTBEAT_TIME = "standby_heartbeat_time"; - private static final String KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; - private static final String KEY_STANDBY_FREQUENT_BEATS = "standby_frequent_beats"; - private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; + private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME = + "standby_heartbeat_time"; + private static final String DEPRECATED_KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; + private static final String DEPRECATED_KEY_STANDBY_FREQUENT_BEATS = + "standby_frequent_beats"; + private static final String DEPRECATED_KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac"; private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac"; - private static final String KEY_USE_HEARTBEATS = "use_heartbeats"; + private static final String DEPRECATED_KEY_USE_HEARTBEATS = "use_heartbeats"; private static final int DEFAULT_MIN_IDLE_COUNT = 1; private static final int DEFAULT_MIN_CHARGING_COUNT = 1; @@ -488,13 +456,8 @@ public class JobSchedulerService extends com.android.server.SystemService private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE; private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; - private static final long DEFAULT_STANDBY_HEARTBEAT_TIME = 11 * 60 * 1000L; - private static final int DEFAULT_STANDBY_WORKING_BEATS = 11; // ~ 2 hours, with 11min beats - private static final int DEFAULT_STANDBY_FREQUENT_BEATS = 43; // ~ 8 hours - private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; - private static final boolean DEFAULT_USE_HEARTBEATS = false; /** * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things @@ -617,26 +580,7 @@ public class JobSchedulerService extends com.android.server.SystemService * The minimum backoff time to allow for exponential backoff. */ long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME; - /** - * How often we recalculate runnability based on apps' standby bucket assignment. - * This should be prime relative to common time interval lengths such as a quarter- - * hour or day, so that the heartbeat drifts relative to wall-clock milestones. - */ - long STANDBY_HEARTBEAT_TIME = DEFAULT_STANDBY_HEARTBEAT_TIME; - /** - * Mapping: standby bucket -> number of heartbeats between each sweep of that - * bucket's jobs. - * - * Bucket assignments as recorded in the JobStatus objects are normalized to be - * indices into this array, rather than the raw constants used - * by AppIdleHistory. - */ - final int[] STANDBY_BEATS = { - 0, - DEFAULT_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_RARE_BEATS - }; + /** * The fraction of a job's running window that must pass before we * consider running it when the network is congested. @@ -647,11 +591,6 @@ public class JobSchedulerService extends com.android.server.SystemService * we consider matching it against a metered network. */ public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC; - /** - * Whether to use heartbeats or rolling window for quota management. True will use - * heartbeats, false will use a rolling window. - */ - public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -709,19 +648,10 @@ public class JobSchedulerService extends com.android.server.SystemService DEFAULT_MIN_LINEAR_BACKOFF_TIME); MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME, DEFAULT_MIN_EXP_BACKOFF_TIME); - STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME, - DEFAULT_STANDBY_HEARTBEAT_TIME); - STANDBY_BEATS[WORKING_INDEX] = mParser.getInt(KEY_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_WORKING_BEATS); - STANDBY_BEATS[FREQUENT_INDEX] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS); - STANDBY_BEATS[RARE_INDEX] = mParser.getInt(KEY_STANDBY_RARE_BEATS, - DEFAULT_STANDBY_RARE_BEATS); CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC, DEFAULT_CONN_CONGESTION_DELAY_FRAC); CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC, DEFAULT_CONN_PREFETCH_RELAX_FRAC); - USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS); } void dump(IndentingPrintWriter pw) { @@ -757,17 +687,8 @@ public class JobSchedulerService extends com.android.server.SystemService pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println(); pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println(); pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println(); - pw.printPair(KEY_STANDBY_HEARTBEAT_TIME, STANDBY_HEARTBEAT_TIME).println(); - pw.print("standby_beats={"); - pw.print(STANDBY_BEATS[0]); - for (int i = 1; i < STANDBY_BEATS.length; i++) { - pw.print(", "); - pw.print(STANDBY_BEATS[i]); - } - pw.println('}'); pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println(); - pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println(); pw.decreaseIndent(); } @@ -797,13 +718,8 @@ public class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT); proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME); proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME); - proto.write(ConstantsProto.STANDBY_HEARTBEAT_TIME_MS, STANDBY_HEARTBEAT_TIME); - for (int period : STANDBY_BEATS) { - proto.write(ConstantsProto.STANDBY_BEATS, period); - } proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC); proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC); - proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS); } } @@ -1441,9 +1357,6 @@ public class JobSchedulerService extends com.android.server.SystemService mAppStateTracker = Preconditions.checkNotNull( LocalServices.getService(AppStateTracker.class)); - if (mConstants.USE_HEARTBEATS) { - setNextHeartbeatAlarm(); - } // Register br for package removals and user removals. final IntentFilter filter = new IntentFilter(); @@ -1647,7 +1560,7 @@ public class JobSchedulerService extends com.android.server.SystemService } delayMillis = Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS); - JobStatus newJob = new JobStatus(failureToReschedule, getCurrentHeartbeat(), + JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, backoffAttempts, failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis()); @@ -1682,8 +1595,7 @@ public class JobSchedulerService extends com.android.server.SystemService * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead * to underscheduling at least, rather than if we had taken the last execution time to be the * start of the execution. - *

Unlike a reschedule prior to execution, in this case we advance the next-heartbeat - * tracking as though the job were newly-scheduled. + * * @return A new job representing the execution criteria for this instantiation of the * recurring job. */ @@ -1736,7 +1648,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (newLatestRuntimeElapsed < elapsedNow) { Slog.wtf(TAG, "Rescheduling calculated latest runtime in the past: " + newLatestRuntimeElapsed); - return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), + return new JobStatus(periodicToReschedule, elapsedNow + period - flex, elapsedNow + period, 0 /* backoffAttempt */, sSystemClock.millis() /* lastSuccessfulRunTime */, @@ -1751,64 +1663,13 @@ public class JobSchedulerService extends com.android.server.SystemService newEarliestRunTimeElapsed / 1000 + ", " + newLatestRuntimeElapsed / 1000 + "]s"); } - return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), + return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed, newLatestRuntimeElapsed, 0 /* backoffAttempt */, sSystemClock.millis() /* lastSuccessfulRunTime */, periodicToReschedule.getLastFailedRunTime()); } - /* - * We default to "long enough ago that every bucket's jobs are immediately runnable" to - * avoid starvation of apps in uncommon-use buckets that might arise from repeated - * reboot behavior. - */ - long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) { - // The furthest back in pre-boot time that we need to bother with - long heartbeat = -mConstants.STANDBY_BEATS[RARE_INDEX]; - boolean cacheHit = false; - synchronized (mLock) { - HashMap jobPackages = mLastJobHeartbeats.get(userId); - if (jobPackages != null) { - long cachedValue = jobPackages.getOrDefault(packageName, Long.MAX_VALUE); - if (cachedValue < Long.MAX_VALUE) { - cacheHit = true; - heartbeat = cachedValue; - } - } - if (!cacheHit) { - // We haven't seen it yet; ask usage stats about it - final long timeSinceJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId); - if (timeSinceJob < Long.MAX_VALUE) { - // Usage stats knows about it from before, so calculate back from that - // and go from there. - heartbeat = mHeartbeat - (timeSinceJob / mConstants.STANDBY_HEARTBEAT_TIME); - } - // If usage stats returned its "not found" MAX_VALUE, we still have the - // negative default 'heartbeat' value we established above - setLastJobHeartbeatLocked(packageName, userId, heartbeat); - } - } - if (DEBUG_STANDBY) { - Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " - + packageName + "/" + userId); - } - return heartbeat; - } - - long heartbeatWhenJobsLastRun(JobStatus job) { - return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId()); - } - - void setLastJobHeartbeatLocked(String packageName, int userId, long heartbeat) { - HashMap jobPackages = mLastJobHeartbeats.get(userId); - if (jobPackages == null) { - jobPackages = new HashMap<>(); - mLastJobHeartbeats.put(userId, jobPackages); - } - jobPackages.put(packageName, heartbeat); - } - // JobCompletedListener implementations. /** @@ -2176,82 +2037,6 @@ public class JobSchedulerService extends com.android.server.SystemService mMaybeQueueFunctor.postProcess(); } - /** - * Heartbeat tracking. The heartbeat alarm is intentionally non-wakeup. - */ - class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener { - - @Override - public void onAlarm() { - synchronized (mLock) { - final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime; - final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME; - if (beatsElapsed > 0) { - mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME; - advanceHeartbeatLocked(beatsElapsed); - } - } - setNextHeartbeatAlarm(); - } - } - - // Intentionally does not touch the alarm timing - void advanceHeartbeatLocked(long beatsElapsed) { - if (!mConstants.USE_HEARTBEATS) { - return; - } - mHeartbeat += beatsElapsed; - if (DEBUG_STANDBY) { - Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed - + " to " + mHeartbeat); - } - // Don't update ACTIVE or NEVER bucket milestones. Note that mHeartbeat - // will be equal to mNextBucketHeartbeat[bucket] for one beat, during which - // new jobs scheduled by apps in that bucket will be permitted to run - // immediately. - boolean didAdvanceBucket = false; - for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) { - // Did we reach or cross a bucket boundary? - if (mHeartbeat >= mNextBucketHeartbeat[i]) { - didAdvanceBucket = true; - } - while (mHeartbeat > mNextBucketHeartbeat[i]) { - mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i]; - } - if (DEBUG_STANDBY) { - Slog.v(TAG, " Bucket " + i + " next heartbeat " - + mNextBucketHeartbeat[i]); - } - } - - if (didAdvanceBucket) { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Hit bucket boundary; reevaluating job runnability"); - } - mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); - } - } - - void setNextHeartbeatAlarm() { - final long heartbeatLength; - synchronized (mLock) { - if (!mConstants.USE_HEARTBEATS) { - return; - } - heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME; - } - final long now = sElapsedRealtimeClock.millis(); - final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength; - final long nextHeartbeat = nextBeatOrdinal * heartbeatLength; - if (DEBUG_STANDBY) { - Slog.i(TAG, "Setting heartbeat alarm for " + nextHeartbeat - + " = " + TimeUtils.formatDuration(nextHeartbeat - now)); - } - AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); - am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat, - HEARTBEAT_TAG, mHeartbeatAlarm, mHandler); - } - /** Returns true if both the calling and source users for the job are started. */ private boolean areUsersStartedLocked(final JobStatus job) { boolean sourceStarted = ArrayUtils.contains(mStartedUsers, job.getSourceUserId()); @@ -2323,54 +2108,6 @@ public class JobSchedulerService extends com.android.server.SystemService return false; } - if (mConstants.USE_HEARTBEATS) { - // If the app is in a non-active standby bucket, make sure we've waited - // an appropriate amount of time since the last invocation. During device- - // wide parole, standby bucketing is ignored. - // - // Jobs in 'active' apps are not subject to standby, nor are jobs that are - // specifically marked as exempt. - if (DEBUG_STANDBY) { - Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString() - + " parole=" + mInParole + " active=" + job.uidActive - + " exempt=" + job.getJob().isExemptedFromAppStandby()); - } - if (!mInParole - && !job.uidActive - && !job.getJob().isExemptedFromAppStandby()) { - final int bucket = job.getStandbyBucket(); - if (DEBUG_STANDBY) { - Slog.v(TAG, " bucket=" + bucket + " heartbeat=" + mHeartbeat - + " next=" + mNextBucketHeartbeat[bucket]); - } - if (mHeartbeat < mNextBucketHeartbeat[bucket]) { - // Only skip this job if the app is still waiting for the end of its nominal - // bucket interval. Once it's waited that long, we let it go ahead and clear. - // The final (NEVER) bucket is special; we never age those apps' jobs into - // runnability. - final long appLastRan = heartbeatWhenJobsLastRun(job); - if (bucket >= mConstants.STANDBY_BEATS.length - || (mHeartbeat > appLastRan - && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) { - if (job.getWhenStandbyDeferred() == 0) { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < " - + (appLastRan + mConstants.STANDBY_BEATS[bucket]) - + " for " + job); - } - job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis()); - } - return false; - } else { - if (DEBUG_STANDBY) { - Slog.v(TAG, "Bucket deferred job aged into runnability at " - + mHeartbeat + " : " + job); - } - } - } - } - } - // The expensive check: validate that the defined package+service is // still present & viable. return isComponentUsable(job); @@ -2439,9 +2176,6 @@ public class JobSchedulerService extends com.android.server.SystemService // Job pending/active doesn't affect the readiness of a job. - // Skipping the heartbeat check as this will only come into play when using the rolling - // window quota management system. - // The expensive check: validate that the defined package+service is // still present & viable. return isComponentUsable(job); @@ -2450,9 +2184,6 @@ public class JobSchedulerService extends com.android.server.SystemService /** Returns the maximum amount of time this job could run for. */ public long getMaxJobExecutionTimeMs(JobStatus job) { synchronized (mLock) { - if (mConstants.USE_HEARTBEATS) { - return JobServiceContext.EXECUTING_TIMESLICE_MILLIS; - } return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job), JobServiceContext.EXECUTING_TIMESLICE_MILLIS); } @@ -2497,56 +2228,6 @@ public class JobSchedulerService extends com.android.server.SystemService final class LocalService implements JobSchedulerInternal { - /** - * The current bucket heartbeat ordinal - */ - public long currentHeartbeat() { - return getCurrentHeartbeat(); - } - - /** - * Heartbeat ordinal at which the given standby bucket's jobs next become runnable - */ - public long nextHeartbeatForBucket(int bucket) { - synchronized (mLock) { - return mNextBucketHeartbeat[bucket]; - } - } - - /** - * Heartbeat ordinal for the given app. This is typically the heartbeat at which - * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run - * jobs in a long time is immediately runnable even if the app is bucketed into - * an infrequent time allocation. - */ - public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, - final int appStandbyBucket) { - if (appStandbyBucket == 0 || - appStandbyBucket >= mConstants.STANDBY_BEATS.length) { - // ACTIVE => everything can be run right away - // NEVER => we won't run them anyway, so let them go in the future - // as soon as the app enters normal use - if (DEBUG_STANDBY) { - Slog.v(TAG, "Base heartbeat forced ZERO for new job in " - + packageName + "/" + userId); - } - return 0; - } - - final long baseHeartbeat = heartbeatWhenJobsLastRun(packageName, userId); - if (DEBUG_STANDBY) { - Slog.v(TAG, "Base heartbeat " + baseHeartbeat + " for new job in " - + packageName + "/" + userId); - } - return baseHeartbeat; - } - - public void noteJobStart(String packageName, int userId) { - synchronized (mLock) { - setLastJobHeartbeatLocked(packageName, userId, mHeartbeat); - } - } - /** * Returns a list of all pending jobs. A running job is not considered pending. Periodic * jobs are always considered pending. @@ -3158,12 +2839,6 @@ public class JobSchedulerService extends com.android.server.SystemService } } - long getCurrentHeartbeat() { - synchronized (mLock) { - return mHeartbeat; - } - } - // Shell command infrastructure int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) { try { @@ -3249,21 +2924,6 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; } - // Shell command infrastructure - int executeHeartbeatCommand(PrintWriter pw, int numBeats) { - if (numBeats < 1) { - pw.println(getCurrentHeartbeat()); - return 0; - } - - pw.print("Advancing standby heartbeat by "); - pw.println(numBeats); - synchronized (mLock) { - advanceHeartbeatLocked(numBeats); - } - return 0; - } - void triggerDockState(boolean idleState) { final Intent dockIntent; if (idleState) { @@ -3319,20 +2979,6 @@ public class JobSchedulerService extends com.android.server.SystemService } pw.println(); - pw.println(" Heartbeat:"); - pw.print(" Current: "); pw.println(mHeartbeat); - pw.println(" Next"); - pw.print(" ACTIVE: "); pw.println(mNextBucketHeartbeat[0]); - pw.print(" WORKING: "); pw.println(mNextBucketHeartbeat[1]); - pw.print(" FREQUENT: "); pw.println(mNextBucketHeartbeat[2]); - pw.print(" RARE: "); pw.println(mNextBucketHeartbeat[3]); - pw.print(" Last heartbeat: "); - TimeUtils.formatDuration(mLastHeartbeatTime, nowElapsed, pw); - pw.println(); - pw.print(" Next heartbeat: "); - TimeUtils.formatDuration(mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME, - nowElapsed, pw); - pw.println(); pw.print(" In parole?: "); pw.print(mInParole); pw.println(); @@ -3358,9 +3004,6 @@ public class JobSchedulerService extends com.android.server.SystemService } job.dump(pw, " ", true, nowElapsed); - pw.print(" Last run heartbeat: "); - pw.print(heartbeatWhenJobsLastRun(job)); - pw.println(); pw.print(" Ready: "); pw.print(isReadyToBeExecutedLocked(job)); @@ -3514,15 +3157,6 @@ public class JobSchedulerService extends com.android.server.SystemService } proto.end(settingsToken); - proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[2]); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[3]); - proto.write(JobSchedulerServiceDumpProto.LAST_HEARTBEAT_TIME_MILLIS, - mLastHeartbeatTime - nowUptime); - proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS, - mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime); proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole); proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint); @@ -3564,7 +3198,6 @@ public class JobSchedulerService extends com.android.server.SystemService } proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_PRESENT, componentPresent); - proto.write(RegisteredJob.LAST_RUN_HEARTBEAT, heartbeatWhenJobsLastRun(job)); proto.end(rjToken); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index e3614413121af..01d158ba9452f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -340,15 +340,8 @@ public final class JobSchedulerShellCommand extends ShellCommand { private int doHeartbeat(PrintWriter pw) throws Exception { checkPermission("manipulate scheduler heartbeat"); - final String arg = getNextArg(); - final int numBeats = (arg != null) ? Integer.parseInt(arg) : 0; - - final long ident = Binder.clearCallingIdentity(); - try { - return mInternal.executeHeartbeatCommand(pw, numBeats); - } finally { - Binder.restoreCallingIdentity(ident); - } + pw.println("Heartbeat command is no longer supported"); + return -1; } private int triggerDockState(PrintWriter pw) throws Exception { @@ -401,8 +394,7 @@ public final class JobSchedulerShellCommand extends ShellCommand { pw.println(" -u or --user: specify which user's job is to be run; the default is"); pw.println(" the primary or system user"); pw.println(" heartbeat [num]"); - pw.println(" With no argument, prints the current standby heartbeat. With a positive"); - pw.println(" argument, advances the standby heartbeat by that number."); + pw.println(" No longer used."); pw.println(" monitor-battery [on|off]"); pw.println(" Control monitoring of all battery changes. Off by default. Turning"); pw.println(" on makes get-battery-seq useful."); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 7da128f9d3ecc..4d9f1331e6ff9 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -285,9 +285,6 @@ public final class JobServiceContext implements ServiceConnection { UsageStatsManagerInternal usageStats = LocalServices.getService(UsageStatsManagerInternal.class); usageStats.setLastJobRunTime(jobPackage, jobUserId, mExecutionStartTimeElapsed); - JobSchedulerInternal jobScheduler = - LocalServices.getService(JobSchedulerInternal.class); - jobScheduler.noteJobStart(jobPackage, jobUserId); mAvailable = false; mStoppedReason = null; mStoppedTime = 0; diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index d69faf37397ce..4321fc716b4d0 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -189,7 +189,7 @@ public final class JobStore { if (utcTimes != null) { Pair elapsedRuntimes = convertRtcBoundsToElapsed(utcTimes, elapsedNow); - JobStatus newJob = new JobStatus(job, job.getBaseHeartbeat(), + JobStatus newJob = new JobStatus(job, elapsedRuntimes.first, elapsedRuntimes.second, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime()); newJob.prepareLocked(am); @@ -944,10 +944,9 @@ public final class JobStore { JobSchedulerInternal service = LocalServices.getService(JobSchedulerInternal.class); final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName, sourceUserId, elapsedNow); - long currentHeartbeat = service != null ? service.currentHeartbeat() : 0; JobStatus js = new JobStatus( jobBuilder.build(), uid, sourcePackageName, sourceUserId, - appBucket, currentHeartbeat, sourceTag, + appBucket, sourceTag, elapsedRuntimes.first, elapsedRuntimes.second, lastSuccessfulRunTime, lastFailedRunTime, (rtcIsGood) ? null : rtcRuntimes, internalFlags); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index f8cf6ae049505..a67aadfc69590 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -47,7 +47,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobSchedulerService.Constants; -import com.android.server.job.JobServiceContext; import com.android.server.job.StateControllerProto; import com.android.server.net.NetworkPolicyManagerInternal; @@ -88,8 +87,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") private final ArraySet mAvailableNetworks = new ArraySet<>(); - private boolean mUseQuotaLimit; - private static final int MSG_DATA_SAVER_TOGGLED = 0; private static final int MSG_UID_RULES_CHANGES = 1; private static final int MSG_REEVALUATE_JOBS = 2; @@ -110,8 +107,6 @@ public final class ConnectivityController extends StateController implements mConnManager.registerNetworkCallback(request, mNetworkCallback); mNetPolicyManager.registerListener(mNetPolicyListener); - - mUseQuotaLimit = !mConstants.USE_HEARTBEATS; } @GuardedBy("mLock") @@ -142,24 +137,6 @@ public final class ConnectivityController extends StateController implements } } - @GuardedBy("mLock") - @Override - public void onConstantsUpdatedLocked() { - if (mConstants.USE_HEARTBEATS) { - // App idle exceptions are only requested for the rolling quota system. - if (DEBUG) Slog.i(TAG, "Revoking all standby exceptions"); - for (int i = 0; i < mRequestedWhitelistJobs.size(); ++i) { - int uid = mRequestedWhitelistJobs.keyAt(i); - mNetPolicyManagerInternal.setAppIdleWhitelist(uid, false); - } - mRequestedWhitelistJobs.clear(); - } - if (mUseQuotaLimit == mConstants.USE_HEARTBEATS) { - mUseQuotaLimit = !mConstants.USE_HEARTBEATS; - mHandler.obtainMessage(MSG_REEVALUATE_JOBS).sendToTarget(); - } - } - /** * Returns true if the job's requested network is available. This DOES NOT necesarilly mean * that the UID has been granted access to the network. @@ -237,11 +214,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override public void evaluateStateLocked(JobStatus jobStatus) { - if (mConstants.USE_HEARTBEATS) { - // This should only be used for the rolling quota system. - return; - } - if (!jobStatus.hasConnectivityConstraint()) { return; } @@ -263,9 +235,6 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override public void reevaluateStateLocked(final int uid) { - if (mConstants.USE_HEARTBEATS) { - return; - } // Check if we still need a connectivity exception in case the JobService was disabled. ArraySet jobs = mTrackedJobs.get(uid); if (jobs == null) { @@ -329,9 +298,7 @@ public final class ConnectivityController extends StateController implements */ private boolean isInsane(JobStatus jobStatus, Network network, NetworkCapabilities capabilities, Constants constants) { - final long maxJobExecutionTimeMs = mUseQuotaLimit - ? mService.getMaxJobExecutionTimeMs(jobStatus) - : JobServiceContext.EXECUTING_TIMESLICE_MILLIS; + final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus); final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes(); if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { @@ -617,7 +584,6 @@ public final class ConnectivityController extends StateController implements @Override public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate predicate) { - pw.print("mUseQuotaLimit="); pw.println(mUseQuotaLimit); if (mRequestedWhitelistJobs.size() > 0) { pw.print("Requested standby exceptions:"); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index 6f2b334538917..ae4abd65ab60f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -168,12 +168,6 @@ public final class JobStatus { /** How many times this job has failed, used to compute back-off. */ private final int numFailures; - /** - * Current standby heartbeat when this job was scheduled or last ran. Used to - * pin the runnability check regardless of the job's app moving between buckets. - */ - private final long baseHeartbeat; - /** * Which app standby bucket this job's app is in. Updated when the app is moved to a * different bucket. @@ -350,8 +344,6 @@ public final class JobStatus { * @param standbyBucket The standby bucket that the source package is currently assigned to, * cached here for speed of handling during runnability evaluations (and updated when bucket * assignments are changed) - * @param heartbeat Timestamp of when the job was created, in the standby-related - * timebase. * @param tag A string associated with the job for debugging/logging purposes. * @param numFailures Count of how many times this job has requested a reschedule because * its work was not yet finished. @@ -364,13 +356,12 @@ public final class JobStatus { * @param internalFlags Non-API property flags about this job */ private JobStatus(JobInfo job, int callingUid, String sourcePackageName, - int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures, + int sourceUserId, int standbyBucket, String tag, int numFailures, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) { this.job = job; this.callingUid = callingUid; this.standbyBucket = standbyBucket; - this.baseHeartbeat = heartbeat; int tempSourceUid = -1; if (sourceUserId != -1 && sourcePackageName != null) { @@ -440,7 +431,7 @@ public final class JobStatus { public JobStatus(JobStatus jobStatus) { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), - jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(), + jobStatus.getStandbyBucket(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(), @@ -462,13 +453,13 @@ public final class JobStatus { * standby bucket is whatever the OS thinks it should be at this moment. */ public JobStatus(JobInfo job, int callingUid, String sourcePkgName, int sourceUserId, - int standbyBucket, long baseHeartbeat, String sourceTag, + int standbyBucket, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime, Pair persistedExecutionTimesUTC, int innerFlags) { this(job, callingUid, sourcePkgName, sourceUserId, - standbyBucket, baseHeartbeat, + standbyBucket, sourceTag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, innerFlags); @@ -486,13 +477,13 @@ public final class JobStatus { } /** Create a new job to be rescheduled with the provided parameters. */ - public JobStatus(JobStatus rescheduling, long newBaseHeartbeat, + public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis, long newLatestRuntimeElapsedMillis, int backoffAttempt, long lastSuccessfulRunTime, long lastFailedRunTime) { this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(), - rescheduling.getStandbyBucket(), newBaseHeartbeat, + rescheduling.getStandbyBucket(), rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags()); @@ -529,11 +520,8 @@ public final class JobStatus { int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage, sourceUserId, elapsedNow); JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); - long currentHeartbeat = js != null - ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket) - : 0; return new JobStatus(job, callingUid, sourcePkg, sourceUserId, - standbyBucket, currentHeartbeat, tag, 0, + standbyBucket, tag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, /*innerFlags=*/ 0); @@ -714,10 +702,6 @@ public final class JobStatus { return standbyBucket; } - public long getBaseHeartbeat() { - return baseHeartbeat; - } - public void setStandbyBucket(int newBucket) { standbyBucket = newBucket; } @@ -1631,10 +1615,6 @@ public final class JobStatus { } pw.print(prefix); pw.print("Standby bucket: "); pw.println(getBucketName()); - if (standbyBucket > 0) { - pw.print(prefix); pw.print("Base heartbeat: "); - pw.println(baseHeartbeat); - } if (whenStandbyDeferred != 0) { pw.print(prefix); pw.print(" Deferred since: "); TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw); 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 b8cfac4d42064..043cda469db27 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 @@ -416,13 +416,6 @@ public final class QuotaController extends StateController { private volatile boolean mInParole; - /** - * If the QuotaController should throttle apps based on their standby bucket and job activity. - * If false, all jobs will have their CONSTRAINT_WITHIN_QUOTA bit set to true immediately and - * indefinitely. - */ - private boolean mShouldThrottle; - /** How much time each app will have to run jobs within their standby bucket window. */ private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS; @@ -594,8 +587,6 @@ public final class QuotaController extends StateController { } catch (RemoteException e) { // ignored; both services live in system_server } - - mShouldThrottle = !mConstants.USE_HEARTBEATS; } @Override @@ -607,8 +598,6 @@ public final class QuotaController extends StateController { public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { final int userId = jobStatus.getSourceUserId(); final String pkgName = jobStatus.getSourcePackageName(); - // Still need to track jobs even if mShouldThrottle is false in case it's set to true at - // some point. ArraySet jobs = mTrackedJobs.get(userId, pkgName); if (jobs == null) { jobs = new ArraySet<>(); @@ -616,16 +605,10 @@ public final class QuotaController extends StateController { } jobs.add(jobStatus); jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA); - if (mShouldThrottle) { - final boolean isWithinQuota = isWithinQuotaLocked(jobStatus); - setConstraintSatisfied(jobStatus, isWithinQuota); - if (!isWithinQuota) { - maybeScheduleStartAlarmLocked(userId, pkgName, - getEffectiveStandbyBucket(jobStatus)); - } - } else { - // QuotaController isn't throttling, so always set to true. - jobStatus.setQuotaConstraintSatisfied(true); + final boolean isWithinQuota = isWithinQuotaLocked(jobStatus); + setConstraintSatisfied(jobStatus, isWithinQuota); + if (!isWithinQuota) { + maybeScheduleStartAlarmLocked(userId, pkgName, getEffectiveStandbyBucket(jobStatus)); } } @@ -673,20 +656,6 @@ public final class QuotaController extends StateController { } } - @Override - public void onConstantsUpdatedLocked() { - if (mShouldThrottle == mConstants.USE_HEARTBEATS) { - mShouldThrottle = !mConstants.USE_HEARTBEATS; - - // Update job bookkeeping out of band. - BackgroundThread.getHandler().post(() -> { - synchronized (mLock) { - maybeUpdateAllConstraintsLocked(); - } - }); - } - } - @Override public void onAppRemovedLocked(String packageName, int uid) { if (packageName == null) { @@ -780,8 +749,6 @@ public final class QuotaController extends StateController { boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { if (standbyBucket == NEVER_INDEX) return false; - // This check is needed in case the flag is toggled after a job has been registered. - if (!mShouldThrottle) return true; // Quota constraint is not enforced while charging or when parole is on. if (mChargeTracker.isCharging() || mInParole) { @@ -1820,8 +1787,7 @@ public final class QuotaController extends StateController { if (timer != null && timer.isActive()) { timer.rescheduleCutoff(); } - if (!mShouldThrottle || maybeUpdateConstraintForPkgLocked(userId, - packageName)) { + if (maybeUpdateConstraintForPkgLocked(userId, packageName)) { mStateChangedListener.onControllerStateChanged(); } } @@ -2396,7 +2362,7 @@ public final class QuotaController extends StateController { changed = true; } - if (changed && mShouldThrottle) { + if (changed) { // Update job bookkeeping out of band. BackgroundThread.getHandler().post(() -> { synchronized (mLock) { @@ -2561,7 +2527,6 @@ public final class QuotaController extends StateController { @Override public void dumpControllerStateLocked(final IndentingPrintWriter pw, final Predicate predicate) { - pw.println("Is throttling: " + mShouldThrottle); pw.println("Is charging: " + mChargeTracker.isCharging()); pw.println("In parole: " + mInParole); pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis()); diff --git a/core/java/com/android/server/job/JobSchedulerInternal.java b/core/java/com/android/server/job/JobSchedulerInternal.java index 425ec473bc8e1..dbf3b984d5fe4 100644 --- a/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/core/java/com/android/server/job/JobSchedulerInternal.java @@ -16,7 +16,6 @@ package com.android.server.job; -import android.annotation.UserIdInt; import android.app.job.JobInfo; import java.util.List; @@ -27,31 +26,6 @@ import java.util.List; */ public interface JobSchedulerInternal { - // Bookkeeping about app standby bucket scheduling - - /** - * The current bucket heartbeat ordinal - */ - long currentHeartbeat(); - - /** - * Heartbeat ordinal at which the given standby bucket's jobs next become runnable - */ - long nextHeartbeatForBucket(int bucket); - - /** - * Heartbeat ordinal for the given app. This is typically the heartbeat at which - * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run - * jobs in a long time is immediately runnable even if the app is bucketed into - * an infrequent time allocation. - */ - public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket); - - /** - * Tell the scheduler when a JobServiceContext starts running a job in an app - */ - void noteJobStart(String packageName, int userId); - /** * Returns a list of pending jobs scheduled by the system service. */ diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index c534aa4195951..5d4be55021385 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -38,10 +38,10 @@ message JobSchedulerServiceDumpProto { optional ConstantsProto settings = 1; - optional int32 current_heartbeat = 14; - repeated int32 next_heartbeat = 15; - optional int64 last_heartbeat_time_millis = 16; - optional int64 next_heartbeat_time_millis = 17; + reserved 14; // current_heartbeat + reserved 15; // next_heartbeat + reserved 16; // last_heartbeat_time_millis + reserved 17; // next_heartbeat_time_millis optional bool in_parole = 18; optional bool in_thermal = 19; @@ -64,7 +64,7 @@ message JobSchedulerServiceDumpProto { optional bool is_uid_backing_up = 7; optional bool is_component_present = 8; - optional int64 last_run_heartbeat = 9; + reserved 9; // last_run_heartbeat } repeated RegisteredJob registered_jobs = 3; @@ -214,13 +214,13 @@ message ConstantsProto { // assignment. This should be prime relative to common time interval lengths // such as a quarter-hour or day, so that the heartbeat drifts relative to // wall-clock milestones. - optional int64 standby_heartbeat_time_ms = 19; + reserved 19; // standby_heartbeat_time_ms // Mapping: standby bucket -> number of heartbeats between each sweep of // that bucket's jobs. // Bucket assignments as recorded in the JobStatus objects are normalized to // be indices into this array, rather than the raw constants used by // AppIdleHistory. - repeated int32 standby_beats = 20; + reserved 20; // standby_beats // The fraction of a job's running window that must pass before we // consider running it when the network is congested. optional double conn_congestion_delay_frac = 21; @@ -229,7 +229,7 @@ message ConstantsProto { optional double conn_prefetch_relax_frac = 22; // Whether to use heartbeats or rolling window for quota management. True // will use heartbeats, false will use a rolling window. - optional bool use_heartbeats = 23; + reserved 23; // use_heartbeats message QuotaController { option (.android.msg_privacy).dest = DEST_AUTOMATIC; diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 328e8f41f5e20..1c88c40c3e2ba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -399,23 +399,8 @@ public class ConnectivityControllerTest { assertTrue(controller.wouldBeReadyWithConnectivityLocked(red)); } - @Test - public void testEvaluateStateLocked_HeartbeatsOn() { - mConstants.USE_HEARTBEATS = true; - final ConnectivityController controller = new ConnectivityController(mService); - final JobStatus red = createJobStatus(createJob() - .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED); - - controller.evaluateStateLocked(red); - assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED)); - verify(mNetPolicyManagerInternal, never()) - .setAppIdleWhitelist(eq(UID_RED), anyBoolean()); - } - @Test public void testEvaluateStateLocked_JobWithoutConnectivity() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = new ConnectivityController(mService); final JobStatus red = createJobStatus(createJob().setMinimumLatency(1)); @@ -427,7 +412,6 @@ public class ConnectivityControllerTest { @Test public void testEvaluateStateLocked_JobWouldBeReady() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(any()); final JobStatus red = createJobStatus(createJob() @@ -466,7 +450,6 @@ public class ConnectivityControllerTest { @Test public void testEvaluateStateLocked_JobWouldNotBeReady() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(any()); final JobStatus red = createJobStatus(createJob() @@ -502,7 +485,6 @@ public class ConnectivityControllerTest { @Test public void testReevaluateStateLocked() { - mConstants.USE_HEARTBEATS = false; final ConnectivityController controller = spy(new ConnectivityController(mService)); final JobStatus redOne = createJobStatus(createJob(1) .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) @@ -625,7 +607,7 @@ public class ConnectivityControllerTest { private static JobStatus createJobStatus(JobInfo.Builder job, int uid, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) { - return new JobStatus(job.build(), uid, null, -1, 0, 0, null, + return new JobStatus(job.build(), uid, null, -1, 0, null, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index 94e02d3b2648c..64da6f6b85907 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -573,7 +573,7 @@ public class JobStatusTest { long latestRunTimeElapsedMillis) { final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar")) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build(); - return new JobStatus(job, 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis, + return new JobStatus(job, 0, null, -1, 0, null, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0); } 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 2d702312a62b6..8863d5abeca36 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 @@ -107,7 +107,6 @@ public class QuotaControllerTest { private static final int SOURCE_USER_ID = 0; private BroadcastReceiver mChargingReceiver; - private Constants mJsConstants; private QuotaController mQuotaController; private QuotaController.QcConstants mQcConstants; private int mSourceUid; @@ -134,14 +133,11 @@ public class QuotaControllerTest { .strictness(Strictness.LENIENT) .mockStatic(LocalServices.class) .startMocking(); - // Make sure constants turn on QuotaController. - mJsConstants = new Constants(); - mJsConstants.USE_HEARTBEATS = false; // Called in StateController constructor. when(mJobSchedulerService.getTestableContext()).thenReturn(mContext); when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService); - when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants); + when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class)); // Called in QuotaController constructor. IActivityManager activityManager = ActivityManager.getService(); spyOn(activityManager); @@ -1809,30 +1805,6 @@ public class QuotaControllerTest { .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } - /** Tests that QuotaController doesn't throttle if throttling is turned off. */ - @Test - public void testThrottleToggling() throws Exception { - setDischarging(); - mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, - createTimingSession( - JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS, - 10 * MINUTE_IN_MILLIS, 4)); - JobStatus jobStatus = createJobStatus("testThrottleToggling", 1); - setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window - mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); - assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - - mJsConstants.USE_HEARTBEATS = true; - mQuotaController.onConstantsUpdatedLocked(); - Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. - assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - - mJsConstants.USE_HEARTBEATS = false; - mQuotaController.onConstantsUpdatedLocked(); - Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. - assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - } - @Test public void testConstantsUpdating_ValidValues() { mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS; diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 0309dbeea2ca1..cae7b57580bb2 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -273,7 +273,7 @@ public class JobStoreTest { invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period). final Pair persistedExecutionTimesUTC = new Pair<>(rtcNow, rtcNow + ONE_HOUR); final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", - 0 /* sourceUserId */, 0, 0, "someTag", + 0 /* sourceUserId */, 0, "someTag", invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, persistedExecutionTimesUTC, 0 /* innerFlagg */);