Loading apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +2 −1 Original line number Diff line number Diff line Loading @@ -1769,7 +1769,8 @@ public final class ConnectivityController extends RestrictingController implemen @VisibleForTesting class CcConfig { private boolean mFlexIsEnabled = FlexibilityController.FcConfig.DEFAULT_FLEXIBILITY_ENABLED; private boolean mFlexIsEnabled = FlexibilityController.FcConfig.DEFAULT_APPLIED_CONSTRAINTS != 0; private boolean mShouldReprocessNetworkCapabilities = false; /** Loading apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +124 −61 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NOT_LOW; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CONNECTIVITY; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_FLEXIBLE; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_IDLE; import android.annotation.ElapsedRealtimeLong; Loading Loading @@ -74,17 +73,10 @@ public final class FlexibilityController extends StateController { private static final int JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS = CONSTRAINT_CONNECTIVITY; /** List of all flexible constraints. */ private static final int FLEXIBLE_CONSTRAINTS = @VisibleForTesting static final int FLEXIBLE_CONSTRAINTS = JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS | SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; private static final int NUM_JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS = Integer.bitCount(JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS); static final int NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS = Integer.bitCount(SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS); static final int NUM_FLEXIBLE_CONSTRAINTS = Integer.bitCount(FLEXIBLE_CONSTRAINTS); private static final long NO_LIFECYCLE_END = Long.MAX_VALUE; /** Loading @@ -100,9 +92,15 @@ public final class FlexibilityController extends StateController { private long mUnseenConstraintGracePeriodMs = FcConfig.DEFAULT_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS; @VisibleForTesting /** Set of constraints supported on this device for flex scheduling. */ private final int mSupportedFlexConstraints; @GuardedBy("mLock") private boolean mFlexibilityEnabled; /** Set of constraints that will be used in the flex policy. */ @GuardedBy("mLock") boolean mFlexibilityEnabled = FcConfig.DEFAULT_FLEXIBILITY_ENABLED; private int mAppliedConstraints = FcConfig.DEFAULT_APPLIED_CONSTRAINTS; private long mMinTimeBetweenFlexibilityAlarmsMs = FcConfig.DEFAULT_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS; Loading @@ -118,9 +116,6 @@ public final class FlexibilityController extends StateController { */ private int[] mPercentToDropConstraints; @VisibleForTesting boolean mDeviceSupportsFlexConstraints; /** * Keeps track of what flexible constraints are satisfied at the moment. * Is updated by the other controllers. Loading Loading @@ -178,7 +173,7 @@ public final class FlexibilityController extends StateController { if (!js.hasFlexibilityConstraint()) { continue; } mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); } } Loading @@ -186,15 +181,23 @@ public final class FlexibilityController extends StateController { }; private static final int MSG_UPDATE_JOBS = 0; private static final int MSG_UPDATE_JOB = 1; public FlexibilityController( JobSchedulerService service, PrefetchController prefetchController) { super(service); mHandler = new FcHandler(AppSchedulingModuleThread.get().getLooper()); mDeviceSupportsFlexConstraints = !mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_AUTOMOTIVE); mFlexibilityEnabled &= mDeviceSupportsFlexConstraints; mFlexibilityTracker = new FlexibilityTracker(NUM_FLEXIBLE_CONSTRAINTS); if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) || mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED)) { // Embedded devices have no user-installable apps. Assume all jobs are critical // and can't be flexed. mSupportedFlexConstraints = 0; } else { // TODO(236261941): handle devices without a battery mSupportedFlexConstraints = FLEXIBLE_CONSTRAINTS; } mFlexibilityEnabled = (mAppliedConstraints & mSupportedFlexConstraints) != 0; mFlexibilityTracker = new FlexibilityTracker(Integer.bitCount(mSupportedFlexConstraints)); mFcConfig = new FcConfig(); mFlexibilityAlarmQueue = new FlexibilityAlarmQueue( mContext, AppSchedulingModuleThread.get().getLooper()); Loading @@ -218,10 +221,12 @@ public final class FlexibilityController extends StateController { public void maybeStartTrackingJobLocked(JobStatus js, JobStatus lastJob) { if (js.hasFlexibilityConstraint()) { final long nowElapsed = sElapsedRealtimeClock.millis(); if (!mDeviceSupportsFlexConstraints) { if (mSupportedFlexConstraints == 0) { js.setFlexibilityConstraintSatisfied(nowElapsed, true); return; } js.setNumAppliedFlexibleConstraints( Integer.bitCount(getRelevantAppliedConstraintsLocked(js))); js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js)); mFlexibilityTracker.add(js); js.setTrackingController(JobStatus.TRACKING_FLEXIBILITY); Loading Loading @@ -266,6 +271,14 @@ public final class FlexibilityController extends StateController { || mService.isCurrentlyRunningLocked(js); } @VisibleForTesting @GuardedBy("mLock") int getRelevantAppliedConstraintsLocked(@NonNull JobStatus js) { final int relevantConstraints = SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS | (js.canApplyTransportAffinities() ? CONSTRAINT_CONNECTIVITY : 0); return mAppliedConstraints & relevantConstraints; } /** * Returns whether there are enough constraints satisfied to allow running the job from flex's * perspective. This takes into account unseen constraint combinations and expectations around Loading @@ -274,7 +287,7 @@ public final class FlexibilityController extends StateController { @VisibleForTesting @GuardedBy("mLock") boolean hasEnoughSatisfiedConstraintsLocked(@NonNull JobStatus js) { final int satisfiedConstraints = mSatisfiedFlexibleConstraints final int satisfiedConstraints = mSatisfiedFlexibleConstraints & mAppliedConstraints & (SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS | (js.areTransportAffinitiesSatisfied() ? CONSTRAINT_CONNECTIVITY : 0)); final int numSatisfied = Integer.bitCount(satisfiedConstraints); Loading @@ -296,8 +309,7 @@ public final class FlexibilityController extends StateController { // count have not been seen recently enough, then assume they won't be seen anytime soon, // so don't force the job to wait longer. If any combinations with a higher count have been // seen recently, then the job can potentially wait for those combinations. final int irrelevantConstraints = ~(SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS | (js.canApplyTransportAffinities() ? CONSTRAINT_CONNECTIVITY : 0)); final int irrelevantConstraints = ~getRelevantAppliedConstraintsLocked(js); for (int i = mLastSeenConstraintTimesElapsed.size() - 1; i >= 0; --i) { final int constraints = mLastSeenConstraintTimesElapsed.keyAt(i); if ((constraints & irrelevantConstraints) != 0) { Loading Loading @@ -515,9 +527,9 @@ public final class FlexibilityController extends StateController { for (int j = 0; j < mFlexibilityTracker.size(); j++) { final ArraySet<JobStatus> jobs = mFlexibilityTracker .getJobsByNumRequiredConstraints(j); for (int i = 0; i < jobs.size(); i++) { for (int i = jobs.size() - 1; i >= 0; --i) { JobStatus js = jobs.valueAt(i); mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); mFlexibilityTracker.updateFlexibleConstraints(js, nowElapsed); mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); if (js.setFlexibilityConstraintSatisfied( nowElapsed, isFlexibilitySatisfiedLocked(js))) { Loading Loading @@ -579,18 +591,46 @@ public final class FlexibilityController extends StateController { mTrackedJobs.get(js.getNumRequiredFlexibleConstraints()).remove(js); } public void resetJobNumDroppedConstraints(JobStatus js, long nowElapsed) { /** * Updates applied and dropped constraints for the job. */ public void updateFlexibleConstraints(JobStatus js, long nowElapsed) { final int prevNumRequired = js.getNumRequiredFlexibleConstraints(); final int numAppliedConstraints = Integer.bitCount(getRelevantAppliedConstraintsLocked(js)); js.setNumAppliedFlexibleConstraints(numAppliedConstraints); final int curPercent = getCurPercentOfLifecycleLocked(js, nowElapsed); int toDrop = 0; final int jsMaxFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (js.canApplyTransportAffinities() ? 1 : 0); for (int i = 0; i < numAppliedConstraints; i++) { if (curPercent >= mPercentToDropConstraints[i]) { toDrop++; } } js.setNumDroppedFlexibleConstraints(toDrop); if (prevNumRequired == js.getNumRequiredFlexibleConstraints()) { return; } mTrackedJobs.get(prevNumRequired).remove(js); add(js); } /** * Calculates the number of constraints that should be dropped for the job, based on how * far along the job is into its lifecycle. */ public void calculateNumDroppedConstraints(JobStatus js, long nowElapsed) { final int curPercent = getCurPercentOfLifecycleLocked(js, nowElapsed); int toDrop = 0; final int jsMaxFlexibleConstraints = js.getNumAppliedFlexibleConstraints(); for (int i = 0; i < jsMaxFlexibleConstraints; i++) { if (curPercent >= mPercentToDropConstraints[i]) { toDrop++; } } adjustJobsRequiredConstraints( js, js.getNumDroppedFlexibleConstraints() - toDrop, nowElapsed); setNumDroppedFlexibleConstraints(js, toDrop); } /** Returns all tracked jobs. */ Loading @@ -599,17 +639,14 @@ public final class FlexibilityController extends StateController { } /** * Adjusts number of required flexible constraints and sorts it into the tracker. * Returns false if the job status's number of flexible constraints is now 0. * Updates the number of dropped flexible constraints and sorts it into the tracker. */ public boolean adjustJobsRequiredConstraints(JobStatus js, int adjustBy, long nowElapsed) { if (adjustBy != 0) { public void setNumDroppedFlexibleConstraints(JobStatus js, int numDropped) { if (numDropped != js.getNumDroppedFlexibleConstraints()) { remove(js); js.adjustNumRequiredFlexibleConstraints(adjustBy); js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js)); js.setNumDroppedFlexibleConstraints(numDropped); add(js); } return js.getNumRequiredFlexibleConstraints() > 0; } public int size() { Loading Loading @@ -658,8 +695,10 @@ public final class FlexibilityController extends StateController { if (DEBUG) { Slog.d(TAG, "scheduleDropNumConstraintsAlarm: " + js.getSourcePackageName() + " " + js.getSourceUserId() + " numApplied: " + js.getNumAppliedFlexibleConstraints() + " numRequired: " + js.getNumRequiredFlexibleConstraints() + " numSatisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints) + " numSatisfied: " + Integer.bitCount( mSatisfiedFlexibleConstraints & getRelevantAppliedConstraintsLocked(js)) + " curTime: " + nowElapsed + " earliest: " + earliest + " latest: " + latest Loading @@ -669,8 +708,9 @@ public final class FlexibilityController extends StateController { if (DEBUG) { Slog.d(TAG, "deadline proximity met: " + js); } mFlexibilityTracker.adjustJobsRequiredConstraints(js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); mFlexibilityTracker.setNumDroppedFlexibleConstraints(js, js.getNumAppliedFlexibleConstraints()); mHandler.obtainMessage(MSG_UPDATE_JOB, js).sendToTarget(); return; } if (nextTimeElapsed == NO_LIFECYCLE_END) { Loading @@ -696,12 +736,15 @@ public final class FlexibilityController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); for (int i = 0; i < expired.size(); i++) { JobStatus js = expired.valueAt(i); boolean wasFlexibilitySatisfied = js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE); if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed)) { if (DEBUG) { Slog.d(TAG, "Alarm fired for " + js.toShortString()); } mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); if (js.getNumRequiredFlexibleConstraints() > 0) { scheduleDropNumConstraintsAlarm(js, nowElapsed); } if (wasFlexibilitySatisfied != js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE)) { if (js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js))) { changedJobs.add(js); } } Loading @@ -725,7 +768,9 @@ public final class FlexibilityController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); final ArraySet<JobStatus> changedJobs = new ArraySet<>(); for (int o = 0; o <= NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; ++o) { final int numAppliedSystemWideConstraints = Integer.bitCount( mAppliedConstraints & SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS); for (int o = 0; o <= numAppliedSystemWideConstraints; ++o) { final ArraySet<JobStatus> jobsByNumConstraints = mFlexibilityTracker .getJobsByNumRequiredConstraints(o); Loading @@ -744,6 +789,23 @@ public final class FlexibilityController extends StateController { } } break; case MSG_UPDATE_JOB: synchronized (mLock) { final JobStatus js = (JobStatus) msg.obj; if (DEBUG) { Slog.d("blah", "Checking on " + js.toShortString()); } final long nowElapsed = sElapsedRealtimeClock.millis(); if (js.setFlexibilityConstraintSatisfied( nowElapsed, isFlexibilitySatisfiedLocked(js))) { // TODO(141645789): add method that will take a single job ArraySet<JobStatus> changedJob = new ArraySet<>(); changedJob.add(js); mStateChangedListener.onControllerStateChanged(changedJob); } } break; } } } Loading @@ -754,7 +816,8 @@ public final class FlexibilityController extends StateController { /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */ private static final String FC_CONFIG_PREFIX = "fc_"; static final String KEY_FLEXIBILITY_ENABLED = FC_CONFIG_PREFIX + "enable_flexibility"; @VisibleForTesting static final String KEY_APPLIED_CONSTRAINTS = FC_CONFIG_PREFIX + "applied_constraints"; static final String KEY_DEADLINE_PROXIMITY_LIMIT = FC_CONFIG_PREFIX + "flexibility_deadline_proximity_limit_ms"; static final String KEY_FALLBACK_FLEXIBILITY_DEADLINE = Loading @@ -770,7 +833,7 @@ public final class FlexibilityController extends StateController { static final String KEY_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS = FC_CONFIG_PREFIX + "unseen_constraint_grace_period_ms"; static final boolean DEFAULT_FLEXIBILITY_ENABLED = false; static final int DEFAULT_APPLIED_CONSTRAINTS = 0; @VisibleForTesting static final long DEFAULT_DEADLINE_PROXIMITY_LIMIT_MS = 15 * MINUTE_IN_MILLIS; @VisibleForTesting Loading @@ -783,11 +846,8 @@ public final class FlexibilityController extends StateController { @VisibleForTesting static final long DEFAULT_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS = 3 * DAY_IN_MILLIS; /** * If false the controller will not track new jobs * and the flexibility constraint will always be satisfied. */ public boolean FLEXIBILITY_ENABLED = DEFAULT_FLEXIBILITY_ENABLED; /** Which constraints to apply/consider in flex policy. */ public int APPLIED_CONSTRAINTS = DEFAULT_APPLIED_CONSTRAINTS; /** How close to a jobs' deadline all flexible constraints will be dropped. */ public long DEADLINE_PROXIMITY_LIMIT_MS = DEFAULT_DEADLINE_PROXIMITY_LIMIT_MS; /** For jobs that lack a deadline, the time that will be used to drop all constraints by. */ Loading @@ -811,16 +871,19 @@ public final class FlexibilityController extends StateController { public void processConstantLocked(@NonNull DeviceConfig.Properties properties, @NonNull String key) { switch (key) { case KEY_FLEXIBILITY_ENABLED: FLEXIBILITY_ENABLED = properties.getBoolean(key, DEFAULT_FLEXIBILITY_ENABLED) && mDeviceSupportsFlexConstraints; if (mFlexibilityEnabled != FLEXIBILITY_ENABLED) { mFlexibilityEnabled = FLEXIBILITY_ENABLED; case KEY_APPLIED_CONSTRAINTS: APPLIED_CONSTRAINTS = properties.getInt(key, DEFAULT_APPLIED_CONSTRAINTS) & mSupportedFlexConstraints; if (mAppliedConstraints != APPLIED_CONSTRAINTS) { mAppliedConstraints = APPLIED_CONSTRAINTS; mShouldReevaluateConstraints = true; if (mFlexibilityEnabled) { if (mAppliedConstraints != 0) { mFlexibilityEnabled = true; mPrefetchController .registerPrefetchChangedListener(mPrefetchChangedListener); } else { mFlexibilityEnabled = false; mPrefetchController .unRegisterPrefetchChangedListener(mPrefetchChangedListener); } Loading Loading @@ -893,7 +956,7 @@ public final class FlexibilityController extends StateController { private int[] parsePercentToDropString(String s) { String[] dropPercentString = s.split(","); int[] dropPercentInt = new int[NUM_FLEXIBLE_CONSTRAINTS]; int[] dropPercentInt = new int[Integer.bitCount(FLEXIBLE_CONSTRAINTS)]; if (dropPercentInt.length != dropPercentString.length) { return DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS; } Loading Loading @@ -922,7 +985,7 @@ public final class FlexibilityController extends StateController { pw.println(":"); pw.increaseIndent(); pw.print(KEY_FLEXIBILITY_ENABLED, FLEXIBILITY_ENABLED).println(); pw.print(KEY_APPLIED_CONSTRAINTS, APPLIED_CONSTRAINTS).println(); pw.print(KEY_DEADLINE_PROXIMITY_LIMIT, DEADLINE_PROXIMITY_LIMIT_MS).println(); pw.print(KEY_FALLBACK_FLEXIBILITY_DEADLINE, FALLBACK_FLEXIBILITY_DEADLINE_MS).println(); pw.print(KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS, Loading apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +15 −10 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static com.android.server.job.JobSchedulerService.NEVER_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.FlexibilityController.NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; import static com.android.server.job.controllers.FlexibilityController.SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; import android.annotation.ElapsedRealtimeLong; Loading Loading @@ -155,7 +154,7 @@ public final class JobStatus { /** * Keeps track of how many flexible constraints must be satisfied for the job to execute. */ private final int mNumRequiredFlexibleConstraints; private int mNumAppliedFlexibleConstraints; /** * Number of required flexible constraints that have been dropped. Loading Loading @@ -697,11 +696,7 @@ public final class JobStatus { && satisfiesMinWindowException && (numFailures + numSystemStops) != 1 && lacksSomeFlexibleConstraints) { mNumRequiredFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (mCanApplyTransportAffinities ? 1 : 0); requiredConstraints |= CONSTRAINT_FLEXIBLE; } else { mNumRequiredFlexibleConstraints = 0; } this.requiredConstraints = requiredConstraints; Loading Loading @@ -1527,9 +1522,14 @@ public final class JobStatus { return (requiredConstraints & CONSTRAINT_FLEXIBLE) != 0; } /** Returns the number of flexible job constraints being applied to the job. */ public int getNumAppliedFlexibleConstraints() { return mNumAppliedFlexibleConstraints; } /** Returns the number of flexible job constraints required to be satisfied to execute */ public int getNumRequiredFlexibleConstraints() { return mNumRequiredFlexibleConstraints - mNumDroppedFlexibleConstraints; return mNumAppliedFlexibleConstraints - mNumDroppedFlexibleConstraints; } /** Loading Loading @@ -2112,9 +2112,14 @@ public final class JobStatus { } /** Adjusts the number of required flexible constraints by the given number */ public void adjustNumRequiredFlexibleConstraints(int adjustment) { mNumDroppedFlexibleConstraints = Math.max(0, Math.min(mNumRequiredFlexibleConstraints, mNumDroppedFlexibleConstraints - adjustment)); public void setNumAppliedFlexibleConstraints(int count) { mNumAppliedFlexibleConstraints = count; } /** Sets the number of dropped flexible constraints to the given number */ public void setNumDroppedFlexibleConstraints(int count) { mNumDroppedFlexibleConstraints = Math.max(0, Math.min(mNumAppliedFlexibleConstraints, count)); } /** Loading Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +2 −1 Original line number Diff line number Diff line Loading @@ -1769,7 +1769,8 @@ public final class ConnectivityController extends RestrictingController implemen @VisibleForTesting class CcConfig { private boolean mFlexIsEnabled = FlexibilityController.FcConfig.DEFAULT_FLEXIBILITY_ENABLED; private boolean mFlexIsEnabled = FlexibilityController.FcConfig.DEFAULT_APPLIED_CONSTRAINTS != 0; private boolean mShouldReprocessNetworkCapabilities = false; /** Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +124 −61 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_BATTERY_NOT_LOW; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CHARGING; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_CONNECTIVITY; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_FLEXIBLE; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_IDLE; import android.annotation.ElapsedRealtimeLong; Loading Loading @@ -74,17 +73,10 @@ public final class FlexibilityController extends StateController { private static final int JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS = CONSTRAINT_CONNECTIVITY; /** List of all flexible constraints. */ private static final int FLEXIBLE_CONSTRAINTS = @VisibleForTesting static final int FLEXIBLE_CONSTRAINTS = JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS | SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; private static final int NUM_JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS = Integer.bitCount(JOB_SPECIFIC_FLEXIBLE_CONSTRAINTS); static final int NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS = Integer.bitCount(SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS); static final int NUM_FLEXIBLE_CONSTRAINTS = Integer.bitCount(FLEXIBLE_CONSTRAINTS); private static final long NO_LIFECYCLE_END = Long.MAX_VALUE; /** Loading @@ -100,9 +92,15 @@ public final class FlexibilityController extends StateController { private long mUnseenConstraintGracePeriodMs = FcConfig.DEFAULT_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS; @VisibleForTesting /** Set of constraints supported on this device for flex scheduling. */ private final int mSupportedFlexConstraints; @GuardedBy("mLock") private boolean mFlexibilityEnabled; /** Set of constraints that will be used in the flex policy. */ @GuardedBy("mLock") boolean mFlexibilityEnabled = FcConfig.DEFAULT_FLEXIBILITY_ENABLED; private int mAppliedConstraints = FcConfig.DEFAULT_APPLIED_CONSTRAINTS; private long mMinTimeBetweenFlexibilityAlarmsMs = FcConfig.DEFAULT_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS; Loading @@ -118,9 +116,6 @@ public final class FlexibilityController extends StateController { */ private int[] mPercentToDropConstraints; @VisibleForTesting boolean mDeviceSupportsFlexConstraints; /** * Keeps track of what flexible constraints are satisfied at the moment. * Is updated by the other controllers. Loading Loading @@ -178,7 +173,7 @@ public final class FlexibilityController extends StateController { if (!js.hasFlexibilityConstraint()) { continue; } mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); } } Loading @@ -186,15 +181,23 @@ public final class FlexibilityController extends StateController { }; private static final int MSG_UPDATE_JOBS = 0; private static final int MSG_UPDATE_JOB = 1; public FlexibilityController( JobSchedulerService service, PrefetchController prefetchController) { super(service); mHandler = new FcHandler(AppSchedulingModuleThread.get().getLooper()); mDeviceSupportsFlexConstraints = !mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_AUTOMOTIVE); mFlexibilityEnabled &= mDeviceSupportsFlexConstraints; mFlexibilityTracker = new FlexibilityTracker(NUM_FLEXIBLE_CONSTRAINTS); if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) || mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED)) { // Embedded devices have no user-installable apps. Assume all jobs are critical // and can't be flexed. mSupportedFlexConstraints = 0; } else { // TODO(236261941): handle devices without a battery mSupportedFlexConstraints = FLEXIBLE_CONSTRAINTS; } mFlexibilityEnabled = (mAppliedConstraints & mSupportedFlexConstraints) != 0; mFlexibilityTracker = new FlexibilityTracker(Integer.bitCount(mSupportedFlexConstraints)); mFcConfig = new FcConfig(); mFlexibilityAlarmQueue = new FlexibilityAlarmQueue( mContext, AppSchedulingModuleThread.get().getLooper()); Loading @@ -218,10 +221,12 @@ public final class FlexibilityController extends StateController { public void maybeStartTrackingJobLocked(JobStatus js, JobStatus lastJob) { if (js.hasFlexibilityConstraint()) { final long nowElapsed = sElapsedRealtimeClock.millis(); if (!mDeviceSupportsFlexConstraints) { if (mSupportedFlexConstraints == 0) { js.setFlexibilityConstraintSatisfied(nowElapsed, true); return; } js.setNumAppliedFlexibleConstraints( Integer.bitCount(getRelevantAppliedConstraintsLocked(js))); js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js)); mFlexibilityTracker.add(js); js.setTrackingController(JobStatus.TRACKING_FLEXIBILITY); Loading Loading @@ -266,6 +271,14 @@ public final class FlexibilityController extends StateController { || mService.isCurrentlyRunningLocked(js); } @VisibleForTesting @GuardedBy("mLock") int getRelevantAppliedConstraintsLocked(@NonNull JobStatus js) { final int relevantConstraints = SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS | (js.canApplyTransportAffinities() ? CONSTRAINT_CONNECTIVITY : 0); return mAppliedConstraints & relevantConstraints; } /** * Returns whether there are enough constraints satisfied to allow running the job from flex's * perspective. This takes into account unseen constraint combinations and expectations around Loading @@ -274,7 +287,7 @@ public final class FlexibilityController extends StateController { @VisibleForTesting @GuardedBy("mLock") boolean hasEnoughSatisfiedConstraintsLocked(@NonNull JobStatus js) { final int satisfiedConstraints = mSatisfiedFlexibleConstraints final int satisfiedConstraints = mSatisfiedFlexibleConstraints & mAppliedConstraints & (SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS | (js.areTransportAffinitiesSatisfied() ? CONSTRAINT_CONNECTIVITY : 0)); final int numSatisfied = Integer.bitCount(satisfiedConstraints); Loading @@ -296,8 +309,7 @@ public final class FlexibilityController extends StateController { // count have not been seen recently enough, then assume they won't be seen anytime soon, // so don't force the job to wait longer. If any combinations with a higher count have been // seen recently, then the job can potentially wait for those combinations. final int irrelevantConstraints = ~(SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS | (js.canApplyTransportAffinities() ? CONSTRAINT_CONNECTIVITY : 0)); final int irrelevantConstraints = ~getRelevantAppliedConstraintsLocked(js); for (int i = mLastSeenConstraintTimesElapsed.size() - 1; i >= 0; --i) { final int constraints = mLastSeenConstraintTimesElapsed.keyAt(i); if ((constraints & irrelevantConstraints) != 0) { Loading Loading @@ -515,9 +527,9 @@ public final class FlexibilityController extends StateController { for (int j = 0; j < mFlexibilityTracker.size(); j++) { final ArraySet<JobStatus> jobs = mFlexibilityTracker .getJobsByNumRequiredConstraints(j); for (int i = 0; i < jobs.size(); i++) { for (int i = jobs.size() - 1; i >= 0; --i) { JobStatus js = jobs.valueAt(i); mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); mFlexibilityTracker.updateFlexibleConstraints(js, nowElapsed); mFlexibilityAlarmQueue.scheduleDropNumConstraintsAlarm(js, nowElapsed); if (js.setFlexibilityConstraintSatisfied( nowElapsed, isFlexibilitySatisfiedLocked(js))) { Loading Loading @@ -579,18 +591,46 @@ public final class FlexibilityController extends StateController { mTrackedJobs.get(js.getNumRequiredFlexibleConstraints()).remove(js); } public void resetJobNumDroppedConstraints(JobStatus js, long nowElapsed) { /** * Updates applied and dropped constraints for the job. */ public void updateFlexibleConstraints(JobStatus js, long nowElapsed) { final int prevNumRequired = js.getNumRequiredFlexibleConstraints(); final int numAppliedConstraints = Integer.bitCount(getRelevantAppliedConstraintsLocked(js)); js.setNumAppliedFlexibleConstraints(numAppliedConstraints); final int curPercent = getCurPercentOfLifecycleLocked(js, nowElapsed); int toDrop = 0; final int jsMaxFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (js.canApplyTransportAffinities() ? 1 : 0); for (int i = 0; i < numAppliedConstraints; i++) { if (curPercent >= mPercentToDropConstraints[i]) { toDrop++; } } js.setNumDroppedFlexibleConstraints(toDrop); if (prevNumRequired == js.getNumRequiredFlexibleConstraints()) { return; } mTrackedJobs.get(prevNumRequired).remove(js); add(js); } /** * Calculates the number of constraints that should be dropped for the job, based on how * far along the job is into its lifecycle. */ public void calculateNumDroppedConstraints(JobStatus js, long nowElapsed) { final int curPercent = getCurPercentOfLifecycleLocked(js, nowElapsed); int toDrop = 0; final int jsMaxFlexibleConstraints = js.getNumAppliedFlexibleConstraints(); for (int i = 0; i < jsMaxFlexibleConstraints; i++) { if (curPercent >= mPercentToDropConstraints[i]) { toDrop++; } } adjustJobsRequiredConstraints( js, js.getNumDroppedFlexibleConstraints() - toDrop, nowElapsed); setNumDroppedFlexibleConstraints(js, toDrop); } /** Returns all tracked jobs. */ Loading @@ -599,17 +639,14 @@ public final class FlexibilityController extends StateController { } /** * Adjusts number of required flexible constraints and sorts it into the tracker. * Returns false if the job status's number of flexible constraints is now 0. * Updates the number of dropped flexible constraints and sorts it into the tracker. */ public boolean adjustJobsRequiredConstraints(JobStatus js, int adjustBy, long nowElapsed) { if (adjustBy != 0) { public void setNumDroppedFlexibleConstraints(JobStatus js, int numDropped) { if (numDropped != js.getNumDroppedFlexibleConstraints()) { remove(js); js.adjustNumRequiredFlexibleConstraints(adjustBy); js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js)); js.setNumDroppedFlexibleConstraints(numDropped); add(js); } return js.getNumRequiredFlexibleConstraints() > 0; } public int size() { Loading Loading @@ -658,8 +695,10 @@ public final class FlexibilityController extends StateController { if (DEBUG) { Slog.d(TAG, "scheduleDropNumConstraintsAlarm: " + js.getSourcePackageName() + " " + js.getSourceUserId() + " numApplied: " + js.getNumAppliedFlexibleConstraints() + " numRequired: " + js.getNumRequiredFlexibleConstraints() + " numSatisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints) + " numSatisfied: " + Integer.bitCount( mSatisfiedFlexibleConstraints & getRelevantAppliedConstraintsLocked(js)) + " curTime: " + nowElapsed + " earliest: " + earliest + " latest: " + latest Loading @@ -669,8 +708,9 @@ public final class FlexibilityController extends StateController { if (DEBUG) { Slog.d(TAG, "deadline proximity met: " + js); } mFlexibilityTracker.adjustJobsRequiredConstraints(js, -js.getNumRequiredFlexibleConstraints(), nowElapsed); mFlexibilityTracker.setNumDroppedFlexibleConstraints(js, js.getNumAppliedFlexibleConstraints()); mHandler.obtainMessage(MSG_UPDATE_JOB, js).sendToTarget(); return; } if (nextTimeElapsed == NO_LIFECYCLE_END) { Loading @@ -696,12 +736,15 @@ public final class FlexibilityController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); for (int i = 0; i < expired.size(); i++) { JobStatus js = expired.valueAt(i); boolean wasFlexibilitySatisfied = js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE); if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed)) { if (DEBUG) { Slog.d(TAG, "Alarm fired for " + js.toShortString()); } mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); if (js.getNumRequiredFlexibleConstraints() > 0) { scheduleDropNumConstraintsAlarm(js, nowElapsed); } if (wasFlexibilitySatisfied != js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE)) { if (js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js))) { changedJobs.add(js); } } Loading @@ -725,7 +768,9 @@ public final class FlexibilityController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); final ArraySet<JobStatus> changedJobs = new ArraySet<>(); for (int o = 0; o <= NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; ++o) { final int numAppliedSystemWideConstraints = Integer.bitCount( mAppliedConstraints & SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS); for (int o = 0; o <= numAppliedSystemWideConstraints; ++o) { final ArraySet<JobStatus> jobsByNumConstraints = mFlexibilityTracker .getJobsByNumRequiredConstraints(o); Loading @@ -744,6 +789,23 @@ public final class FlexibilityController extends StateController { } } break; case MSG_UPDATE_JOB: synchronized (mLock) { final JobStatus js = (JobStatus) msg.obj; if (DEBUG) { Slog.d("blah", "Checking on " + js.toShortString()); } final long nowElapsed = sElapsedRealtimeClock.millis(); if (js.setFlexibilityConstraintSatisfied( nowElapsed, isFlexibilitySatisfiedLocked(js))) { // TODO(141645789): add method that will take a single job ArraySet<JobStatus> changedJob = new ArraySet<>(); changedJob.add(js); mStateChangedListener.onControllerStateChanged(changedJob); } } break; } } } Loading @@ -754,7 +816,8 @@ public final class FlexibilityController extends StateController { /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */ private static final String FC_CONFIG_PREFIX = "fc_"; static final String KEY_FLEXIBILITY_ENABLED = FC_CONFIG_PREFIX + "enable_flexibility"; @VisibleForTesting static final String KEY_APPLIED_CONSTRAINTS = FC_CONFIG_PREFIX + "applied_constraints"; static final String KEY_DEADLINE_PROXIMITY_LIMIT = FC_CONFIG_PREFIX + "flexibility_deadline_proximity_limit_ms"; static final String KEY_FALLBACK_FLEXIBILITY_DEADLINE = Loading @@ -770,7 +833,7 @@ public final class FlexibilityController extends StateController { static final String KEY_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS = FC_CONFIG_PREFIX + "unseen_constraint_grace_period_ms"; static final boolean DEFAULT_FLEXIBILITY_ENABLED = false; static final int DEFAULT_APPLIED_CONSTRAINTS = 0; @VisibleForTesting static final long DEFAULT_DEADLINE_PROXIMITY_LIMIT_MS = 15 * MINUTE_IN_MILLIS; @VisibleForTesting Loading @@ -783,11 +846,8 @@ public final class FlexibilityController extends StateController { @VisibleForTesting static final long DEFAULT_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS = 3 * DAY_IN_MILLIS; /** * If false the controller will not track new jobs * and the flexibility constraint will always be satisfied. */ public boolean FLEXIBILITY_ENABLED = DEFAULT_FLEXIBILITY_ENABLED; /** Which constraints to apply/consider in flex policy. */ public int APPLIED_CONSTRAINTS = DEFAULT_APPLIED_CONSTRAINTS; /** How close to a jobs' deadline all flexible constraints will be dropped. */ public long DEADLINE_PROXIMITY_LIMIT_MS = DEFAULT_DEADLINE_PROXIMITY_LIMIT_MS; /** For jobs that lack a deadline, the time that will be used to drop all constraints by. */ Loading @@ -811,16 +871,19 @@ public final class FlexibilityController extends StateController { public void processConstantLocked(@NonNull DeviceConfig.Properties properties, @NonNull String key) { switch (key) { case KEY_FLEXIBILITY_ENABLED: FLEXIBILITY_ENABLED = properties.getBoolean(key, DEFAULT_FLEXIBILITY_ENABLED) && mDeviceSupportsFlexConstraints; if (mFlexibilityEnabled != FLEXIBILITY_ENABLED) { mFlexibilityEnabled = FLEXIBILITY_ENABLED; case KEY_APPLIED_CONSTRAINTS: APPLIED_CONSTRAINTS = properties.getInt(key, DEFAULT_APPLIED_CONSTRAINTS) & mSupportedFlexConstraints; if (mAppliedConstraints != APPLIED_CONSTRAINTS) { mAppliedConstraints = APPLIED_CONSTRAINTS; mShouldReevaluateConstraints = true; if (mFlexibilityEnabled) { if (mAppliedConstraints != 0) { mFlexibilityEnabled = true; mPrefetchController .registerPrefetchChangedListener(mPrefetchChangedListener); } else { mFlexibilityEnabled = false; mPrefetchController .unRegisterPrefetchChangedListener(mPrefetchChangedListener); } Loading Loading @@ -893,7 +956,7 @@ public final class FlexibilityController extends StateController { private int[] parsePercentToDropString(String s) { String[] dropPercentString = s.split(","); int[] dropPercentInt = new int[NUM_FLEXIBLE_CONSTRAINTS]; int[] dropPercentInt = new int[Integer.bitCount(FLEXIBLE_CONSTRAINTS)]; if (dropPercentInt.length != dropPercentString.length) { return DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS; } Loading Loading @@ -922,7 +985,7 @@ public final class FlexibilityController extends StateController { pw.println(":"); pw.increaseIndent(); pw.print(KEY_FLEXIBILITY_ENABLED, FLEXIBILITY_ENABLED).println(); pw.print(KEY_APPLIED_CONSTRAINTS, APPLIED_CONSTRAINTS).println(); pw.print(KEY_DEADLINE_PROXIMITY_LIMIT, DEADLINE_PROXIMITY_LIMIT_MS).println(); pw.print(KEY_FALLBACK_FLEXIBILITY_DEADLINE, FALLBACK_FLEXIBILITY_DEADLINE_MS).println(); pw.print(KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS, Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +15 −10 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static com.android.server.job.JobSchedulerService.NEVER_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.FlexibilityController.NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; import static com.android.server.job.controllers.FlexibilityController.SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; import android.annotation.ElapsedRealtimeLong; Loading Loading @@ -155,7 +154,7 @@ public final class JobStatus { /** * Keeps track of how many flexible constraints must be satisfied for the job to execute. */ private final int mNumRequiredFlexibleConstraints; private int mNumAppliedFlexibleConstraints; /** * Number of required flexible constraints that have been dropped. Loading Loading @@ -697,11 +696,7 @@ public final class JobStatus { && satisfiesMinWindowException && (numFailures + numSystemStops) != 1 && lacksSomeFlexibleConstraints) { mNumRequiredFlexibleConstraints = NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (mCanApplyTransportAffinities ? 1 : 0); requiredConstraints |= CONSTRAINT_FLEXIBLE; } else { mNumRequiredFlexibleConstraints = 0; } this.requiredConstraints = requiredConstraints; Loading Loading @@ -1527,9 +1522,14 @@ public final class JobStatus { return (requiredConstraints & CONSTRAINT_FLEXIBLE) != 0; } /** Returns the number of flexible job constraints being applied to the job. */ public int getNumAppliedFlexibleConstraints() { return mNumAppliedFlexibleConstraints; } /** Returns the number of flexible job constraints required to be satisfied to execute */ public int getNumRequiredFlexibleConstraints() { return mNumRequiredFlexibleConstraints - mNumDroppedFlexibleConstraints; return mNumAppliedFlexibleConstraints - mNumDroppedFlexibleConstraints; } /** Loading Loading @@ -2112,9 +2112,14 @@ public final class JobStatus { } /** Adjusts the number of required flexible constraints by the given number */ public void adjustNumRequiredFlexibleConstraints(int adjustment) { mNumDroppedFlexibleConstraints = Math.max(0, Math.min(mNumRequiredFlexibleConstraints, mNumDroppedFlexibleConstraints - adjustment)); public void setNumAppliedFlexibleConstraints(int count) { mNumAppliedFlexibleConstraints = count; } /** Sets the number of dropped flexible constraints to the given number */ public void setNumDroppedFlexibleConstraints(int count) { mNumDroppedFlexibleConstraints = Math.max(0, Math.min(mNumAppliedFlexibleConstraints, count)); } /** Loading