From a6738a47b1f0dede8640ebf48a0bbc8a223108de Mon Sep 17 00:00:00 2001 From: Kweku Adams <kwekua@google.com> Date: Mon, 4 Dec 2023 23:04:45 +0000 Subject: [PATCH] Make applied flex constraints configurable. Make it possible to change which specific constraints are used in the flex scheduling behavior. Bug: 236261941 Bug: 299329948 Bug: 299346198 Test: atest CtsJobSchedulerTestCases:FlexibilityConstraintTest Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/job Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/job Change-Id: I55c143d9e4ec384bd4c687dbe9313a8e78a9a6f1 --- .../controllers/ConnectivityController.java | 3 +- .../controllers/FlexibilityController.java | 185 +++++++++----- .../server/job/controllers/JobStatus.java | 25 +- .../FlexibilityControllerTest.java | 236 +++++++++++++----- .../server/job/controllers/JobStatusTest.java | 13 + 5 files changed, 331 insertions(+), 131 deletions(-) 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 e06006f25d3f..f40508302ee3 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 @@ -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; /** diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java index 13a474ccf451..0e67b9ac944f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java @@ -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; @@ -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; /** @@ -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") - boolean mFlexibilityEnabled = FcConfig.DEFAULT_FLEXIBILITY_ENABLED; + private boolean mFlexibilityEnabled; + + /** Set of constraints that will be used in the flex policy. */ + @GuardedBy("mLock") + private int mAppliedConstraints = FcConfig.DEFAULT_APPLIED_CONSTRAINTS; private long mMinTimeBetweenFlexibilityAlarmsMs = FcConfig.DEFAULT_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS; @@ -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. @@ -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); } } @@ -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()); @@ -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); @@ -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 @@ -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); @@ -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) { @@ -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))) { @@ -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. */ @@ -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() { @@ -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 @@ -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) { @@ -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); } } @@ -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); @@ -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; } } } @@ -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 = @@ -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 @@ -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. */ @@ -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); } @@ -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; } @@ -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, 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 d1f575ef40c8..0d5d11e98860 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 @@ -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; @@ -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. @@ -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; @@ -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; } /** @@ -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)); } /** diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java index 4fb9472021c5..650c473533ed 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java @@ -30,15 +30,16 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.server.job.controllers.FlexibilityController.FcConfig.DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS; import static com.android.server.job.controllers.FlexibilityController.FcConfig.DEFAULT_UNSEEN_CONSTRAINT_GRACE_PERIOD_MS; +import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_APPLIED_CONSTRAINTS; import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_DEADLINE_PROXIMITY_LIMIT; import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_FALLBACK_FLEXIBILITY_DEADLINE; -import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_FLEXIBILITY_ENABLED; import static com.android.server.job.controllers.FlexibilityController.FcConfig.KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS; -import static com.android.server.job.controllers.FlexibilityController.NUM_FLEXIBLE_CONSTRAINTS; +import static com.android.server.job.controllers.FlexibilityController.FLEXIBLE_CONSTRAINTS; import static com.android.server.job.controllers.FlexibilityController.SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS; 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_CONTENT_TRIGGER; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_FLEXIBLE; import static com.android.server.job.controllers.JobStatus.CONSTRAINT_IDLE; import static com.android.server.job.controllers.JobStatus.MIN_WINDOW_FOR_FLEXIBILITY_MS; @@ -66,6 +67,7 @@ import android.os.Looper; import android.provider.DeviceConfig; import android.util.ArraySet; +import com.android.server.AppSchedulingModuleThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobStore; @@ -129,6 +131,7 @@ public class FlexibilityControllerTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.hasSystemFeature( PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(false); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_EMBEDDED)).thenReturn(false); // Used in FlexibilityController.FcConstants. doAnswer((Answer<Void>) invocationOnMock -> null) .when(() -> DeviceConfig.addOnPropertiesChangedListener( @@ -161,7 +164,8 @@ public class FlexibilityControllerTest { setDeviceConfigString(KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS, "50,60,70,80"); setDeviceConfigLong(KEY_DEADLINE_PROXIMITY_LIMIT, 0L); - setDeviceConfigBoolean(KEY_FLEXIBILITY_ENABLED, true); + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, FLEXIBLE_CONSTRAINTS); + waitForQuietModuleThread(); } @After @@ -171,26 +175,22 @@ public class FlexibilityControllerTest { } } - private void setDeviceConfigBoolean(String key, boolean val) { - mDeviceConfigPropertiesBuilder.setBoolean(key, val); - synchronized (mFlexibilityController.mLock) { - mFlexibilityController.prepareForUpdatedConstantsLocked(); - mFcConfig.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key); - mFlexibilityController.onConstantsUpdatedLocked(); - } + private void setDeviceConfigInt(String key, int val) { + mDeviceConfigPropertiesBuilder.setInt(key, val); + updateDeviceConfig(key); } private void setDeviceConfigLong(String key, Long val) { mDeviceConfigPropertiesBuilder.setLong(key, val); - synchronized (mFlexibilityController.mLock) { - mFlexibilityController.prepareForUpdatedConstantsLocked(); - mFcConfig.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key); - mFlexibilityController.onConstantsUpdatedLocked(); - } + updateDeviceConfig(key); } private void setDeviceConfigString(String key, String val) { mDeviceConfigPropertiesBuilder.setString(key, val); + updateDeviceConfig(key); + } + + private void updateDeviceConfig(String key) { synchronized (mFlexibilityController.mLock) { mFlexibilityController.prepareForUpdatedConstantsLocked(); mFcConfig.processConstantLocked(mDeviceConfigPropertiesBuilder.build(), key); @@ -198,6 +198,11 @@ public class FlexibilityControllerTest { } } + private void waitForQuietModuleThread() { + assertTrue("Failed to wait for quiet module thread", + AppSchedulingModuleThread.getHandler().runWithScissors(() -> {}, 10_000L)); + } + private static JobInfo.Builder createJob(int id) { return new JobInfo.Builder(id, new ComponentName("foo", "bar")); } @@ -207,6 +212,10 @@ public class FlexibilityControllerTest { JobStatus js = JobStatus.createFromJobInfo( jobInfo, 1000, SOURCE_PACKAGE, SOURCE_USER_ID, "FCTest", testTag); js.enqueueTime = FROZEN_TIME; + if (js.hasFlexibilityConstraint()) { + js.setNumAppliedFlexibleConstraints(Integer.bitCount( + mFlexibilityController.getRelevantAppliedConstraintsLocked(js))); + } return js; } @@ -215,18 +224,120 @@ public class FlexibilityControllerTest { */ @Test public void testDefaultVariableValues() { - assertEquals(NUM_FLEXIBLE_CONSTRAINTS, + assertEquals(Integer.bitCount(FLEXIBLE_CONSTRAINTS), mFlexibilityController.mFcConfig.DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS.length ); } @Test - public void testOnConstantsUpdated_DefaultFlexibility() { + public void testAppliedConstraints() { + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, FLEXIBLE_CONSTRAINTS); + + // Add connectivity to require 4 constraints + JobStatus connJs = createJobStatus("testAppliedConstraints", + createJob(0).setRequiredNetworkType(NETWORK_TYPE_ANY)); + JobStatus nonConnJs = createJobStatus("testAppliedConstraints", + createJob(1).setRequiredNetworkType(NETWORK_TYPE_NONE)); + + mFlexibilityController.maybeStartTrackingJobLocked(connJs, null); + mFlexibilityController.maybeStartTrackingJobLocked(nonConnJs, null); + + assertEquals(4, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(3, nonConnJs.getNumAppliedFlexibleConstraints()); + + mFlexibilityController.setConstraintSatisfied( + CONSTRAINT_BATTERY_NOT_LOW, true, + JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS); + mFlexibilityController.setConstraintSatisfied( + CONSTRAINT_CHARGING, false, + JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS); + mFlexibilityController.setConstraintSatisfied( + CONSTRAINT_IDLE, false, + JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS); + mFlexibilityController.setConstraintSatisfied( + CONSTRAINT_CONNECTIVITY, true, + JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS); + connJs.setTransportAffinitiesSatisfied(true); + + synchronized (mFlexibilityController.mLock) { + assertFalse(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertFalse(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, + CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_CONNECTIVITY); + waitForQuietModuleThread(); + + // Only battery-not-low (which is satisfied) applies to the non-connectivity job, so it + // should be able to run. + assertEquals(2, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(1, nonConnJs.getNumAppliedFlexibleConstraints()); + synchronized (mFlexibilityController.mLock) { + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, CONSTRAINT_BATTERY_NOT_LOW); + waitForQuietModuleThread(); + + assertEquals(1, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(1, nonConnJs.getNumAppliedFlexibleConstraints()); + synchronized (mFlexibilityController.mLock) { + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, CONSTRAINT_CONNECTIVITY); + waitForQuietModuleThread(); + + // No constraints apply to the non-connectivity job, so it should be able to run. + assertEquals(1, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(0, nonConnJs.getNumAppliedFlexibleConstraints()); + synchronized (mFlexibilityController.mLock) { + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, CONSTRAINT_CHARGING); + waitForQuietModuleThread(); + + assertEquals(1, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(1, nonConnJs.getNumAppliedFlexibleConstraints()); + synchronized (mFlexibilityController.mLock) { + assertFalse(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertFalse(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, 0); + waitForQuietModuleThread(); + + // No constraints apply, so they should be able to run. + assertEquals(0, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(0, nonConnJs.getNumAppliedFlexibleConstraints()); + synchronized (mFlexibilityController.mLock) { + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + + // Invalid constraint to apply. + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, CONSTRAINT_CONTENT_TRIGGER); + waitForQuietModuleThread(); + + // No constraints apply, so they should be able to run. + assertEquals(0, connJs.getNumAppliedFlexibleConstraints()); + assertEquals(0, nonConnJs.getNumAppliedFlexibleConstraints()); + synchronized (mFlexibilityController.mLock) { + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(connJs)); + assertTrue(mFlexibilityController.hasEnoughSatisfiedConstraintsLocked(nonConnJs)); + } + } + + @Test + public void testOnConstantsUpdated_AppliedConstraints() { JobStatus js = createJobStatus("testDefaultFlexibilityConfig", createJob(0)); - assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(js)); - setDeviceConfigBoolean(KEY_FLEXIBILITY_ENABLED, false); + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, 0); assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(js)); - setDeviceConfigBoolean(KEY_FLEXIBILITY_ENABLED, true); + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, FLEXIBLE_CONSTRAINTS); assertFalse(mFlexibilityController.isFlexibilitySatisfiedLocked(js)); } @@ -261,10 +372,10 @@ public class FlexibilityControllerTest { new int[] {10, 20, 30, 40}); assertEquals(FROZEN_TIME + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(1); assertEquals(FROZEN_TIME + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 2, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(2); assertEquals(FROZEN_TIME + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 3, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); } @@ -303,12 +414,12 @@ public class FlexibilityControllerTest { .getNextConstraintDropTimeElapsedLocked(js); assertEquals(FROZEN_TIME + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 5, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(1); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(FROZEN_TIME + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 6, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(2); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(FROZEN_TIME + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 7, @@ -321,11 +432,11 @@ public class FlexibilityControllerTest { nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(130400100, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(1); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(156320100L, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(2); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(182240100L, nextTimeToDropNumConstraints); @@ -337,11 +448,11 @@ public class FlexibilityControllerTest { nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(129600100, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(1); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(155520100L, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(2); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(181440100L, nextTimeToDropNumConstraints); @@ -357,12 +468,12 @@ public class FlexibilityControllerTest { .getNextConstraintDropTimeElapsedLocked(js); assertEquals(windowStart + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 5, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(1); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(windowStart + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 6, nextTimeToDropNumConstraints); - js.adjustNumRequiredFlexibleConstraints(-1); + js.setNumDroppedFlexibleConstraints(2); nextTimeToDropNumConstraints = mFlexibilityController .getNextConstraintDropTimeElapsedLocked(js); assertEquals(windowStart + MIN_WINDOW_FOR_FLEXIBILITY_MS / 10 * 7, @@ -580,10 +691,10 @@ public class FlexibilityControllerTest { } @Test - public void testWontStopJobFromRunning() { - JobStatus js = createJobStatus("testWontStopJobFromRunning", createJob(101)); + public void testWontStopAlreadyRunningJob() { + JobStatus js = createJobStatus("testWontStopAlreadyRunningJob", createJob(101)); // Stop satisfied constraints from causing a false positive. - js.adjustNumRequiredFlexibleConstraints(100); + js.setNumAppliedFlexibleConstraints(100); synchronized (mFlexibilityController.mLock) { when(mJobSchedulerService.isCurrentlyRunningLocked(js)).thenReturn(true); assertTrue(mFlexibilityController.isFlexibilitySatisfiedLocked(js)); @@ -593,10 +704,9 @@ public class FlexibilityControllerTest { @Test public void testFlexibilityTracker() { FlexibilityController.FlexibilityTracker flexTracker = - mFlexibilityController.new - FlexibilityTracker(NUM_FLEXIBLE_CONSTRAINTS); + mFlexibilityController.new FlexibilityTracker(4); // Plus one for jobs with 0 required constraint. - assertEquals(NUM_FLEXIBLE_CONSTRAINTS + 1, flexTracker.size()); + assertEquals(4 + 1, flexTracker.size()); JobStatus[] jobs = new JobStatus[4]; JobInfo.Builder jb; for (int i = 0; i < jobs.length; i++) { @@ -622,21 +732,21 @@ public class FlexibilityControllerTest { assertEquals(3, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); + flexTracker.setNumDroppedFlexibleConstraints(jobs[0], 1); assertEquals(1, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(1, trackedJobs.get(2).size()); assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); + flexTracker.setNumDroppedFlexibleConstraints(jobs[0], 2); assertEquals(1, trackedJobs.get(0).size()); assertEquals(1, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -1, FROZEN_TIME); + flexTracker.setNumDroppedFlexibleConstraints(jobs[0], 3); assertEquals(2, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); @@ -650,14 +760,14 @@ public class FlexibilityControllerTest { assertEquals(1, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); - flexTracker.resetJobNumDroppedConstraints(jobs[0], FROZEN_TIME); + flexTracker.calculateNumDroppedConstraints(jobs[0], FROZEN_TIME); assertEquals(1, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); assertEquals(2, trackedJobs.get(3).size()); assertEquals(0, trackedJobs.get(4).size()); - flexTracker.adjustJobsRequiredConstraints(jobs[0], -2, FROZEN_TIME); + flexTracker.setNumDroppedFlexibleConstraints(jobs[0], 2); assertEquals(1, trackedJobs.get(0).size()); assertEquals(1, trackedJobs.get(1).size()); assertEquals(0, trackedJobs.get(2).size()); @@ -669,7 +779,7 @@ public class FlexibilityControllerTest { JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - flexTracker.resetJobNumDroppedConstraints(jobs[0], nowElapsed); + flexTracker.calculateNumDroppedConstraints(jobs[0], nowElapsed); assertEquals(1, trackedJobs.get(0).size()); assertEquals(0, trackedJobs.get(1).size()); assertEquals(1, trackedJobs.get(2).size()); @@ -779,9 +889,9 @@ public class FlexibilityControllerTest { mFlexibilityController.setConstraintSatisfied( SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS, false, FROZEN_TIME); // Require only a single constraint - jsAny.adjustNumRequiredFlexibleConstraints(-3); - jsCell.adjustNumRequiredFlexibleConstraints(-2); - jsWifi.adjustNumRequiredFlexibleConstraints(-2); + jsAny.setNumAppliedFlexibleConstraints(1); + jsCell.setNumAppliedFlexibleConstraints(1); + jsWifi.setNumAppliedFlexibleConstraints(1); synchronized (mFlexibilityController.mLock) { jsAny.setTransportAffinitiesSatisfied(false); jsCell.setTransportAffinitiesSatisfied(false); @@ -1008,9 +1118,9 @@ public class FlexibilityControllerTest { } @Test - public void testResetJobNumDroppedConstraints() { + public void testCalculateNumDroppedConstraints() { JobInfo.Builder jb = createJob(22); - JobStatus js = createJobStatus("testResetJobNumDroppedConstraints", jb); + JobStatus js = createJobStatus("testCalculateNumDroppedConstraints", jb); long nowElapsed = FROZEN_TIME; mFlexibilityController.mFlexibilityTracker.add(js); @@ -1025,14 +1135,14 @@ public class FlexibilityControllerTest { Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); mFlexibilityController.mFlexibilityTracker - .adjustJobsRequiredConstraints(js, -1, nowElapsed); + .setNumDroppedFlexibleConstraints(js, 1); assertEquals(2, js.getNumRequiredFlexibleConstraints()); assertEquals(1, js.getNumDroppedFlexibleConstraints()); assertEquals(1, mFlexibilityController .mFlexibilityTracker.getJobsByNumRequiredConstraints(2).size()); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); + mFlexibilityController.mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); assertEquals(2, js.getNumRequiredFlexibleConstraints()); assertEquals(1, js.getNumDroppedFlexibleConstraints()); @@ -1043,7 +1153,7 @@ public class FlexibilityControllerTest { JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); + mFlexibilityController.mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); assertEquals(3, js.getNumRequiredFlexibleConstraints()); assertEquals(0, js.getNumDroppedFlexibleConstraints()); @@ -1054,7 +1164,7 @@ public class FlexibilityControllerTest { JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); + mFlexibilityController.mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); assertEquals(0, js.getNumRequiredFlexibleConstraints()); assertEquals(3, js.getNumDroppedFlexibleConstraints()); @@ -1063,7 +1173,7 @@ public class FlexibilityControllerTest { JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - mFlexibilityController.mFlexibilityTracker.resetJobNumDroppedConstraints(js, nowElapsed); + mFlexibilityController.mFlexibilityTracker.calculateNumDroppedConstraints(js, nowElapsed); assertEquals(1, js.getNumRequiredFlexibleConstraints()); assertEquals(2, js.getNumDroppedFlexibleConstraints()); @@ -1139,20 +1249,28 @@ public class FlexibilityControllerTest { } @Test - public void testDeviceDisabledFlexibility_Auto() { - when(mPackageManager.hasSystemFeature( - PackageManager.FEATURE_AUTOMOTIVE)).thenReturn(true); + public void testUnsupportedDevice_Auto() { + runTestUnsupportedDevice(PackageManager.FEATURE_AUTOMOTIVE); + } + + @Test + public void testUnsupportedDevice_Embedded() { + runTestUnsupportedDevice(PackageManager.FEATURE_EMBEDDED); + } + + private void runTestUnsupportedDevice(String feature) { + when(mPackageManager.hasSystemFeature(feature)).thenReturn(true); mFlexibilityController = new FlexibilityController(mJobSchedulerService, mPrefetchController); - assertFalse(mFlexibilityController.mFlexibilityEnabled); + assertFalse(mFlexibilityController.isEnabled()); - JobStatus js = createJobStatus("testIsAuto", createJob(0)); + JobStatus js = createJobStatus("testUnsupportedDevice", createJob(0)); mFlexibilityController.maybeStartTrackingJobLocked(js, null); assertTrue(js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE)); - setDeviceConfigBoolean(KEY_FLEXIBILITY_ENABLED, true); - assertFalse(mFlexibilityController.mFlexibilityEnabled); + setDeviceConfigInt(KEY_APPLIED_CONSTRAINTS, FLEXIBLE_CONSTRAINTS); + assertFalse(mFlexibilityController.isEnabled()); ArrayList<ArraySet<JobStatus>> jobs = mFlexibilityController.mFlexibilityTracker.getArrayList(); 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 8397b87706d6..293391f43828 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 @@ -231,6 +231,19 @@ public class JobStatusTest { assertTrue(job.canRunInDoze()); } + @Test + public void testFlexibleConstraintCounts() { + JobStatus js = createJobStatus(new JobInfo.Builder(101, new ComponentName("foo", "bar")) + .setUserInitiated(false) + .build()); + + js.setNumAppliedFlexibleConstraints(3); + js.setNumDroppedFlexibleConstraints(2); + assertEquals(3, js.getNumAppliedFlexibleConstraints()); + assertEquals(2, js.getNumDroppedFlexibleConstraints()); + assertEquals(1, js.getNumRequiredFlexibleConstraints()); + } + @Test public void testIsUserVisibleJob() { JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar")) -- GitLab