Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab8a67fa authored by Makoto Onuki's avatar Makoto Onuki
Browse files

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
parent a014ce29
Loading
Loading
Loading
Loading
+17 −7
Original line number Original line Diff line number Diff line
@@ -39,19 +39,23 @@ public final class JobPackageTracker {
    public static final int EVENT_NULL = 0;
    public static final int EVENT_NULL = 0;
    public static final int EVENT_START_JOB = 1;
    public static final int EVENT_START_JOB = 1;
    public static final int EVENT_STOP_JOB = 2;
    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 RingBufferIndices mEventIndices = new RingBufferIndices(EVENT_BUFFER_SIZE);
    private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
    private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE];
    private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
    private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE];
    private final int[] mEventUids = new int[EVENT_BUFFER_SIZE];
    private final int[] mEventUids = new int[EVENT_BUFFER_SIZE];
    private final String[] mEventTags = new String[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();
        int index = mEventIndices.add();
        mEventCmds[index] = cmd;
        mEventCmds[index] = cmd;
        mEventTimes[index] = SystemClock.elapsedRealtime();
        mEventTimes[index] = SystemClock.elapsedRealtime();
        mEventUids[index] = uid;
        mEventUids[index] = uid;
        mEventTags[index] = tag;
        mEventTags[index] = tag;
        mEventJobIds[index] = jobId;
    }
    }


    DataSet mCurDataSet = new DataSet();
    DataSet mCurDataSet = new DataSet();
@@ -365,7 +369,8 @@ public final class JobPackageTracker {
        } else {
        } else {
            mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
            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) {
    public void noteInactive(JobStatus job) {
@@ -376,7 +381,8 @@ public final class JobPackageTracker {
            mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
            mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
        }
        }
        rebatchIfNeeded(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) {
    public void noteConcurrency(int totalActive, int fgActive) {
@@ -450,14 +456,18 @@ public final class JobPackageTracker {
            switch (mEventCmds[index]) {
            switch (mEventCmds[index]) {
                case EVENT_START_JOB:           label = "  START"; break;
                case EVENT_START_JOB:           label = "  START"; break;
                case EVENT_STOP_JOB:            label = "   STOP"; 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;
                default:                        label = "     ??"; break;
            }
            }
            pw.print(prefix);
            pw.print(prefix);
            TimeUtils.formatDuration(mEventTimes[index]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
            TimeUtils.formatDuration(mEventTimes[index]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
            pw.print(" ");
            pw.print(" ");
            pw.print(label);
            pw.print(label);
            pw.print(": ");
            pw.print(": #");
            UserHandle.formatUid(pw, uid);
            UserHandle.formatUid(pw, uid);
            pw.print("/");
            pw.print(mEventJobIds[index]);
            pw.print(" ");
            pw.print(" ");
            pw.println(mEventTags[index]);
            pw.println(mEventTags[index]);
        }
        }
+5 −2
Original line number Original line Diff line number Diff line
@@ -1122,7 +1122,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
        delayMillis =
        delayMillis =
                Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
                Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
        JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
        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++) {
        for (int ic=0; ic<mControllers.size(); ic++) {
            StateController controller = mControllers.get(ic);
            StateController controller = mControllers.get(ic);
            controller.rescheduleForFailureLocked(newJob, failureToReschedule);
            controller.rescheduleForFailureLocked(newJob, failureToReschedule);
@@ -1160,7 +1161,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
                    newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
        }
        }
        return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
        return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
                newLatestRuntimeElapsed, 0 /* backoffAttempt */);
                newLatestRuntimeElapsed, 0 /* backoffAttempt */,
                System.currentTimeMillis() /* lastSuccessfulRunTime */,
                periodicToReschedule.getLastFailedRunTime());
    }
    }


    // JobCompletedListener implementations.
    // JobCompletedListener implementations.
+15 −1
Original line number Original line Diff line number Diff line
@@ -345,6 +345,11 @@ public final class JobStore {
            out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
            out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
            out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
            out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
            out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
            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)
        private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
