From ef3aa6ee53c5e4f1c50dd5a9b5821c54e449d4b3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 29 Apr 2016 18:18:08 -0700 Subject: [PATCH] Fix issue #28477006: Add small event log to job scheduler Added. Also fixed dumpsys output when filtering, to apply the filter to (almost) all of the output. Change-Id: Iafb446599ad8fddbe8a766784deff618a6cfdbb7 --- .../android/server/DeviceIdleController.java | 4 +- .../server/job/JobCompletedListener.java | 3 +- .../android/server/job/JobPackageTracker.java | 72 +++++++++++++++++-- .../server/job/JobSchedulerService.java | 65 +++++++++++++---- .../job/controllers/AppIdleController.java | 8 ++- .../job/controllers/BatteryController.java | 12 +++- .../controllers/ConnectivityController.java | 12 ++-- .../ContentObserverController.java | 19 ++++- .../controllers/DeviceIdleJobsController.java | 7 +- .../job/controllers/IdleController.java | 5 +- .../server/job/controllers/JobStatus.java | 5 ++ .../job/controllers/StateController.java | 2 +- .../job/controllers/TimeController.java | 5 +- 13 files changed, 176 insertions(+), 43 deletions(-) diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 6a08191eef472..6b0ead47923b1 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -309,8 +309,8 @@ public class DeviceIdleController extends SystemService private static final int EVENT_DEEP_IDLE = 4; private static final int EVENT_DEEP_MAINTENANCE = 5; - private int[] mEventCmds = new int[EVENT_BUFFER_SIZE]; - private long[] mEventTimes = new long[EVENT_BUFFER_SIZE]; + private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE]; + private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE]; private void addEvent(int cmd) { if (mEventCmds[0] != cmd) { diff --git a/services/core/java/com/android/server/job/JobCompletedListener.java b/services/core/java/com/android/server/job/JobCompletedListener.java index a7af9cd2b64b9..655abd73e6add 100644 --- a/services/core/java/com/android/server/job/JobCompletedListener.java +++ b/services/core/java/com/android/server/job/JobCompletedListener.java @@ -23,10 +23,9 @@ import com.android.server.job.controllers.JobStatus; * {@link com.android.server.job.JobSchedulerService}. */ public interface JobCompletedListener { - /** * Callback for when a job is completed. * @param needsReschedule Whether the implementing class should reschedule this job. */ - public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule); + void onJobCompleted(JobStatus jobStatus, boolean needsReschedule); } diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java index e5a20954dcc2f..4ba9dae87ca49 100644 --- a/services/core/java/com/android/server/job/JobPackageTracker.java +++ b/services/core/java/com/android/server/job/JobPackageTracker.java @@ -33,6 +33,28 @@ public final class JobPackageTracker { // Number of historical data sets we keep. static final int NUM_HISTORY = 5; + private static final int EVENT_BUFFER_SIZE = 50; + + public static final int EVENT_NULL = 0; + public static final int EVENT_START_JOB = 1; + public static final int EVENT_STOP_JOB = 2; + + private int[] mEventCmds = new int[EVENT_BUFFER_SIZE]; + private long[] mEventTimes = new long[EVENT_BUFFER_SIZE]; + private int[] mEventUids = new int[EVENT_BUFFER_SIZE]; + private String[] mEventTags = new String[EVENT_BUFFER_SIZE]; + + public void addEvent(int cmd, int uid, String tag) { + System.arraycopy(mEventCmds, 0, mEventCmds, 1, EVENT_BUFFER_SIZE - 1); + System.arraycopy(mEventTimes, 0, mEventTimes, 1, EVENT_BUFFER_SIZE - 1); + System.arraycopy(mEventUids, 0, mEventUids, 1, EVENT_BUFFER_SIZE - 1); + System.arraycopy(mEventTags, 0, mEventTags, 1, EVENT_BUFFER_SIZE - 1); + mEventCmds[0] = cmd; + mEventTimes[0] = SystemClock.elapsedRealtime(); + mEventUids[0] = uid; + mEventTags[0] = tag; + } + DataSet mCurDataSet = new DataSet(); DataSet[] mLastDataSets = new DataSet[NUM_HISTORY]; @@ -240,7 +262,8 @@ public final class JobPackageTracker { } } - void dump(PrintWriter pw, String header, String prefix, long now, long nowEllapsed) { + void dump(PrintWriter pw, String header, String prefix, long now, long nowEllapsed, + int filterUid) { final long period = getTotalTime(now); pw.print(prefix); pw.print(header); pw.print(" at "); pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString()); @@ -251,12 +274,16 @@ public final class JobPackageTracker { pw.println(":"); final int NE = mEntries.size(); for (int i = 0; i < NE; i++) { + int uid = mEntries.keyAt(i); + if (filterUid != -1 && filterUid != UserHandle.getAppId(uid)) { + continue; + } ArrayMap uidMap = mEntries.valueAt(i); final int NP = uidMap.size(); for (int j = 0; j < NP; j++) { PackageEntry pe = uidMap.valueAt(j); pw.print(prefix); pw.print(" "); - UserHandle.formatUid(pw, mEntries.keyAt(i)); + UserHandle.formatUid(pw, uid); pw.print(" / "); pw.print(uidMap.keyAt(j)); pw.print(":"); printDuration(pw, period, pe.getPendingTime(now), "pending"); @@ -309,6 +336,7 @@ public final class JobPackageTracker { } else { mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now); } + addEvent(EVENT_START_JOB, job.getSourceUid(), job.getBatteryName()); } public void noteInactive(JobStatus job) { @@ -319,6 +347,7 @@ public final class JobPackageTracker { mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now); } rebatchIfNeeded(now); + addEvent(EVENT_STOP_JOB, job.getSourceUid(), job.getBatteryName()); } public float getLoadFactor(JobStatus job) { @@ -339,7 +368,7 @@ public final class JobPackageTracker { return time / (float)period; } - public void dump(PrintWriter pw, String prefix) { + public void dump(PrintWriter pw, String prefix, int filterUid) { final long now = SystemClock.uptimeMillis(); final long nowEllapsed = SystemClock.elapsedRealtime(); final DataSet total; @@ -352,10 +381,43 @@ public final class JobPackageTracker { mCurDataSet.addTo(total, now); for (int i = 1; i < mLastDataSets.length; i++) { if (mLastDataSets[i] != null) { - mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowEllapsed); + mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowEllapsed, filterUid); pw.println(); } } - total.dump(pw, "Current stats", prefix, now, nowEllapsed); + total.dump(pw, "Current stats", prefix, now, nowEllapsed, filterUid); + } + + public boolean dumpHistory(PrintWriter pw, String prefix, int filterUid) { + if (mEventCmds[0] == EVENT_NULL) { + return false; + } + pw.println(" Job history:"); + long now = SystemClock.elapsedRealtime(); + for (int i=EVENT_BUFFER_SIZE-1; i>=0; i--) { + int uid = mEventUids[i]; + if (filterUid != -1 && filterUid != UserHandle.getAppId(filterUid)) { + continue; + } + int cmd = mEventCmds[i]; + if (cmd == EVENT_NULL) { + continue; + } + String label; + switch (mEventCmds[i]) { + case EVENT_START_JOB: label = "START"; break; + case EVENT_STOP_JOB: label = " STOP"; break; + default: label = " ??"; break; + } + pw.print(prefix); + TimeUtils.formatDuration(mEventTimes[i]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); + pw.print(" "); + pw.print(label); + pw.print(": "); + UserHandle.formatUid(pw, uid); + pw.print(" "); + pw.println(mEventTags[i]); + } + return true; } } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 075a88f34ac96..7e26d4b5c4ca5 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1477,17 +1477,45 @@ public final class JobSchedulerService extends com.android.server.SystemService return s.toString(); } + static void dumpHelp(PrintWriter pw) { + pw.println("Job Scheduler (jobscheduler) dump options:"); + pw.println(" [-h] [package] ..."); + pw.println(" -h: print this help"); + pw.println(" [package] is an optional package name to limit the output to."); + } + void dumpInternal(final PrintWriter pw, String[] args) { int filterUid = -1; if (!ArrayUtils.isEmpty(args)) { - try { - filterUid = getContext().getPackageManager().getPackageUid(args[0], - PackageManager.MATCH_UNINSTALLED_PACKAGES); - } catch (NameNotFoundException ignored) { + int opti = 0; + while (opti < args.length) { + String arg = args[opti]; + if ("-h".equals(arg)) { + dumpHelp(pw); + return; + } else if ("-a".equals(arg)) { + // Ignore, we always dump all. + } else if (arg.length() > 0 && arg.charAt(0) == '-') { + pw.println("Unknown option: " + arg); + return; + } else { + break; + } + opti++; + } + if (opti < args.length) { + String pkg = args[opti]; + try { + filterUid = getContext().getPackageManager().getPackageUid(pkg, + PackageManager.MATCH_UNINSTALLED_PACKAGES); + } catch (NameNotFoundException ignored) { + pw.println("Invalid package: " + pkg); + return; + } } } - final int filterUidFinal = filterUid; + final int filterUidFinal = UserHandle.getAppId(filterUid); final long now = SystemClock.elapsedRealtime(); synchronized (mLock) { pw.println("Started users: " + Arrays.toString(mStartedUsers)); @@ -1502,8 +1530,7 @@ public final class JobSchedulerService extends com.android.server.SystemService pw.println(job.toShortString()); // Skip printing details if the caller requested a filter - if (filterUidFinal != -1 && job.getUid() != filterUidFinal - && job.getSourceUid() != filterUidFinal) { + if (!job.shouldDump(filterUidFinal)) { return; } @@ -1526,17 +1553,23 @@ public final class JobSchedulerService extends com.android.server.SystemService } for (int i=0; i it = mTrackedTasks.iterator(); if (it.hasNext()) { - pw.print(String.valueOf(it.next().hashCode())); + JobStatus jobStatus = it.next(); + if (jobStatus.shouldDump(filterUid)) { + pw.print(String.valueOf(jobStatus.hashCode())); + } } while (it.hasNext()) { - pw.print("," + String.valueOf(it.next().hashCode())); + JobStatus jobStatus = it.next(); + if (jobStatus.shouldDump(filterUid)) { + pw.print("," + String.valueOf(jobStatus.hashCode())); + } } pw.println(); } diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index f5aac087f9b05..9fd22686a9a05 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -181,14 +181,16 @@ public class ConnectivityController extends StateController implements }; @Override - public void dumpControllerStateLocked(PrintWriter pw) { + public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { pw.println("Conn."); for (int i = 0; i < mTrackedJobs.size(); i++) { final JobStatus js = mTrackedJobs.get(i); - pw.println(String.valueOf(js.getJobId() + "," + js.getUid()) - + ": C=" + js.hasConnectivityConstraint() - + ", UM=" + js.hasUnmeteredConstraint() - + ", NR=" + js.hasNotRoamingConstraint()); + if (js.shouldDump(filterUid)) { + pw.println(String.valueOf(js.getJobId() + "," + js.getUid()) + + ": C=" + js.hasConnectivityConstraint() + + ", UM=" + js.hasUnmeteredConstraint() + + ", NR=" + js.hasNotRoamingConstraint()); + } } } } diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java index c5b1a3d88052c..6722bfbeb0c0e 100644 --- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java +++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java @@ -322,11 +322,15 @@ public class ContentObserverController extends StateController { } @Override - public void dumpControllerStateLocked(PrintWriter pw) { + public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { pw.println("Content."); boolean printed = false; Iterator it = mTrackedTasks.iterator(); while (it.hasNext()) { + JobStatus js = it.next(); + if (!js.shouldDump(filterUid)) { + continue; + } if (!printed) { pw.print(" "); printed = true; @@ -343,13 +347,24 @@ public class ContentObserverController extends StateController { pw.println(" Observers:"); for (int i = 0; i < N; i++) { ObserverInstance obs = mObservers.valueAt(i); + int M = obs.mJobs.size(); + boolean shouldDump = false; + for (int j=0; jor the deadline on the job has expired. diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java index 013903939f180..1721fb9ac3fc1 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -64,5 +64,5 @@ public abstract class StateController { public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) { } - public abstract void dumpControllerStateLocked(PrintWriter pw); + public abstract void dumpControllerStateLocked(PrintWriter pw, int filterUid); } diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index ab6768e998789..2f8ca7eb1f803 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -275,7 +275,7 @@ public class TimeController extends StateController { }; @Override - public void dumpControllerStateLocked(PrintWriter pw) { + public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { final long nowElapsed = SystemClock.elapsedRealtime(); pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")"); pw.println( @@ -284,6 +284,9 @@ public class TimeController extends StateController { + "s"); pw.println("Tracking:"); for (JobStatus ts : mTrackedJobs) { + if (!ts.shouldDump(filterUid)) { + continue; + } pw.println(String.valueOf(ts.getJobId() + "," + ts.getUid()) + ": (" + (ts.hasTimingDelayConstraint() ? ts.getEarliestRunTime() : "N/A") + ", " + (ts.hasDeadlineConstraint() ?ts.getLatestRunTimeElapsed() : "N/A")