Update jobscheduler dumpsys

- Show job IDs in the history.
- Show "last successful/failed run time" for existing jobs.

Bug 62052247
Test: Manual test with dumpsys jobscheduler

Change-Id: Ic0cdab58e4c5b454a3df8300607e9c24c4b1f438
This commit is contained in:
Makoto Onuki
2017-06-20 12:20:34 -07:00
parent a014ce292a
commit ab8a67fa78
5 changed files with 87 additions and 18 deletions

View File

@@ -39,19 +39,23 @@ public final class JobPackageTracker {
public static final int EVENT_NULL = 0;
public static final int EVENT_START_JOB = 1;
public static final int EVENT_STOP_JOB = 2;
public static final int EVENT_START_PERIODIC_JOB = 3;
public static final int EVENT_STOP_PERIODIC_JOB = 4;
private final RingBufferIndices mEventIndices = new RingBufferIndices(EVENT_BUFFER_SIZE);
private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
private final int[] mEventUids = new int[EVENT_BUFFER_SIZE];
private final String[] mEventTags = new String[EVENT_BUFFER_SIZE];
private final int[] mEventJobIds = new int[EVENT_BUFFER_SIZE];
public void addEvent(int cmd, int uid, String tag) {
public void addEvent(int cmd, int uid, String tag, int jobId) {
int index = mEventIndices.add();
mEventCmds[index] = cmd;
mEventTimes[index] = SystemClock.elapsedRealtime();
mEventUids[index] = uid;
mEventTags[index] = tag;
mEventJobIds[index] = jobId;
}
DataSet mCurDataSet = new DataSet();
@@ -365,7 +369,8 @@ public final class JobPackageTracker {
} else {
mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
}
addEvent(EVENT_START_JOB, job.getSourceUid(), job.getBatteryName());
addEvent(job.getJob().isPeriodic() ? EVENT_START_PERIODIC_JOB : EVENT_START_JOB,
job.getSourceUid(), job.getBatteryName(), job.getJobId());
}
public void noteInactive(JobStatus job) {
@@ -376,7 +381,8 @@ public final class JobPackageTracker {
mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
}
rebatchIfNeeded(now);
addEvent(EVENT_STOP_JOB, job.getSourceUid(), job.getBatteryName());
addEvent(job.getJob().isPeriodic() ? EVENT_STOP_JOB : EVENT_STOP_PERIODIC_JOB,
job.getSourceUid(), job.getBatteryName(), job.getJobId());
}
public void noteConcurrency(int totalActive, int fgActive) {
@@ -448,16 +454,20 @@ public final class JobPackageTracker {
}
final String label;
switch (mEventCmds[index]) {
case EVENT_START_JOB: label = "START"; break;
case EVENT_STOP_JOB: label = " STOP"; break;
default: label = " ??"; break;
case EVENT_START_JOB: label = " START"; break;
case EVENT_STOP_JOB: label = " STOP"; break;
case EVENT_START_PERIODIC_JOB: label = "START-P"; break;
case EVENT_STOP_PERIODIC_JOB: label = " STOP-P"; break;
default: label = " ??"; break;
}
pw.print(prefix);
TimeUtils.formatDuration(mEventTimes[index]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
pw.print(" ");
pw.print(label);
pw.print(": ");
pw.print(": #");
UserHandle.formatUid(pw, uid);
pw.print("/");
pw.print(mEventJobIds[index]);
pw.print(" ");
pw.println(mEventTags[index]);
}

View File

@@ -1122,7 +1122,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
delayMillis =
Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
JobStatus.NO_LATEST_RUNTIME, backoffAttempts);
JobStatus.NO_LATEST_RUNTIME, backoffAttempts,
failureToReschedule.getLastSuccessfulRunTime(), System.currentTimeMillis());
for (int ic=0; ic<mControllers.size(); ic++) {
StateController controller = mControllers.get(ic);
controller.rescheduleForFailureLocked(newJob, failureToReschedule);
@@ -1160,7 +1161,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
}
return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
newLatestRuntimeElapsed, 0 /* backoffAttempt */);
newLatestRuntimeElapsed, 0 /* backoffAttempt */,
System.currentTimeMillis() /* lastSuccessfulRunTime */,
periodicToReschedule.getLastFailedRunTime());
}
// JobCompletedListener implementations.

View File