@@ -555,6 +560,8 @@ public final class JobStore {
                IOException {
                IOException {
            JobInfo.Builder jobBuilder;
            JobInfo.Builder jobBuilder;
            int uid, sourceUserId;
            int uid, sourceUserId;
            long lastSuccessfulRunTime;
            long lastFailedRunTime;


            // Read out job identifier attributes and priority.
            // Read out job identifier attributes and priority.
            try {
            try {
@@ -572,6 +579,12 @@ public final class JobStore {
                }
                }
                val = parser.getAttributeValue(null, "sourceUserId");
                val = parser.getAttributeValue(null, "sourceUserId");
                sourceUserId = val == null ? -1 : Integer.parseInt(val);
                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) {
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Error parsing job's required fields, skipping");
                Slog.e(TAG, "Error parsing job's required fields, skipping");
                return null;
                return null;
@@ -708,7 +721,8 @@ public final class JobStore {
            // And now we're done
            // And now we're done
            JobStatus js = new JobStatus(
            JobStatus js = new JobStatus(
                    jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
                    jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
                    elapsedRuntimes.first, elapsedRuntimes.second);
                    elapsedRuntimes.first, elapsedRuntimes.second,
                    lastSuccessfulRunTime, lastFailedRunTime);
            return js;
            return js;
        }
        }


+48 −7
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.net.Uri;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.text.format.Time;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Slog;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.TimeUtils;
@@ -183,6 +184,17 @@ public final class JobStatus {
    public long madePending;
    public long madePending;
    public long madeActive;
    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
     * For use only by ContentObserverController: state it is maintaining about content URIs
     * being observed.
     * being observed.
@@ -196,7 +208,7 @@ public final class JobStatus {


    private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
    private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
            int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
            int sourceUserId, String tag, int numFailures, long earliestRunTimeElapsedMillis,
            long latestRunTimeElapsedMillis) {
            long latestRunTimeElapsedMillis, long lastSuccessfulRunTime, long lastFailedRunTime) {
        this.job = job;
        this.job = job;
        this.callingUid = callingUid;
        this.callingUid = callingUid;


@@ -263,6 +275,9 @@ public final class JobStatus {
            requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
            requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
        }
        }
        this.requiredConstraints = requiredConstraints;
        this.requiredConstraints = requiredConstraints;

        mLastSuccessfulRunTime = lastSuccessfulRunTime;
        mLastFailedRunTime = lastFailedRunTime;
    }
    }


    /** Copy constructor. */
    /** Copy constructor. */
@@ -270,7 +285,8 @@ public final class JobStatus {
        this(jobStatus.getJob(), jobStatus.getUid(),
        this(jobStatus.getJob(), jobStatus.getUid(),
                jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
                jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
                jobStatus.getSourceTag(), jobStatus.getNumFailures(),
                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.
     * We consider a freshly loaded job to no longer be in back-off.
     */
     */
    public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
    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,
        this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0,
                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                lastSuccessfulRunTime, lastFailedRunTime);
    }
    }


    /** Create a new job to be rescheduled with the provided parameters. */
    /** Create a new job to be rescheduled with the provided parameters. */
    public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
    public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
                      long newLatestRuntimeElapsedMillis, int backoffAttempt) {
            long newLatestRuntimeElapsedMillis, int backoffAttempt,
            long lastSuccessfulRunTime, long lastFailedRunTime) {
        this(rescheduling.job, rescheduling.getUid(),
        this(rescheduling.job, rescheduling.getUid(),
                rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
                rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
                rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                newLatestRuntimeElapsedMillis);
                newLatestRuntimeElapsedMillis,
                lastSuccessfulRunTime, lastFailedRunTime);
    }
    }


    /**
    /**
@@ -316,7 +336,8 @@ public final class JobStatus {
                    elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
                    elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
        }
        }
        return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
        return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, tag, 0,
                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
    }
    }


    public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
    public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) {
@@ -669,6 +690,14 @@ public final class JobStatus {
        trackingControllers |= which;
        trackingControllers |= which;
    }
    }


    public long getLastSuccessfulRunTime() {
        return mLastSuccessfulRunTime;
    }

    public long getLastFailedRunTime() {
        return mLastFailedRunTime;
    }

    public boolean shouldDump(int filterUid) {
    public boolean shouldDump(int filterUid) {
        return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
        return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid
                || UserHandle.getAppId(getSourceUid()) == filterUid;
                || UserHandle.getAppId(getSourceUid()) == filterUid;
@@ -1041,5 +1070,17 @@ public final class JobStatus {
        if (numFailures != 0) {
        if (numFailures != 0) {
            pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
            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));
        }
    }
    }
}
}
+2 −1
Original line number Original line Diff line number Diff line
@@ -206,7 +206,8 @@ public class JobStoreTest extends AndroidTestCase {
                invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
                invalidLateRuntimeElapsedMillis - TWO_HOURS;  // Early is (late - period).
        final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
        final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
                0 /* sourceUserId */, "someTag",
                0 /* sourceUserId */, "someTag",
                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
                invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
                0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);


        mTaskStoreUnderTest.add(js);
        mTaskStoreUnderTest.add(js);
        Thread.sleep(IO_WAIT);
        Thread.sleep(IO_WAIT);