Merge "Let EJs for TOP app run immediately and without limit." into tm-dev am: fdaa18f597
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17452330 Change-Id: Ie9bdc76f8a5586b7f82eae65f56861d922d9e3f7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.server.job;
|
||||
|
||||
import static com.android.server.job.JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
|
||||
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
|
||||
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
|
||||
|
||||
@@ -82,6 +81,11 @@ class JobConcurrencyManager {
|
||||
private static final String TAG = JobSchedulerService.TAG + ".Concurrency";
|
||||
private static final boolean DEBUG = JobSchedulerService.DEBUG;
|
||||
|
||||
/** The maximum number of concurrent jobs we'll aim to run at one time. */
|
||||
public static final int STANDARD_CONCURRENCY_LIMIT = 16;
|
||||
/** The maximum number of objects we should retain in memory when not in use. */
|
||||
private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * STANDARD_CONCURRENCY_LIMIT);
|
||||
|
||||
static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_";
|
||||
private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS =
|
||||
CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
|
||||
@@ -93,7 +97,7 @@ class JobConcurrencyManager {
|
||||
@VisibleForTesting
|
||||
static final String KEY_PKG_CONCURRENCY_LIMIT_REGULAR =
|
||||
CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_regular";
|
||||
private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = MAX_JOB_CONTEXTS_COUNT / 2;
|
||||
private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = STANDARD_CONCURRENCY_LIMIT / 2;
|
||||
|
||||
/**
|
||||
* Set of possible execution types that a job can have. The actual type(s) of a job are based
|
||||
@@ -309,7 +313,7 @@ class JobConcurrencyManager {
|
||||
private final ArrayList<ContextAssignment> mRecycledStoppable = new ArrayList<>();
|
||||
|
||||
private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
|
||||
new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
|
||||
new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
|
||||
|
||||
/**
|
||||
* Set of JobServiceContexts that are actively running jobs.
|
||||
@@ -317,14 +321,16 @@ class JobConcurrencyManager {
|
||||
final List<JobServiceContext> mActiveServices = new ArrayList<>();
|
||||
|
||||
/** Set of JobServiceContexts that aren't currently running any jobs. */
|
||||
final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>();
|
||||
private final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>();
|
||||
|
||||
private int mNumDroppedContexts = 0;
|
||||
|
||||
private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
|
||||
|
||||
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
|
||||
|
||||
private final Pools.Pool<PackageStats> mPkgStatsPool =
|
||||
new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
|
||||
new Pools.SimplePool<>(MAX_RETAINED_OBJECTS);
|
||||
|
||||
private final SparseArrayMap<String, PackageStats> mActivePkgStats = new SparseArrayMap<>();
|
||||
|
||||
@@ -406,7 +412,7 @@ class JobConcurrencyManager {
|
||||
void onThirdPartyAppsCanStart() {
|
||||
final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
|
||||
ServiceManager.getService(BatteryStats.SERVICE_NAME));
|
||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
||||
for (int i = 0; i < STANDARD_CONCURRENCY_LIMIT; i++) {
|
||||
mIdleContexts.add(
|
||||
new JobServiceContext(mService, this, batteryStats,
|
||||
mService.mJobPackageTracker, mContext.getMainLooper()));
|
||||
@@ -655,13 +661,13 @@ class JobConcurrencyManager {
|
||||
}
|
||||
preferredUidOnly.sort(sDeterminationComparator);
|
||||
stoppable.sort(sDeterminationComparator);
|
||||
for (int i = numRunningJobs; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
|
||||
for (int i = numRunningJobs; i < STANDARD_CONCURRENCY_LIMIT; ++i) {
|
||||
final JobServiceContext jsc;
|
||||
final int numIdleContexts = mIdleContexts.size();
|
||||
if (numIdleContexts > 0) {
|
||||
jsc = mIdleContexts.removeAt(numIdleContexts - 1);
|
||||
} else {
|
||||
Slog.wtf(TAG, "Had fewer than " + MAX_JOB_CONTEXTS_COUNT + " in existence");
|
||||
Slog.wtf(TAG, "Had fewer than " + STANDARD_CONCURRENCY_LIMIT + " in existence");
|
||||
jsc = createNewJobServiceContext();
|
||||
}
|
||||
|
||||
@@ -681,6 +687,7 @@ class JobConcurrencyManager {
|
||||
|
||||
JobStatus nextPending;
|
||||
pendingJobQueue.resetIterator();
|
||||
int projectedRunningCount = numRunningJobs;
|
||||
while ((nextPending = pendingJobQueue.next()) != null) {
|
||||
if (mRunningJobs.contains(nextPending)) {
|
||||
continue;
|
||||
@@ -694,6 +701,9 @@ class JobConcurrencyManager {
|
||||
ContextAssignment selectedContext = null;
|
||||
final int allWorkTypes = getJobWorkTypes(nextPending);
|
||||
final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
|
||||
final boolean isTopEj = nextPending.shouldTreatAsExpeditedJob()
|
||||
&& nextPending.lastEvaluatedBias == JobInfo.BIAS_TOP_APP;
|
||||
final boolean isInOverage = projectedRunningCount > STANDARD_CONCURRENCY_LIMIT;
|
||||
boolean startingJob = false;
|
||||
if (idle.size() > 0) {
|
||||
final int idx = idle.size() - 1;
|
||||
@@ -711,14 +721,36 @@ class JobConcurrencyManager {
|
||||
assignment.newWorkType = workType;
|
||||
}
|
||||
}
|
||||
if (selectedContext == null) {
|
||||
if (selectedContext == null && stoppable.size() > 0) {
|
||||
int topEjCount = 0;
|
||||
for (int r = mRunningJobs.size() - 1; r >= 0; --r) {
|
||||
JobStatus js = mRunningJobs.valueAt(r);
|
||||
if (js.startedAsExpeditedJob && js.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
|
||||
topEjCount++;
|
||||
}
|
||||
}
|
||||
for (int s = stoppable.size() - 1; s >= 0; --s) {
|
||||
final ContextAssignment assignment = stoppable.get(s);
|
||||
final JobStatus runningJob = assignment.context.getRunningJobLocked();
|
||||
// Maybe stop the job if it has had its day in the sun. Don't let a different
|
||||
// app preempt jobs started for TOP apps though.
|
||||
if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
|
||||
&& assignment.shouldStopJobReason != null) {
|
||||
// Maybe stop the job if it has had its day in the sun. Only allow replacing
|
||||
// for one of the following conditions:
|
||||
// 1. We're putting in the current TOP app's EJ
|
||||
// 2. There aren't too many jobs running AND the current job started when the
|
||||
// app was in the background
|
||||
// 3. There aren't too many jobs running AND the current job started when the
|
||||
// app was on TOP, but the app has since left TOP
|
||||
// 4. There aren't too many jobs running AND the current job started when the
|
||||
// app was on TOP, the app is still TOP, but there are too many TOP+EJs
|
||||
// running (because we don't want them to starve out other apps and the
|
||||
// current job has already run for the minimum guaranteed time).
|
||||
boolean canReplace = isTopEj; // Case 1
|
||||
if (!canReplace && !isInOverage) {
|
||||
final int currentJobBias = mService.evaluateJobBiasLocked(runningJob);
|
||||
canReplace = runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP // Case 2
|
||||
|| currentJobBias < JobInfo.BIAS_TOP_APP // Case 3
|
||||
|| topEjCount > .5 * mWorkTypeConfig.getMaxTotal(); // Case 4
|
||||
}
|
||||
if (canReplace) {
|
||||
int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes,
|
||||
assignment.context.getRunningJobWorkType());
|
||||
if (replaceWorkType != WORK_TYPE_NONE) {
|
||||
@@ -736,7 +768,7 @@ class JobConcurrencyManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedContext == null) {
|
||||
if (selectedContext == null && (!isInOverage || isTopEj)) {
|
||||
int lowestBiasSeen = Integer.MAX_VALUE;
|
||||
for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
|
||||
final ContextAssignment assignment = preferredUidOnly.get(p);
|
||||
@@ -765,10 +797,43 @@ class JobConcurrencyManager {
|
||||
preferredUidOnly.remove(selectedContext);
|
||||
}
|
||||
}
|
||||
// Make sure to run EJs for the TOP app immediately.
|
||||
if (isTopEj) {
|
||||
if (selectedContext != null
|
||||
&& selectedContext.context.getRunningJobLocked() != null) {
|
||||
// We're "replacing" a currently running job, but we want TOP EJs to start
|
||||
// immediately, so we'll start the EJ on a fresh available context and
|
||||
// stop this currently running job to replace in two steps.
|
||||
changed.add(selectedContext);
|
||||
projectedRunningCount--;
|
||||
selectedContext.newJob = null;
|
||||
selectedContext.newWorkType = WORK_TYPE_NONE;
|
||||
selectedContext = null;
|
||||
}
|
||||
if (selectedContext == null) {
|
||||
selectedContext = mContextAssignmentPool.acquire();
|
||||
if (selectedContext == null) {
|
||||
selectedContext = new ContextAssignment();
|
||||
}
|
||||
selectedContext.context = mIdleContexts.size() > 0
|
||||
? mIdleContexts.removeAt(mIdleContexts.size() - 1)
|
||||
: createNewJobServiceContext();
|
||||
selectedContext.newJob = nextPending;
|
||||
final int workType = mWorkCountTracker.canJobStart(allWorkTypes);
|
||||
selectedContext.newWorkType =
|
||||
(workType != WORK_TYPE_NONE) ? workType : WORK_TYPE_TOP;
|
||||
}
|
||||
}
|
||||
final PackageStats packageStats = getPkgStatsLocked(
|
||||
nextPending.getSourceUserId(), nextPending.getSourcePackageName());
|
||||
if (selectedContext != null) {
|
||||
changed.add(selectedContext);
|
||||
if (selectedContext.context.getRunningJobLocked() != null) {
|
||||
projectedRunningCount--;
|
||||
}
|
||||
if (selectedContext.newJob != null) {
|
||||
projectedRunningCount++;
|
||||
}
|
||||
packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
|
||||
}
|
||||
if (startingJob) {
|
||||
@@ -793,7 +858,7 @@ class JobConcurrencyManager {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "preempting job: " + js);
|
||||
}
|
||||
// preferredUid will be set to uid of currently running job.
|
||||
// preferredUid will be set to uid of currently running job, if appropriate.
|
||||
assignment.context.cancelExecutingJobLocked(
|
||||
assignment.preemptReasonCode,
|
||||
JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason);
|
||||
@@ -811,9 +876,6 @@ class JobConcurrencyManager {
|
||||
}
|
||||
for (int s = stoppable.size() - 1; s >= 0; --s) {
|
||||
final ContextAssignment assignment = stoppable.get(s);
|
||||
// The preferred UID is set when we cancel with PREEMPT reason, but don't preserve the
|
||||
// UID for any stoppable contexts since we want to open the context up to any/all apps.
|
||||
assignment.context.clearPreferredUid();
|
||||
assignment.clear();
|
||||
mContextAssignmentPool.release(assignment);
|
||||
}
|
||||
@@ -837,6 +899,21 @@ class JobConcurrencyManager {
|
||||
noteConcurrency();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
void onUidBiasChangedLocked(int prevBias, int newBias) {
|
||||
if (prevBias != JobInfo.BIAS_TOP_APP && newBias != JobInfo.BIAS_TOP_APP) {
|
||||
// TOP app didn't change. Nothing to do.
|
||||
return;
|
||||
}
|
||||
if (mService.getPendingJobQueue().size() == 0) {
|
||||
// Nothing waiting for the top app to leave. Nothing to do.
|
||||
return;
|
||||
}
|
||||
// Don't stop the TOP jobs directly. Instead, see if they would be replaced by some
|
||||
// pending job (there may not always be something to replace them).
|
||||
assignJobsToContextsLocked();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean stopJobOnServiceContextLocked(JobStatus job,
|
||||
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
|
||||
@@ -1041,7 +1118,13 @@ class JobConcurrencyManager {
|
||||
mWorkCountTracker.onJobFinished(workType);
|
||||
mRunningJobs.remove(jobStatus);
|
||||
mActiveServices.remove(worker);
|
||||
mIdleContexts.add(worker);
|
||||
if (mIdleContexts.size() < MAX_RETAINED_OBJECTS) {
|
||||
// Don't need to save all new contexts, but keep some extra around in case we need
|
||||
// extras for another TOP+EJ overage.
|
||||
mIdleContexts.add(worker);
|
||||
} else {
|
||||
mNumDroppedContexts++;
|
||||
}
|
||||
final PackageStats packageStats =
|
||||
mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
|
||||
if (packageStats == null) {
|
||||
@@ -1054,6 +1137,14 @@ class JobConcurrencyManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT) {
|
||||
worker.clearPreferredUid();
|
||||
// We're over the limit (because the TOP app scheduled a lot of EJs). Don't start
|
||||
// running anything new until we get back below the limit.
|
||||
noteConcurrency();
|
||||
return;
|
||||
}
|
||||
|
||||
final PendingJobQueue pendingJobQueue = mService.getPendingJobQueue();
|
||||
if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) {
|
||||
updateCounterConfigLocked();
|
||||
@@ -1245,6 +1336,18 @@ class JobConcurrencyManager {
|
||||
}
|
||||
} else if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) {
|
||||
return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue";
|
||||
} else if (js.startedAsExpeditedJob && js.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
|
||||
// Try not to let TOP + EJ starve out other apps.
|
||||
int topEjCount = 0;
|
||||
for (int r = mRunningJobs.size() - 1; r >= 0; --r) {
|
||||
JobStatus j = mRunningJobs.valueAt(r);
|
||||
if (j.startedAsExpeditedJob && j.lastEvaluatedBias == JobInfo.BIAS_TOP_APP) {
|
||||
topEjCount++;
|
||||
}
|
||||
}
|
||||
if (topEjCount > .5 * mWorkTypeConfig.getMaxTotal()) {
|
||||
return "prevent top EJ dominance";
|
||||
}
|
||||
}
|
||||
// No other pending EJs. Return null so we don't let regular jobs preempt an EJ.
|
||||
return null;
|
||||
@@ -1361,10 +1464,10 @@ class JobConcurrencyManager {
|
||||
CONFIG_LIMITS_SCREEN_OFF.low.update(properties);
|
||||
CONFIG_LIMITS_SCREEN_OFF.critical.update(properties);
|
||||
|
||||
// Package concurrency limits must in the range [1, MAX_JOB_CONTEXTS_COUNT].
|
||||
mPkgConcurrencyLimitEj = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
|
||||
// Package concurrency limits must in the range [1, STANDARD_CONCURRENCY_LIMIT].
|
||||
mPkgConcurrencyLimitEj = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
|
||||
properties.getInt(KEY_PKG_CONCURRENCY_LIMIT_EJ, DEFAULT_PKG_CONCURRENCY_LIMIT_EJ)));
|
||||
mPkgConcurrencyLimitRegular = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
|
||||
mPkgConcurrencyLimitRegular = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
|
||||
properties.getInt(
|
||||
KEY_PKG_CONCURRENCY_LIMIT_REGULAR, DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR)));
|
||||
}
|
||||
@@ -1492,6 +1595,13 @@ class JobConcurrencyManager {
|
||||
jsc.dumpLocked(pw, nowElapsed);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
if (mNumDroppedContexts > 0) {
|
||||
pw.println();
|
||||
pw.print("Dropped ");
|
||||
pw.print(mNumDroppedContexts);
|
||||
pw.println(" contexts");
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
|
||||
@@ -1600,7 +1710,7 @@ class JobConcurrencyManager {
|
||||
WorkTypeConfig(@NonNull String configIdentifier, int defaultMaxTotal,
|
||||
List<Pair<Integer, Integer>> defaultMin, List<Pair<Integer, Integer>> defaultMax) {
|
||||
mConfigIdentifier = configIdentifier;
|
||||
mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, MAX_JOB_CONTEXTS_COUNT);
|
||||
mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, STANDARD_CONCURRENCY_LIMIT);
|
||||
int numReserved = 0;
|
||||
for (int i = defaultMin.size() - 1; i >= 0; --i) {
|
||||
mDefaultMinReservedSlots.put(defaultMin.get(i).first, defaultMin.get(i).second);
|
||||
@@ -1621,8 +1731,8 @@ class JobConcurrencyManager {
|
||||
}
|
||||
|
||||
void update(@NonNull DeviceConfig.Properties properties) {
|
||||
// Ensure total in the range [1, MAX_JOB_CONTEXTS_COUNT].
|
||||
mMaxTotal = Math.max(1, Math.min(MAX_JOB_CONTEXTS_COUNT,
|
||||
// Ensure total in the range [1, STANDARD_CONCURRENCY_LIMIT].
|
||||
mMaxTotal = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT,
|
||||
properties.getInt(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mDefaultMaxTotal)));
|
||||
|
||||
mMaxAllowedSlots.clear();
|
||||
|
||||
@@ -159,8 +159,6 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
public static final boolean DEBUG_STANDBY = DEBUG || false;
|
||||
|
||||
/** The maximum number of concurrent jobs we run at one time. */
|
||||
static final int MAX_JOB_CONTEXTS_COUNT = 16;
|
||||
/** The maximum number of jobs that we allow an app to schedule */
|
||||
private static final int MAX_JOBS_PER_APP = 150;
|
||||
/** The number of the most recently completed jobs to keep track of for debugging purposes. */
|
||||
@@ -1423,6 +1421,7 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
for (int c = 0; c < mControllers.size(); ++c) {
|
||||
mControllers.get(c).onUidBiasChangedLocked(uid, prevBias, newBias);
|
||||
}
|
||||
mConcurrencyManager.onUidBiasChangedLocked(prevBias, newBias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +751,8 @@ public final class JobServiceContext implements ServiceConnection {
|
||||
}
|
||||
}
|
||||
mParams.setStopReason(stopReasonCode, internalStopReasonCode, debugReason);
|
||||
if (internalStopReasonCode == JobParameters.INTERNAL_STOP_REASON_PREEMPT) {
|
||||
if (stopReasonCode == JobParameters.STOP_REASON_PREEMPT) {
|
||||
// Only preserve the UID when we're preempting the job for another one of the same UID.
|
||||
mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : NO_PREFERRED_UID;
|
||||
}
|
||||
handleCancelLocked(debugReason);
|
||||
|
||||
@@ -297,9 +297,9 @@ public final class QuotaController extends StateController {
|
||||
private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
|
||||
|
||||
/**
|
||||
* List of jobs that started while the UID was in the TOP state. There will be no more than
|
||||
* 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
|
||||
* fine.
|
||||
* List of jobs that started while the UID was in the TOP state. There will usually be no more
|
||||
* than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an
|
||||
* ArraySet is fine.
|
||||
*/
|
||||
private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
|
||||
|
||||
|
||||
@@ -289,9 +289,9 @@ public class TareController extends StateController {
|
||||
};
|
||||
|
||||
/**
|
||||
* List of jobs that started while the UID was in the TOP state. There will be no more than
|
||||
* 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
|
||||
* fine.
|
||||
* List of jobs that started while the UID was in the TOP state. There will usually be no more
|
||||
* than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an
|
||||
* ArraySet is fine.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
|
||||
|
||||
@@ -116,14 +116,14 @@ public final class JobConcurrencyManagerTest {
|
||||
assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));
|
||||
|
||||
// Pending jobs shouldn't affect TOP job's status.
|
||||
for (int i = 1; i <= JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
|
||||
for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
|
||||
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i);
|
||||
mPendingJobQueue.add(job);
|
||||
}
|
||||
assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob));
|
||||
|
||||
// Already running jobs shouldn't affect TOP job's status.
|
||||
for (int i = 1; i <= JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
|
||||
for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
|
||||
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, i);
|
||||
mJobConcurrencyManager.addRunningJobForTesting(job);
|
||||
}
|
||||
@@ -183,9 +183,9 @@ public final class JobConcurrencyManagerTest {
|
||||
spyOn(testEj);
|
||||
doReturn(true).when(testEj).shouldTreatAsExpeditedJob();
|
||||
|
||||
setConcurrencyConfig(JobSchedulerService.MAX_JOB_CONTEXTS_COUNT);
|
||||
setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT);
|
||||
|
||||
for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
|
||||
for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
|
||||
final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i, i + 1);
|
||||
mPendingJobQueue.add(job);
|
||||
}
|
||||
|
||||
@@ -57,14 +57,14 @@ public class BiasSchedulingTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testLowerBiasJobPreempted() throws Exception {
|
||||
for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
|
||||
for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
|
||||
JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
|
||||
.setBias(LOW_BIAS)
|
||||
.setOverrideDeadline(0)
|
||||
.build();
|
||||
mJobScheduler.schedule(job);
|
||||
}
|
||||
final int higherBiasJobId = 100 + JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
|
||||
final int higherBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
|
||||
JobInfo jobHigher = new JobInfo.Builder(higherBiasJobId, sJobServiceComponent)
|
||||
.setBias(HIGH_BIAS)
|
||||
.setMinimumLatency(2000)
|
||||
@@ -88,14 +88,14 @@ public class BiasSchedulingTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testHigherBiasJobNotPreempted() throws Exception {
|
||||
for (int i = 0; i < JobSchedulerService.MAX_JOB_CONTEXTS_COUNT; ++i) {
|
||||
for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) {
|
||||
JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent)
|
||||
.setBias(HIGH_BIAS)
|
||||
.setOverrideDeadline(0)
|
||||
.build();
|
||||
mJobScheduler.schedule(job);
|
||||
}
|
||||
final int lowerBiasJobId = 100 + JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
|
||||
final int lowerBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT;
|
||||
JobInfo jobLower = new JobInfo.Builder(lowerBiasJobId, sJobServiceComponent)
|
||||
.setBias(LOW_BIAS)
|
||||
.setMinimumLatency(2000)
|
||||
|
||||
Reference in New Issue
Block a user