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];
|
||||
|
||||
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];
|
||||
|
||||
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];
|
||||
private final Pools.Pool<ContextAssignment> mContextAssignmentPool =
|
||||
new Pools.SimplePool<>(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<>();
|
||||
|
||||
/** 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 WorkCountTracker mWorkCountTracker = new WorkCountTracker();
|
||||
@@ -378,7 +377,7 @@ class JobConcurrencyManager {
|
||||
final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
|
||||
ServiceManager.getService(BatteryStats.SERVICE_NAME));
|
||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
||||
mActiveServices.add(
|
||||
mIdleContexts.add(
|
||||
new JobServiceContext(mService, this, batteryStats,
|
||||
mService.mJobPackageTracker, mContext.getMainLooper()));
|
||||
}
|
||||
@@ -582,12 +581,10 @@ class JobConcurrencyManager {
|
||||
|
||||
// To avoid GC churn, we recycle the arrays.
|
||||
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
|
||||
boolean[] slotChanged = mRecycledSlotChanged;
|
||||
int[] preferredUidForContext = mRecycledPreferredUidForContext;
|
||||
int[] workTypeForContext = mRecycledWorkTypeForContext;
|
||||
String[] preemptReasonForContext = mRecycledPreemptReasonForContext;
|
||||
int[] preemptReasonCodeForContext = mRecycledPreemptReasonCodeForContext;
|
||||
String[] shouldStopJobReason = mRecycledShouldStopJobReason;
|
||||
final ArraySet<ContextAssignment> changed = mRecycledChanged;
|
||||
final ArraySet<ContextAssignment> idle = mRecycledIdle;
|
||||
final ArraySet<ContextAssignment> preferredUidOnly = mRecycledPreferredUidOnly;
|
||||
final ArraySet<ContextAssignment> stoppable = mRecycledStoppable;
|
||||
|
||||
updateCounterConfigLocked();
|
||||
// Reset everything since we'll re-evaluate the current state.
|
||||
@@ -598,20 +595,47 @@ class JobConcurrencyManager {
|
||||
// shouldStopRunningJobLocked().
|
||||
updateNonRunningPrioritiesLocked(pendingJobQueue, true);
|
||||
|
||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
||||
final JobServiceContext js = activeServices.get(i);
|
||||
final JobStatus status = js.getRunningJobLocked();
|
||||
final int numRunningJobs = activeServices.size();
|
||||
for (int i = 0; i < numRunningJobs; ++i) {
|
||||
final JobServiceContext jsc = activeServices.get(i);
|
||||
final JobStatus js = jsc.getRunningJobLocked();
|
||||
|
||||
if ((contextIdToJobMap[i] = status) != null) {
|
||||
mWorkCountTracker.incrementRunningJobCount(js.getRunningJobWorkType());
|
||||
workTypeForContext[i] = js.getRunningJobWorkType();
|
||||
ContextAssignment assignment = mContextAssignmentPool.acquire();
|
||||
if (assignment == null) {
|
||||
assignment = new ContextAssignment();
|
||||
}
|
||||
|
||||
slotChanged[i] = false;
|
||||
preferredUidForContext[i] = js.getPreferredUid();
|
||||
preemptReasonForContext[i] = null;
|
||||
preemptReasonCodeForContext[i] = JobParameters.STOP_REASON_UNDEFINED;
|
||||
shouldStopJobReason[i] = shouldStopRunningJobLocked(js);
|
||||
assignment.context = jsc;
|
||||
|
||||
if (js != null) {
|
||||
mWorkCountTracker.incrementRunningJobCount(jsc.getRunningJobWorkType());
|
||||
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) {
|
||||
Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
|
||||
@@ -626,83 +650,97 @@ class JobConcurrencyManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find an available slot for nextPending. The context should be available OR
|
||||
// it should have the lowest bias among all running jobs
|
||||
// (sharing the same Uid as nextPending)
|
||||
int minBiasForPreemption = Integer.MAX_VALUE;
|
||||
int selectedContextId = -1;
|
||||
int allWorkTypes = getJobWorkTypes(nextPending);
|
||||
int workType = mWorkCountTracker.canJobStart(allWorkTypes);
|
||||
boolean startingJob = false;
|
||||
int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED;
|
||||
String preemptReason = null;
|
||||
// Find an available slot for nextPending. The context should be one of the following:
|
||||
// 1. Unused
|
||||
// 2. Its job should have used up its minimum execution guarantee so it
|
||||
// 3. Its job should have the lowest bias among all running jobs (sharing the same UID
|
||||
// as nextPending)
|
||||
ContextAssignment selectedContext = null;
|
||||
final int allWorkTypes = getJobWorkTypes(nextPending);
|
||||
final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending);
|
||||
// TODO(141645789): rewrite this to look at empty contexts first so we don't
|
||||
// unnecessarily preempt
|
||||
for (int j = 0; j < MAX_JOB_CONTEXTS_COUNT; j++) {
|
||||
JobStatus job = contextIdToJobMap[j];
|
||||
int preferredUid = preferredUidForContext[j];
|
||||
if (job == null) {
|
||||
final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
|
||||
|| (preferredUid == JobServiceContext.NO_PREFERRED_UID);
|
||||
|
||||
if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
|
||||
// This slot is free, and we haven't yet hit the limit on
|
||||
// concurrent jobs... we can just throw the job in to here.
|
||||
selectedContextId = j;
|
||||
startingJob = true;
|
||||
break;
|
||||
}
|
||||
// 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;
|
||||
boolean startingJob = false;
|
||||
if (idle.size() > 0) {
|
||||
final int idx = idle.size() - 1;
|
||||
final ContextAssignment assignment = idle.valueAt(idx);
|
||||
final boolean preferredUidOkay = (assignment.preferredUid == nextPending.getUid())
|
||||
|| (assignment.preferredUid == JobServiceContext.NO_PREFERRED_UID);
|
||||
int workType = mWorkCountTracker.canJobStart(allWorkTypes);
|
||||
if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) {
|
||||
// This slot is free, and we haven't yet hit the limit on
|
||||
// concurrent jobs... we can just throw the job in to here.
|
||||
selectedContext = assignment;
|
||||
startingJob = true;
|
||||
idle.removeAt(idx);
|
||||
assignment.newJob = nextPending;
|
||||
assignment.newWorkType = workType;
|
||||
}
|
||||
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
|
||||
// app preempt jobs started for TOP apps though.
|
||||
final String reason = shouldStopJobReason[j];
|
||||
if (job.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
|
||||
&& reason != null && mWorkCountTracker.canJobStart(allWorkTypes,
|
||||
activeServices.get(j).getRunningJobWorkType()) != WORK_TYPE_NONE) {
|
||||
// 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
|
||||
// preempted job finally stops.
|
||||
preemptReason = reason;
|
||||
preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE;
|
||||
if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP
|
||||
&& assignment.shouldStopJobReason != null) {
|
||||
int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes,
|
||||
assignment.context.getRunningJobWorkType());
|
||||
if (replaceWorkType != WORK_TYPE_NONE) {
|
||||
// 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
|
||||
// preempted job finally stops.
|
||||
assignment.preemptReason = assignment.shouldStopJobReason;
|
||||
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;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
final int jobBias = mService.evaluateJobBiasLocked(runningJob);
|
||||
if (jobBias >= nextPending.lastEvaluatedBias) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int jobBias = mService.evaluateJobBiasLocked(job);
|
||||
if (jobBias >= nextPending.lastEvaluatedBias) {
|
||||
continue;
|
||||
if (selectedContext == null || lowestBiasSeen > jobBias) {
|
||||
// Step down the preemption threshold - wind up replacing
|
||||
// the lowest-bias running job
|
||||
lowestBiasSeen = jobBias;
|
||||
selectedContext = assignment;
|
||||
assignment.preemptReason = "higher bias job found";
|
||||
assignment.preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
|
||||
// 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 to true.
|
||||
}
|
||||
}
|
||||
|
||||
if (minBiasForPreemption > jobBias) {
|
||||
// Step down the preemption threshold - wind up replacing
|
||||
// the lowest-bias running job
|
||||
minBiasForPreemption = jobBias;
|
||||
selectedContextId = j;
|
||||
preemptReason = "higher bias job found";
|
||||
preemptReasonCode = JobParameters.STOP_REASON_PREEMPT;
|
||||
// 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.
|
||||
if (selectedContext != null) {
|
||||
selectedContext.newJob = nextPending;
|
||||
preferredUidOnly.remove(selectedContext);
|
||||
}
|
||||
}
|
||||
final PackageStats packageStats = getPkgStatsLocked(
|
||||
nextPending.getSourceUserId(), nextPending.getSourcePackageName());
|
||||
if (selectedContextId != -1) {
|
||||
contextIdToJobMap[selectedContextId] = nextPending;
|
||||
slotChanged[selectedContextId] = true;
|
||||
preemptReasonCodeForContext[selectedContextId] = preemptReasonCode;
|
||||
preemptReasonForContext[selectedContextId] = preemptReason;
|
||||
if (selectedContext != null) {
|
||||
changed.add(selectedContext);
|
||||
packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob());
|
||||
}
|
||||
if (startingJob) {
|
||||
// Increase the counters when we're going to start a job.
|
||||
workTypeForContext[selectedContextId] = workType;
|
||||
mWorkCountTracker.stageJob(workType, allWorkTypes);
|
||||
mWorkCountTracker.stageJob(selectedContext.newWorkType, allWorkTypes);
|
||||
mActivePkgStats.add(
|
||||
nextPending.getSourceUserId(), nextPending.getSourcePackageName(),
|
||||
packageStats);
|
||||
@@ -714,37 +752,52 @@ class JobConcurrencyManager {
|
||||
Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString());
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
|
||||
boolean preservePreferredUid = false;
|
||||
if (slotChanged[i]) {
|
||||
JobStatus js = activeServices.get(i).getRunningJobLocked();
|
||||
if (js != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "preempting job: "
|
||||
+ activeServices.get(i).getRunningJobLocked());
|
||||
}
|
||||
// preferredUid will be set to uid of currently running job.
|
||||
activeServices.get(i).cancelExecutingJobLocked(
|
||||
preemptReasonCodeForContext[i],
|
||||
JobParameters.INTERNAL_STOP_REASON_PREEMPT, preemptReasonForContext[i]);
|
||||
// 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 {
|
||||
final JobStatus pendingJob = contextIdToJobMap[i];
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "About to run job on context "
|
||||
+ i + ", job: " + pendingJob);
|
||||
}
|
||||
startJobLocked(activeServices.get(i), pendingJob, workTypeForContext[i]);
|
||||
for (int c = changed.size() - 1; c >= 0; --c) {
|
||||
final ContextAssignment assignment = changed.valueAt(c);
|
||||
final JobStatus js = assignment.context.getRunningJobLocked();
|
||||
if (js != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "preempting job: " + js);
|
||||
}
|
||||
// preferredUid will be set to uid of currently running job.
|
||||
assignment.context.cancelExecutingJobLocked(
|
||||
assignment.preemptReasonCode,
|
||||
JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason);
|
||||
} else {
|
||||
final JobStatus pendingJob = assignment.newJob;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "About to run job on context "
|
||||
+ assignment.context.getId() + ", job: " + pendingJob);
|
||||
}
|
||||
startJobLocked(assignment.context, pendingJob, assignment.newWorkType);
|
||||
}
|
||||
if (!preservePreferredUid) {
|
||||
activeServices.get(i).clearPreferredUid();
|
||||
}
|
||||
|
||||
assignment.clear();
|
||||
mContextAssignmentPool.release(assignment);
|
||||
}
|
||||
for (int s = stoppable.size() - 1; s >= 0; --s) {
|
||||
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();
|
||||
mActivePkgStats.forEach(mPackageStatsStagingCountClearer);
|
||||
noteConcurrency();
|
||||
@@ -787,7 +840,7 @@ class JobConcurrencyManager {
|
||||
|
||||
@GuardedBy("mLock")
|
||||
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 JobStatus jobStatus = jsc.getRunningJobLocked();
|
||||
|
||||
@@ -931,6 +984,8 @@ class JobConcurrencyManager {
|
||||
}
|
||||
} else {
|
||||
mRunningJobs.add(jobStatus);
|
||||
mActiveServices.add(worker);
|
||||
mIdleContexts.remove(worker);
|
||||
mWorkCountTracker.onJobStarted(workType);
|
||||
packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
|
||||
mActivePkgStats.add(
|
||||
@@ -950,6 +1005,8 @@ class JobConcurrencyManager {
|
||||
@WorkType final int workType) {
|
||||
mWorkCountTracker.onJobFinished(workType);
|
||||
mRunningJobs.remove(jobStatus);
|
||||
mActiveServices.remove(worker);
|
||||
mIdleContexts.add(worker);
|
||||
final PackageStats packageStats =
|
||||
mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
@Nullable
|
||||
@@ -1202,6 +1259,14 @@ class JobConcurrencyManager {
|
||||
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")
|
||||
private String printPendingQueueLocked() {
|
||||
StringBuilder s = new StringBuilder("Pending queue: ");
|
||||
@@ -1327,10 +1392,13 @@ class JobConcurrencyManager {
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
void dumpActiveJobsLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
|
||||
void dumpContextInfoLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
|
||||
long nowElapsed, long nowUptime) {
|
||||
pw.println("Active jobs:");
|
||||
pw.increaseIndent();
|
||||
if (mActiveServices.size() == 0) {
|
||||
pw.println("N/A");
|
||||
}
|
||||
for (int i = 0; i < mActiveServices.size(); i++) {
|
||||
JobServiceContext jsc = mActiveServices.get(i);
|
||||
final JobStatus job = jsc.getRunningJobLocked();
|
||||
@@ -1339,7 +1407,8 @@ class JobConcurrencyManager {
|
||||
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);
|
||||
|
||||
if (job != null) {
|
||||
@@ -1361,6 +1430,19 @@ class JobConcurrencyManager {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
@@ -1989,4 +2071,26 @@ class JobConcurrencyManager {
|
||||
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.println();
|
||||
mConcurrencyManager.dumpActiveJobsLocked(pw, predicate, nowElapsed, nowUptime);
|
||||
mConcurrencyManager.dumpContextInfoLocked(pw, predicate, nowElapsed, nowUptime);
|
||||
|
||||
pw.println();
|
||||
boolean recentPrinted = false;
|
||||
|
||||
@@ -433,6 +433,10 @@ public final class JobServiceContext implements ServiceConnection {
|
||||
mPreferredUid = NO_PREFERRED_UID;
|
||||
}
|
||||
|
||||
int getId() {
|
||||
return hashCode();
|
||||
}
|
||||
|
||||
long getExecutionStartTimeElapsed() {
|
||||
return mExecutionStartTimeElapsed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user