@@ -345,6 +345,11 @@ public final class JobStore {
out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
out.attribute(null, "lastSuccessfulRunTime",
String.valueOf(jobStatus.getLastSuccessfulRunTime()));
out.attribute(null, "lastFailedRunTime",
String.valueOf(jobStatus.getLastFailedRunTime()));
}
private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
@@ -555,6 +560,8 @@ public final class JobStore {
IOException {
JobInfo.Builder jobBuilder;
int uid, sourceUserId;
long lastSuccessfulRunTime;
long lastFailedRunTime;
// Read out job identifier attributes and priority.
try {
@@ -572,6 +579,12 @@ public final class JobStore {
}
val = parser.getAttributeValue(null, "sourceUserId");
sourceUserId = val == null ? -1 : Integer.parseInt(val);
val = parser.getAttributeValue(null, "lastSuccessfulRunTime");
lastSuccessfulRunTime = val == null ? 0 : Long.parseLong(val);
val = parser.getAttributeValue(null, "lastFailedRunTime");
lastFailedRunTime = val == null ? 0 : Long.parseLong(val);
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing job's required fields, skipping");
return null;
@@ -708,7 +721,8 @@ public final class JobStore {
// And now we're done
JobStatus js = new JobStatus(
jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
elapsedRuntimes.first, elapsedRuntimes.second);
elapsedRuntimes.first, elapsedRuntimes.second,
lastSuccessfulRunTime, lastFailedRunTime);
return js;
}

View File

@@ -26,6 +26,7 @@ import android.net.Uri;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.Time;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -183,6 +184,17 @@ public final class JobStatus {
public long madePending;
public long madeActive;
/**
* Last time a job finished successfully for a periodic job, in the currentTimeMillis time,
* for dumpsys.
*/
private long mLastSuccessfulRunTime;
/**
* Last time a job finished unsuccessfully, in the currentTimeMillis time, for dumpsys.
*/
private long mLastFailedRunTime;
/**
* For use only by ContentObserverController: state it is maintaining about content URIs
* being observed.
@@ -196,7 +208,7 @@ public final class JobStatus {
private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
long latestRunTimeElapsedMillis) {
long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) {
this.job = job;
this.callingUid = callingUid;
@@ -263,6 +275,9 @@ public final class JobStatus {
requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
}
this.requiredConstraints = requiredConstraints;
mLastSuccessfulRunTime = lastSuccessfulRunTime;
mLastFailedRunTime = lastFailedRunTime;
}
/** Copy constructor. */
@@ -270,7 +285,8 @@ public final class JobStatus {
this(jobStatus.getJob(), jobStatus.getUid(),
jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
jobStatus.getSourceTag(), jobStatus.getNumFailures(),
jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime());
}
/**
@@ -281,18 +297,22 @@ public final class JobStatus {
* We consider a freshly loaded job to no longer be in back-off.
*/
public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime) {
this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
lastSuccessfulRunTime, lastFailedRunTime);
}
/** Create a new job to be rescheduled with the provided parameters. */
public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt) {
long newLatestRuntimeElapsedMillis, int backoffAttempt,
long lastSuccessfulRunTime, long lastFailedRunTime) {
this(rescheduling.job, rescheduling.getUid(),
rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
newLatestRuntimeElapsedMillis);
newLatestRuntimeElapsedMillis,
lastSuccessfulRunTime, lastFailedRunTime);
}
/**
@@ -316,7 +336,8 @@ public final class JobStatus {
elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
}
return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
}
public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
@@ -669,6 +690,14 @@ public final class JobStatus {
trackingControllers |= which;
}
public long getLastSuccessfulRunTime() {
return mLastSuccessfulRunTime;
}
public long getLastFailedRunTime() {
return mLastFailedRunTime;
}
public boolean shouldDump(int filterUid) {
return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
|| UserHandle.getAppId(getSourceUid()) == filterUid;
@@ -1041,5 +1070,17 @@ public final class JobStatus {
if (numFailures != 0) {
pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
}
final Time t = new Time();
final String format = "%Y-%m-%d %H:%M:%S";
if (mLastSuccessfulRunTime != 0) {
pw.print(prefix); pw.print("Last successful run: ");
t.set(mLastSuccessfulRunTime);
pw.println(t.format(format));
}
if (mLastFailedRunTime != 0) {
pw.print(prefix); pw.print("Last failed run: ");
t.set(mLastFailedRunTime);
pw.println(t.format(format));
}
}
}

View File

@@ -206,7 +206,8 @@ public class JobStoreTest extends AndroidTestCase {
invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period).
final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
0 /* sourceUserId */, "someTag",
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
mTaskStoreUnderTest.add(js);
Thread.sleep(IO_WAIT);