Merge "Change context assignment mechanism." into tm-dev
This commit is contained in:
@@ -273,23 +273,22 @@ class JobConcurrencyManager {
|
|||||||
*/
|
*/
|
||||||
JobStatus[] mRecycledAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
|
JobStatus[] mRecycledAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT];
|
||||||
|
|
||||||
boolean[] mRecycledSlotChanged = new boolean[MAX_JOB_CONTEXTS_COUNT];
|
private final ArraySet<ContextAssignment> mRecycledChanged = new ArraySet<>();
|
||||||
|
private final ArraySet<ContextAssignment> mRecycledIdle = new ArraySet<>();
|
||||||
|
private final ArraySet<ContextAssignment> mRecycledPreferredUidOnly = new ArraySet<>();
|
||||||
|
private final ArraySet<ContextAssignment> mRecycledStoppable = new ArraySet<>();
|
||||||
|
|
||||||
int[] mRecycledPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
|
private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
|
||||||
|
new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT);
|
||||||
int[] mRecycledWorkTypeForContext = new int[MAX_JOB_CONTEXTS_COUNT];
|
|
||||||
|
|
||||||
String[] mRecycledPreemptReasonForContext = new String[MAX_JOB_CONTEXTS_COUNT];
|
|
||||||
|
|
||||||
int[] mRecycledPreemptReasonCodeForContext = new int[MAX_JOB_CONTEXTS_COUNT];
|
|
||||||
|
|
||||||
String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of JobServiceContexts that we use to run jobs.
|
* Set of JobServiceContexts that are actively running jobs.
|
||||||
*/
|
*/
|
||||||
final List<JobServiceContext> mActiveServices = new ArrayList<>();
|
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<JobStatus> mRunningJobs = new ArraySet<>();
|
private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
|
||||||
|
|
||||||
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
|
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
|
||||||
@@ -378,7 +377,7 @@ class JobConcurrencyManager {
|
|||||||
final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
|
final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
|
||||||
ServiceManager.getService(BatteryStats.SERVICE_NAME));
|
ServiceManager.getService(BatteryStats.SERVICE_NAME));
|
||||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
||||||
mActiveServices.add(
|
mIdleContexts.add(
|
||||||
new JobServiceContext(mService, this, batteryStats,
|
new JobServiceContext(mService, this, batteryStats,
|
||||||
mService.mJobPackageTracker, mContext.getMainLooper()));
|
mService.mJobPackageTracker, mContext.getMainLooper()));
|
||||||
}
|
}
|
||||||
@@ -582,12 +581,10 @@ class JobConcurrencyManager {
|
|||||||
|
|
||||||
// To avoid GC churn, we recycle the arrays.
|
// To avoid GC churn, we recycle the arrays.
|
||||||
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
|
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
|
||||||
boolean[] slotChanged = mRecycledSlotChanged;
|
final ArraySet<ContextAssignment> changed = mRecycledChanged;
|
||||||
int[] preferredUidForContext = mRecycledPreferredUidForContext;
|
final ArraySet<ContextAssignment> idle = mRecycledIdle;
|
||||||
int[] workTypeForContext = mRecycledWorkTypeForContext;
|
final ArraySet<ContextAssignment> preferredUidOnly = mRecycledPreferredUidOnly;
|
||||||
String[] preemptReasonForContext = mRecycledPreemptReasonForContext;
|
final ArraySet<ContextAssignment> stoppable = mRecycledStoppable;
|
||||||
int[] preemptReasonCodeForContext = mRecycledPreemptReasonCodeForContext;
|
|
||||||
String[] shouldStopJobReason = mRecycledShouldStopJobReason;
|
|
||||||
|
|
||||||
updateCounterConfigLocked();
|
updateCounterConfigLocked();
|
||||||
// Reset everything since we'll re-evaluate the current state.
|
// Reset everything since we'll re-evaluate the current state.
|
||||||
@@ -598,20 +595,47 @@ class JobConcurrencyManager {
|
|||||||
// shouldStopRunningJobLocked().
|
// shouldStopRunningJobLocked().
|
||||||
updateNonRunningPrioritiesLocked(pendingJobQueue, true);
|
updateNonRunningPrioritiesLocked(pendingJobQueue, true);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
final int numRunningJobs = activeServices.size();
|
||||||
final JobServiceContext js = activeServices.get(i);
|
for (int i = 0; i < numRunningJobs; ++i) {
|
||||||
final JobStatus status = js.getRunningJobLocked();
|
final JobServiceContext jsc = activeServices.get(i);
|
||||||
|
final JobStatus js = jsc.getRunningJobLocked();
|
||||||
|
|
||||||
if ((contextIdToJobMap[i] = status) != null) {
|
ContextAssignment assignment = mContextAssignmentPool.acquire();
|
||||||
mWorkCountTracker.incrementRunningJobCount(js.getRunningJobWorkType());
|
if (assignment == null) {
|
||||||
workTypeForContext[i] = js.getRunningJobWorkType();
|
assignment = new ContextAssignment();
|
||||||
}
|
}
|
||||||
|
|
||||||
slotChanged[i] = false;
|
assignment.context = jsc;
|
||||||
preferredUidForContext[i] = js.getPreferredUid();
|
|
||||||
preemptReasonForContext[i] = null;
|
if (js != null) {
|
||||||
preemptReasonCodeForContext[i] = JobParameters.STOP_REASON_UNDEFINED;
|
mWorkCountTracker.incrementRunningJobCount(jsc.getRunningJobWorkType());
|
||||||
shouldStopJobReason[i] = shouldStopRunningJobLocked(js);
|
assignment.workType = jsc.getRunningJobWorkType();
|
||||||
|
}
|
||||||
|
|
||||||
|
assignment.preferredUid = jsc.getPreferredUid();
|
||||||
|
if ((assignment.shouldStopJobReason = shouldStopRunningJobLocked(jsc)) != null) {
|
||||||
|
stoppable.add(assignment);
|
||||||
|
} else {
|
||||||
|
preferredUidOnly.add(assignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = numRunningJobs; i < MAX_JOB_CONTEXTS_COUNT; ++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");
|
||||||
|
jsc = createNewJobServiceContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextAssignment assignment = mContextAssignmentPool.acquire();
|
||||||
|
if (assignment == null) {
|
||||||
|
assignment = new ContextAssignment();
|
||||||
|
}
|
||||||
|
|
||||||
|
assignment.context = jsc;
|
||||||
|
idle.add(assignment);
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
|
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
|
||||||
@@ -626,83 +650,97 @@ class JobConcurrencyManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find an available slot for nextPending. The context should be available OR
|
// Find an available slot for nextPending. The context should be one of the following:
|
||||||
// it should have the lowest bias among all running jobs
|
// 1. Unused
|
||||||
// (sharing the same Uid as nextPending)
|
// 2. Its job should have used up its minimum execution guarantee so it
|
||||||
int minBiasForPreemption = Integer.MAX_VALUE;
|
// 3. Its job should have the lowest bias among all running jobs (sharing the same UID
|
||||||
int selectedContextId = -1;
|
// as nextPending)
|
||||||
int allWorkTypes = getJobWorkTypes(nextPending);
|
ContextAssignment selectedContext = null;
|
||||||
int workType = mWorkCountTracker.canJobStart(allWorkTypes);
|
final int allWorkTypes = getJobWorkTypes(nextPending);
|
||||||
boolean startingJob = false;
|
|
||||||
int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
|
|
||||||
String preemptReason = null;
|
|
||||||
final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
|
final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
|
||||||
// TODO(141645789): rewrite this to look at empty contexts first so we don't
|
boolean startingJob = false;
|
||||||
// unnecessarily preempt
|
if (idle.size() > 0) {
|
||||||
for (int j = 0; j < MAX_JOB_CONTEXTS_COUNT; j++) {
|
final int idx = idle.size() - 1;
|
||||||
JobStatus job = contextIdToJobMap[j];
|
final ContextAssignment assignment = idle.valueAt(idx);
|
||||||
int preferredUid = preferredUidForContext[j];
|
final boolean preferredUidOkay = (assignment.preferredUid == nextPending.getUid())
|
||||||
if (job == null) {
|
|| (assignment.preferredUid == JobServiceContext.NO_PREFERRED_UID);
|
||||||
final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
|
int workType = mWorkCountTracker.canJobStart(allWorkTypes);
|
||||||
|| (preferredUid == JobServiceContext.NO_PREFERRED_UID);
|
|
||||||
|
|
||||||
if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
|
if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
|
||||||
// This slot is free, and we haven't yet hit the limit on
|
// This slot is free, and we haven't yet hit the limit on
|
||||||
// concurrent jobs... we can just throw the job in to here.
|
// concurrent jobs... we can just throw the job in to here.
|
||||||
selectedContextId = j;
|
selectedContext = assignment;
|
||||||
startingJob = true;
|
startingJob = true;
|
||||||
break;
|
idle.removeAt(idx);
|
||||||
|
assignment.newJob = nextPending;
|
||||||
|
assignment.newWorkType = workType;
|
||||||
}
|
}
|
||||||
// No job on this context, but nextPending can't run here because
|
|
||||||
// the context has a preferred Uid or we have reached the limit on
|
|
||||||
// concurrent jobs.
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (job.getUid() != nextPending.getUid()) {
|
if (selectedContext == null) {
|
||||||
|
for (int s = stoppable.size() - 1; s >= 0; --s) {
|
||||||
|
ContextAssignment assignment = stoppable.valueAt(s);
|
||||||
|
JobStatus runningJob = assignment.context.getRunningJobLocked();
|
||||||
// Maybe stop the job if it has had its day in the sun. Don't let a different
|
// 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.
|
// app preempt jobs started for TOP apps though.
|
||||||
final String reason = shouldStopJobReason[j];
|
if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
|
||||||
if (job.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
|
&& assignment.shouldStopJobReason != null) {
|
||||||
&& reason != null && mWorkCountTracker.canJobStart(allWorkTypes,
|
int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes,
|
||||||
activeServices.get(j).getRunningJobWorkType()) != WORK_TYPE_NONE) {
|
assignment.context.getRunningJobWorkType());
|
||||||
|
if (replaceWorkType != WORK_TYPE_NONE) {
|
||||||
// Right now, the way the code is set up, we don't need to explicitly
|
// Right now, the way the code is set up, we don't need to explicitly
|
||||||
// assign the new job to this context since we'll reassign when the
|
// assign the new job to this context since we'll reassign when the
|
||||||
// preempted job finally stops.
|
// preempted job finally stops.
|
||||||
preemptReason = reason;
|
assignment.preemptReason = assignment.shouldStopJobReason;
|
||||||
preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
|
assignment.preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
|
||||||
|
selectedContext = assignment;
|
||||||
|
stoppable.removeAt(s);
|
||||||
|
assignment.newJob = nextPending;
|
||||||
|
assignment.newWorkType = replaceWorkType;
|
||||||
|
// Don't preserve the UID since we're stopping the job because
|
||||||
|
// something is pending (eg. EJs).
|
||||||
|
assignment.context.clearPreferredUid();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedContext == null) {
|
||||||
|
int lowestBiasSeen = Integer.MAX_VALUE;
|
||||||
|
for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
|
||||||
|
final ContextAssignment assignment = preferredUidOnly.valueAt(p);
|
||||||
|
final JobStatus runningJob = assignment.context.getRunningJobLocked();
|
||||||
|
if (runningJob.getUid() != nextPending.getUid()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
final int jobBias = mService.evaluateJobBiasLocked(runningJob);
|
||||||
final int jobBias = mService.evaluateJobBiasLocked(job);
|
|
||||||
if (jobBias >= nextPending.lastEvaluatedBias) {
|
if (jobBias >= nextPending.lastEvaluatedBias) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minBiasForPreemption > jobBias) {
|
if (selectedContext == null || lowestBiasSeen > jobBias) {
|
||||||
// Step down the preemption threshold - wind up replacing
|
// Step down the preemption threshold - wind up replacing
|
||||||
// the lowest-bias running job
|
// the lowest-bias running job
|
||||||
minBiasForPreemption = jobBias;
|
lowestBiasSeen = jobBias;
|
||||||
selectedContextId = j;
|
selectedContext = assignment;
|
||||||
preemptReason = "higher bias job found";
|
assignment.preemptReason = "higher bias job found";
|
||||||
preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
|
assignment.preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
|
||||||
// In this case, we're just going to preempt a low bias job, we're not
|
// In this case, we're just going to preempt a low bias job, we're not
|
||||||
// actually starting a job, so don't set startingJob.
|
// actually starting a job, so don't set startingJob to true.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedContext != null) {
|
||||||
|
selectedContext.newJob = nextPending;
|
||||||
|
preferredUidOnly.remove(selectedContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final PackageStats packageStats = getPkgStatsLocked(
|
final PackageStats packageStats = getPkgStatsLocked(
|
||||||
nextPending.getSourceUserId(), nextPending.getSourcePackageName());
|
nextPending.getSourceUserId(), nextPending.getSourcePackageName());
|
||||||
if (selectedContextId != -1) {
|
if (selectedContext != null) {
|
||||||
contextIdToJobMap[selectedContextId] = nextPending;
|
changed.add(selectedContext);
|
||||||
slotChanged[selectedContextId] = true;
|
|
||||||
preemptReasonCodeForContext[selectedContextId] = preemptReasonCode;
|
|
||||||
preemptReasonForContext[selectedContextId] = preemptReason;
|
|
||||||
packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
|
packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
|
||||||
}
|
}
|
||||||
if (startingJob) {
|
if (startingJob) {
|
||||||
// Increase the counters when we're going to start a job.
|
// Increase the counters when we're going to start a job.
|
||||||
workTypeForContext[selectedContextId] = workType;
|
mWorkCountTracker.stageJob(selectedContext.newWorkType, allWorkTypes);
|
||||||
mWorkCountTracker.stageJob(workType, allWorkTypes);
|
|
||||||
mActivePkgStats.add(
|
mActivePkgStats.add(
|
||||||
nextPending.getSourceUserId(), nextPending.getSourcePackageName(),
|
nextPending.getSourceUserId(), nextPending.getSourcePackageName(),
|
||||||
packageStats);
|
packageStats);
|
||||||
@@ -714,37 +752,52 @@ class JobConcurrencyManager {
|
|||||||
Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString());
|
Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
for (int c = changed.size() - 1; c >= 0; --c) {
|
||||||
boolean preservePreferredUid = false;
|
final ContextAssignment assignment = changed.valueAt(c);
|
||||||
if (slotChanged[i]) {
|
final JobStatus js = assignment.context.getRunningJobLocked();
|
||||||
JobStatus js = activeServices.get(i).getRunningJobLocked();
|
|
||||||
if (js != null) {
|
if (js != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "preempting job: "
|
Slog.d(TAG, "preempting job: " + js);
|
||||||
+ activeServices.get(i).getRunningJobLocked());
|
|
||||||
}
|
}
|
||||||
// preferredUid will be set to uid of currently running job.
|
// preferredUid will be set to uid of currently running job.
|
||||||
activeServices.get(i).cancelExecutingJobLocked(
|
assignment.context.cancelExecutingJobLocked(
|
||||||
preemptReasonCodeForContext[i],
|
assignment.preemptReasonCode,
|
||||||
JobParameters.INTERNAL_STOP_REASON_PREEMPT, preemptReasonForContext[i]);
|
JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason);
|
||||||
// Only preserve the UID if we're preempting for the same UID. If we're stopping
|
|
||||||
// the job because something is pending (eg. EJs), then we shouldn't preserve
|
|
||||||
// the UID.
|
|
||||||
preservePreferredUid =
|
|
||||||
preemptReasonCodeForContext[i] == JobParameters.STOP_REASON_PREEMPT;
|
|
||||||
} else {
|
} else {
|
||||||
final JobStatus pendingJob = contextIdToJobMap[i];
|
final JobStatus pendingJob = assignment.newJob;
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "About to run job on context "
|
Slog.d(TAG, "About to run job on context "
|
||||||
+ i + ", job: " + pendingJob);
|
+ assignment.context.getId() + ", job: " + pendingJob);
|
||||||
}
|
}
|
||||||
startJobLocked(activeServices.get(i), pendingJob, workTypeForContext[i]);
|
startJobLocked(assignment.context, pendingJob, assignment.newWorkType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assignment.clear();
|
||||||
|
mContextAssignmentPool.release(assignment);
|
||||||
}
|
}
|
||||||
if (!preservePreferredUid) {
|
for (int s = stoppable.size() - 1; s >= 0; --s) {
|
||||||
activeServices.get(i).clearPreferredUid();
|
final ContextAssignment assignment = stoppable.valueAt(s);
|
||||||
|
assignment.context.clearPreferredUid();
|
||||||
|
assignment.clear();
|
||||||
|
mContextAssignmentPool.release(assignment);
|
||||||
}
|
}
|
||||||
|
for (int p = preferredUidOnly.size() - 1; p >= 0; --p) {
|
||||||
|
final ContextAssignment assignment = preferredUidOnly.valueAt(p);
|
||||||
|
assignment.context.clearPreferredUid();
|
||||||
|
assignment.clear();
|
||||||
|
mContextAssignmentPool.release(assignment);
|
||||||
}
|
}
|
||||||
|
for (int i = idle.size() - 1; i >= 0; --i) {
|
||||||
|
final ContextAssignment assignment = idle.valueAt(i);
|
||||||
|
mIdleContexts.add(assignment.context);
|
||||||
|
assignment.context.clearPreferredUid();
|
||||||
|
assignment.clear();
|
||||||
|
mContextAssignmentPool.release(assignment);
|
||||||
|
}
|
||||||
|
changed.clear();
|
||||||
|
idle.clear();
|
||||||
|
stoppable.clear();
|
||||||
|
preferredUidOnly.clear();
|
||||||
mWorkCountTracker.resetStagingCount();
|
mWorkCountTracker.resetStagingCount();
|
||||||
mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
|
mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
|
||||||
noteConcurrency();
|
noteConcurrency();
|
||||||
@@ -787,7 +840,7 @@ class JobConcurrencyManager {
|
|||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private void stopLongRunningJobsLocked(@NonNull String debugReason) {
|
private void stopLongRunningJobsLocked(@NonNull String debugReason) {
|
||||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
|
for (int i = 0; i < mActiveServices.size(); ++i) {
|
||||||
final JobServiceContext jsc = mActiveServices.get(i);
|
final JobServiceContext jsc = mActiveServices.get(i);
|
||||||
final JobStatus jobStatus = jsc.getRunningJobLocked();
|
final JobStatus jobStatus = jsc.getRunningJobLocked();
|
||||||
|
|
||||||
@@ -931,6 +984,8 @@ class JobConcurrencyManager {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mRunningJobs.add(jobStatus);
|
mRunningJobs.add(jobStatus);
|
||||||
|
mActiveServices.add(worker);
|
||||||
|
mIdleContexts.remove(worker);
|
||||||
mWorkCountTracker.onJobStarted(workType);
|
mWorkCountTracker.onJobStarted(workType);
|
||||||
packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
|
packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
|
||||||
mActivePkgStats.add(
|
mActivePkgStats.add(
|
||||||
@@ -950,6 +1005,8 @@ class JobConcurrencyManager {
|
|||||||
@WorkType final int workType) {
|
@WorkType final int workType) {
|
||||||
mWorkCountTracker.onJobFinished(workType);
|
mWorkCountTracker.onJobFinished(workType);
|
||||||
mRunningJobs.remove(jobStatus);
|
mRunningJobs.remove(jobStatus);
|
||||||
|
mActiveServices.remove(worker);
|
||||||
|
mIdleContexts.add(worker);
|
||||||
final PackageStats packageStats =
|
final PackageStats packageStats =
|
||||||
mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
|
mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
|
||||||
if (packageStats == null) {
|
if (packageStats == null) {
|
||||||
@@ -1093,7 +1150,7 @@ class JobConcurrencyManager {
|
|||||||
/**
|
/**
|
||||||
* Returns {@code null} if the job can continue running and a non-null String if the job should
|
* Returns {@code null} if the job can continue running and a non-null String if the job should
|
||||||
* be stopped. The non-null String details the reason for stopping the job. A job will generally
|
* be stopped. The non-null String details the reason for stopping the job. A job will generally
|
||||||
* be stopped if there similar job types waiting to be run and stopping this job would allow
|
* be stopped if there are similar job types waiting to be run and stopping this job would allow
|
||||||
* another job to run, or if system state suggests the job should stop.
|
* another job to run, or if system state suggests the job should stop.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -1202,6 +1259,14 @@ class JobConcurrencyManager {
|
|||||||
return foundSome;
|
return foundSome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private JobServiceContext createNewJobServiceContext() {
|
||||||
|
return new JobServiceContext(mService, this,
|
||||||
|
IBatteryStats.Stub.asInterface(
|
||||||
|
ServiceManager.getService(BatteryStats.SERVICE_NAME)),
|
||||||
|
mService.mJobPackageTracker, mContext.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private String printPendingQueueLocked() {
|
private String printPendingQueueLocked() {
|
||||||
StringBuilder s = new StringBuilder("Pending queue: ");
|
StringBuilder s = new StringBuilder("Pending queue: ");
|
||||||
@@ -1327,10 +1392,13 @@ class JobConcurrencyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
void dumpActiveJobsLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
|
void dumpContextInfoLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
|
||||||
long nowElapsed, long nowUptime) {
|
long nowElapsed, long nowUptime) {
|
||||||
pw.println("Active jobs:");
|
pw.println("Active jobs:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
|
if (mActiveServices.size() == 0) {
|
||||||
|
pw.println("N/A");
|
||||||
|
}
|
||||||
for (int i = 0; i < mActiveServices.size(); i++) {
|
for (int i = 0; i < mActiveServices.size(); i++) {
|
||||||
JobServiceContext jsc = mActiveServices.get(i);
|
JobServiceContext jsc = mActiveServices.get(i);
|
||||||
final JobStatus job = jsc.getRunningJobLocked();
|
final JobStatus job = jsc.getRunningJobLocked();
|
||||||
@@ -1339,7 +1407,8 @@ class JobConcurrencyManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.print("Slot #"); pw.print(i); pw.print(": ");
|
pw.print("Slot #"); pw.print(i);
|
||||||
|
pw.print("(ID="); pw.print(jsc.getId()); pw.print("): ");
|
||||||
jsc.dumpLocked(pw, nowElapsed);
|
jsc.dumpLocked(pw, nowElapsed);
|
||||||
|
|
||||||
if (job != null) {
|
if (job != null) {
|
||||||
@@ -1361,6 +1430,19 @@ class JobConcurrencyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
||||||
|
pw.println();
|
||||||
|
pw.print("Idle contexts (");
|
||||||
|
pw.print(mIdleContexts.size());
|
||||||
|
pw.println("):");
|
||||||
|
pw.increaseIndent();
|
||||||
|
for (int i = 0; i < mIdleContexts.size(); i++) {
|
||||||
|
JobServiceContext jsc = mIdleContexts.valueAt(i);
|
||||||
|
|
||||||
|
pw.print("ID="); pw.print(jsc.getId()); pw.print(": ");
|
||||||
|
jsc.dumpLocked(pw, nowElapsed);
|
||||||
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
|
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
|
||||||
@@ -1989,4 +2071,26 @@ class JobConcurrencyManager {
|
|||||||
pw.println("}");
|
pw.println("}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class ContextAssignment {
|
||||||
|
public JobServiceContext context;
|
||||||
|
public int preferredUid = JobServiceContext.NO_PREFERRED_UID;
|
||||||
|
public int workType = WORK_TYPE_NONE;
|
||||||
|
public String preemptReason;
|
||||||
|
public int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
|
||||||
|
public String shouldStopJobReason;
|
||||||
|
public JobStatus newJob;
|
||||||
|
public int newWorkType = WORK_TYPE_NONE;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
context = null;
|
||||||
|
preferredUid = JobServiceContext.NO_PREFERRED_UID;
|
||||||
|
workType = WORK_TYPE_NONE;
|
||||||
|
preemptReason = null;
|
||||||
|
preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
|
||||||
|
shouldStopJobReason = null;
|
||||||
|
newJob = null;
|
||||||
|
newWorkType = WORK_TYPE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3770,7 +3770,7 @@ public class JobSchedulerService extends com.android.server.SystemService
|
|||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
||||||
pw.println();
|
pw.println();
|
||||||
mConcurrencyManager.dumpActiveJobsLocked(pw, predicate, nowElapsed, nowUptime);
|
mConcurrencyManager.dumpContextInfoLocked(pw, predicate, nowElapsed, nowUptime);
|
||||||
|
|
||||||
pw.println();
|
pw.println();
|
||||||
boolean recentPrinted = false;
|
boolean recentPrinted = false;
|
||||||
|
|||||||
@@ -433,6 +433,10 @@ public final class JobServiceContext implements ServiceConnection {
|
|||||||
mPreferredUid = NO_PREFERRED_UID;
|
mPreferredUid = NO_PREFERRED_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getId() {
|
||||||
|
return hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
long getExecutionStartTimeElapsed() {
|
long getExecutionStartTimeElapsed() {
|
||||||
return mExecutionStartTimeElapsed;
|
return mExecutionStartTimeElapsed;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user