diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java index 460763ad4bbc7..692510a5964ff 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -102,14 +102,19 @@ class JobConcurrencyManager { * can run as a background job. */ static final int WORK_TYPE_BG = 1 << 3; + /** + * The job is for an app in a {@link ActivityManager#PROCESS_STATE_FOREGROUND_SERVICE} or higher + * state, or is allowed to run as an expedited job, but is for a completely background user. + */ + static final int WORK_TYPE_BGUSER_IMPORTANT = 1 << 4; /** * The job does not satisfy any of the conditions for {@link #WORK_TYPE_TOP}, * {@link #WORK_TYPE_FGS}, or {@link #WORK_TYPE_EJ}, but is for a completely background user, * so can run as a background user job. */ - static final int WORK_TYPE_BGUSER = 1 << 4; + static final int WORK_TYPE_BGUSER = 1 << 5; @VisibleForTesting - static final int NUM_WORK_TYPES = 5; + static final int NUM_WORK_TYPES = 6; private static final int ALL_WORK_TYPES = (1 << NUM_WORK_TYPES) - 1; @IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = { @@ -118,6 +123,7 @@ class JobConcurrencyManager { WORK_TYPE_FGS, WORK_TYPE_EJ, WORK_TYPE_BG, + WORK_TYPE_BGUSER_IMPORTANT, WORK_TYPE_BGUSER }) @Retention(RetentionPolicy.SOURCE) @@ -139,6 +145,8 @@ class JobConcurrencyManager { return "BG"; case WORK_TYPE_BGUSER: return "BGUSER"; + case WORK_TYPE_BGUSER_IMPORTANT: + return "BGUSER_IMPORTANT"; default: return "WORK(" + workType + ")"; } @@ -164,30 +172,40 @@ class JobConcurrencyManager { new WorkTypeConfig("screen_on_normal", 11, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)), + Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4)) + List.of(Pair.create(WORK_TYPE_BG, 6), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2), + Pair.create(WORK_TYPE_BGUSER, 3)) ), new WorkTypeConfig("screen_on_moderate", 9, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)), + Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)) + List.of(Pair.create(WORK_TYPE_BG, 4), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)) ), new WorkTypeConfig("screen_on_low", 6, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), Pair.create(WORK_TYPE_EJ, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, 1), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)) ), new WorkTypeConfig("screen_on_critical", 6, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), Pair.create(WORK_TYPE_EJ, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, 1), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)) ) ); private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF = @@ -195,30 +213,40 @@ class JobConcurrencyManager { new WorkTypeConfig("screen_off_normal", 15, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)), + Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4)) + List.of(Pair.create(WORK_TYPE_BG, 6), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2), + Pair.create(WORK_TYPE_BGUSER, 3)) ), new WorkTypeConfig("screen_off_moderate", 15, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)), + Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)) + List.of(Pair.create(WORK_TYPE_BG, 4), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)) ), new WorkTypeConfig("screen_off_low", 9, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, 1), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)) ), new WorkTypeConfig("screen_off_critical", 6, // defaultMin List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), Pair.create(WORK_TYPE_EJ, 1)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, 1), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)) ) ); @@ -823,17 +851,22 @@ class JobConcurrencyManager { // Only expedited jobs can replace expedited jobs. if (js.shouldTreatAsExpeditedJob()) { // Keep fg/bg user distinction. - if (workType == WORK_TYPE_BGUSER) { - // For now, let any bg user job replace a bg user expedited job. - // TODO: limit to ej once we have dedicated bg user ej slots. - if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_BGUSER) > 0) { - return "blocking " + workTypeToString(workType) + " queue"; + if (workType == WORK_TYPE_BGUSER_IMPORTANT || workType == WORK_TYPE_BGUSER) { + // Let any important bg user job replace a bg user expedited job. + if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_BGUSER_IMPORTANT) > 0) { + return "blocking " + workTypeToString(WORK_TYPE_BGUSER_IMPORTANT) + " queue"; } - } else { - if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) { - return "blocking " + workTypeToString(workType) + " queue"; + // Let a fg user EJ preempt a bg user EJ (if able), but not the other way around. + if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0 + && mWorkCountTracker.canJobStart(WORK_TYPE_EJ, workType) + != WORK_TYPE_NONE) { + return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue"; } + } else if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) { + return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue"; } + // No other pending EJs. Return null so we don't let regular jobs preempt an EJ. + return null; } // Easy check. If there are pending jobs of the same work type, then we know that @@ -1017,6 +1050,7 @@ class JobConcurrencyManager { int getJobWorkTypes(@NonNull JobStatus js) { int classification = 0; + if (shouldRunAsFgUserJob(js)) { if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) { classification |= WORK_TYPE_TOP; @@ -1030,7 +1064,11 @@ class JobConcurrencyManager { classification |= WORK_TYPE_EJ; } } else { - // TODO(171305774): create dedicated slots for EJs of bg user + if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_FOREGROUND_SERVICE + || js.shouldTreatAsExpeditedJob()) { + classification |= WORK_TYPE_BGUSER_IMPORTANT; + } + // BGUSER_IMPORTANT jobs can also run as BGUSER jobs, so not an 'else' here. classification |= WORK_TYPE_BGUSER; } @@ -1047,12 +1085,16 @@ class JobConcurrencyManager { private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_"; private static final String KEY_PREFIX_MAX_BGUSER = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_"; + private static final String KEY_PREFIX_MAX_BGUSER_IMPORTANT = + CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_important_"; private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_"; private static final String KEY_PREFIX_MIN_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "min_fgs_"; private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_"; private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_"; private static final String KEY_PREFIX_MIN_BGUSER = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_"; + private static final String KEY_PREFIX_MIN_BGUSER_IMPORTANT = + CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_important_"; private final String mConfigIdentifier; private int mMaxTotal; @@ -1108,6 +1150,10 @@ class JobConcurrencyManager { properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier, mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal)))); mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg); + final int maxBgUserImp = Math.max(1, Math.min(mMaxTotal, + properties.getInt(KEY_PREFIX_MAX_BGUSER_IMPORTANT + mConfigIdentifier, + mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, mMaxTotal)))); + mMaxAllowedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, maxBgUserImp); final int maxBgUser = Math.max(1, Math.min(mMaxTotal, properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier, mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal)))); @@ -1139,6 +1185,11 @@ class JobConcurrencyManager { mDefaultMinReservedSlots.get(WORK_TYPE_BG)))); mMinReservedSlots.put(WORK_TYPE_BG, minBg); remaining -= minBg; + // Ensure bg user imp is in the range [0, min(maxBgUserImp, remaining)] + final int minBgUserImp = Math.max(0, Math.min(Math.min(maxBgUserImp, remaining), + properties.getInt(KEY_PREFIX_MIN_BGUSER_IMPORTANT + mConfigIdentifier, + mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, 0)))); + mMinReservedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, minBgUserImp); // Ensure bg user is in the range [0, min(maxBgUser, remaining)] final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining), properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier, @@ -1176,6 +1227,10 @@ class JobConcurrencyManager { .println(); pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG)) .println(); + pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier, + mMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println(); + pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier, + mMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println(); pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BGUSER)).println(); pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier, @@ -1276,19 +1331,10 @@ class JobConcurrencyManager { void setConfig(@NonNull WorkTypeConfig workTypeConfig) { mConfigMaxTotal = workTypeConfig.getMaxTotal(); - mConfigNumReservedSlots.put(WORK_TYPE_TOP, - workTypeConfig.getMinReserved(WORK_TYPE_TOP)); - mConfigNumReservedSlots.put(WORK_TYPE_FGS, - workTypeConfig.getMinReserved(WORK_TYPE_FGS)); - mConfigNumReservedSlots.put(WORK_TYPE_EJ, workTypeConfig.getMinReserved(WORK_TYPE_EJ)); - mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG)); - mConfigNumReservedSlots.put(WORK_TYPE_BGUSER, - workTypeConfig.getMinReserved(WORK_TYPE_BGUSER)); - mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP)); - mConfigAbsoluteMaxSlots.put(WORK_TYPE_FGS, workTypeConfig.getMax(WORK_TYPE_FGS)); - mConfigAbsoluteMaxSlots.put(WORK_TYPE_EJ, workTypeConfig.getMax(WORK_TYPE_EJ)); - mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG)); - mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER)); + for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) { + mConfigNumReservedSlots.put(workType, workTypeConfig.getMinReserved(workType)); + mConfigAbsoluteMaxSlots.put(workType, workTypeConfig.getMax(workType)); + } mNumUnspecializedRemaining = mConfigMaxTotal; for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) { diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java index 7d9ab3772733c..dd9ae6592f5cb 100644 --- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java @@ -19,6 +19,7 @@ package com.android.server.job; import static com.android.server.job.JobConcurrencyManager.NUM_WORK_TYPES; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER_IMPORTANT; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; @@ -29,6 +30,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import android.annotation.NonNull; +import android.util.Log; import android.util.Pair; import android.util.SparseIntArray; @@ -52,11 +54,11 @@ import java.util.Random; @RunWith(AndroidJUnit4.class) @MediumTest public class WorkCountTrackerTest { - private static final String TAG = "WorkerCountTrackerTest"; + private static final String TAG = "WorkCountTrackerTest"; private static final double[] EQUAL_PROBABILITY_CDF = buildWorkTypeCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, - 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES); + 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES); private Random mRandom; private WorkCountTracker mWorkCountTracker; @@ -69,12 +71,15 @@ public class WorkCountTrackerTest { @NonNull private static double[] buildWorkTypeCdf( - double pTop, double pFgs, double pEj, double pBg, double pBgUser) { - return buildCdf(pTop, pFgs, pEj, pBg, pBgUser); + double pTop, double pFgs, double pEj, double pBg, double pBgUserImp, double pBgUser) { + return buildCdf(pTop, pFgs, pEj, pBg, pBgUserImp, pBgUser); } @NonNull private static double[] buildCdf(double... probs) { + if (probs.length == 0) { + throw new IllegalArgumentException("Must supply at least one probability"); + } double[] cdf = new double[probs.length]; double sum = 0; @@ -84,7 +89,9 @@ public class WorkCountTrackerTest { } if (Double.compare(1, sum) != 0) { - throw new IllegalArgumentException("probabilities don't sum to one: " + sum); + Log.e(TAG, "probabilities don't sum to one: " + sum); + // 1.0/6 doesn't work well in code :/ + cdf[cdf.length - 1] = 1; } return cdf; } @@ -111,6 +118,8 @@ public class WorkCountTrackerTest { case 3: return WORK_TYPE_BG; case 4: + return WORK_TYPE_BGUSER_IMPORTANT; + case 5: return WORK_TYPE_BGUSER; default: throw new IllegalStateException("Unknown work type"); @@ -312,7 +321,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final List> minLimits = List.of(); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0); + final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0, 0); final double[] numTypesCdf = buildCdf(.5, .3, .15, .05); final double probStart = 0.5; @@ -330,7 +339,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3); + final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3); final double[] numTypesCdf = buildCdf(.75, .2, .05); final double probStart = 0.5; @@ -348,7 +357,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final List> minLimits = List.of(); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3); + final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3); final double[] numTypesCdf = buildCdf(.05, .95); final double probStart = 0.5; @@ -366,7 +375,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, .1); + final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, 0.02, .08); final double[] numTypesCdf = buildCdf(.5, .3, .15, .05); final double probStart = 0.5; @@ -384,7 +393,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0); + final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0, 0); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; @@ -402,7 +411,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.4; - final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, .8); + final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, 0.05, .75); final double[] numTypesCdf = buildCdf(0.5, 0.5); final double probStart = 0.5; @@ -421,7 +430,7 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final double probStop = 0.4; - final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0.05); + final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0, 0.05); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; @@ -440,7 +449,7 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0.5); + final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0, 0.5); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; @@ -459,7 +468,7 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0.9); + final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0, 0.9); final double[] numTypesCdf = buildCdf(0.9, 0.1); final double probStart = 0.5; @@ -478,7 +487,7 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); final double probStop = 0.5; - final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0.1); + final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0, 0.1); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; @@ -496,7 +505,7 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.4; - final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0); + final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0, 0); final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2); final double probStart = 0.5; @@ -519,7 +528,7 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)); final double probStop = 0.13; - final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.8, 0.05); + final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.7, 0.1, 0.05); final double probStart = 0.87; checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, @@ -536,7 +545,7 @@ public class WorkCountTrackerTest { List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4)); final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.4; - final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0.05); + final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0, 0.05); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; @@ -556,7 +565,28 @@ public class WorkCountTrackerTest { final List> minLimits = List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)); final double probStop = 0.4; - final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0.4); + final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0, 0.4); + final double[] numTypesCdf = buildCdf(0.7, 0.3); + final double probStart = 0.5; + + checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + cdf, numTypesCdf, probStop); + } + + @Test + public void testRandom16() { + final Jobs jobs = new Jobs(); + + final int numTests = 5000; + final int totalMax = 7; + final List> maxLimits = + List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), + Pair.create(WORK_TYPE_BGUSER, 1)); + final List> minLimits = + List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)); + final double probStop = 0.4; + final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.25, 0.05, 0.3, 0.3); final double[] numTypesCdf = buildCdf(0.7, 0.3); final double probStart = 0.5; @@ -748,6 +778,7 @@ public class WorkCountTrackerTest { /* resPen */ List.of( Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2))); + Log.d(TAG, "START***#*#*#*#*#*#**#*"); // Test multi-types checkSimple(6, /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)), @@ -764,7 +795,10 @@ public class WorkCountTrackerTest { /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)), /* resPen */ List.of( - Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1))); + // Not checking BG count because the test starts jobs in random order + // and if it tries to start 4 BG jobs (2 will run as EJ from EJ|BG), but + // the resulting pending will be 3 BG instead of 4 BG. + Pair.create(WORK_TYPE_BGUSER, 1))); } /** Tests that the counter updates properly when jobs are stopped. */ diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java index cc18317d0529b..a5fedef23e00d 100644 --- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java @@ -17,6 +17,7 @@ package com.android.server.job; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER_IMPORTANT; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP; @@ -49,11 +50,13 @@ public class WorkTypeConfigTest { private static final String KEY_MAX_FGS = "concurrency_max_fgs_test"; private static final String KEY_MAX_EJ = "concurrency_max_ej_test"; private static final String KEY_MAX_BG = "concurrency_max_bg_test"; + private static final String KEY_MAX_BGUSER_IMPORTANT = "concurrency_max_bguser_important_test"; private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test"; private static final String KEY_MIN_TOP = "concurrency_min_top_test"; private static final String KEY_MIN_FGS = "concurrency_min_fgs_test"; private static final String KEY_MIN_EJ = "concurrency_min_ej_test"; private static final String KEY_MIN_BG = "concurrency_min_bg_test"; + private static final String KEY_MIN_BGUSER_IMPORTANT = "concurrency_min_bguser_important_test"; private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test"; @After @@ -68,11 +71,15 @@ public class WorkTypeConfigTest { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_FGS, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, null, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, + KEY_MAX_BGUSER_IMPORTANT, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_FGS, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, null, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, + KEY_MIN_BGUSER_IMPORTANT, null, false); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, null, false); } @@ -316,19 +323,23 @@ public class WorkTypeConfigTest { .setInt(KEY_MIN_EJ, 3) .setInt(KEY_MAX_BG, 13) .setInt(KEY_MIN_BG, 4) - .setInt(KEY_MAX_BGUSER, 12) - .setInt(KEY_MIN_BGUSER, 5) + .setInt(KEY_MAX_BGUSER_IMPORTANT, 12) + .setInt(KEY_MIN_BGUSER_IMPORTANT, 5) + .setInt(KEY_MAX_BGUSER, 11) + .setInt(KEY_MIN_BGUSER, 6) .build(), /*default*/ 9, /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), /*expected*/ true, 16, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 3), - Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 5)), + Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 4), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 5), + Pair.create(WORK_TYPE_BGUSER, 6)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_FGS, 15), - Pair.create(WORK_TYPE_EJ, 14), - Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 12))); + Pair.create(WORK_TYPE_EJ, 14), Pair.create(WORK_TYPE_BG, 13), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 12), + Pair.create(WORK_TYPE_BGUSER, 11))); } }