Start really collecting PSS data for process stats.

The activity manager now uses some heuristics to try to
sample PSS data from processes so that it can get enough
data to over reasonable time have something useful, without
doing it too aggressively.

The current policy is:

1. Whenever a significant global change happens (memory state,
   sceen on or off), we collect PSS from all processes; this will
   not happen more than every 10 minutes.
2. When all activities become idle, we will collect PSS from the
   current top process; this will not happen more than every 2
   minutes per process.
3. We will sample the top-most process's PSS every 5 minutes.
4. When an process's oom adj changes and it has been more than
   30 minutes since PSS has been collected from it, we will
   collect a new PSS sample.
5. If a process changes from service A to service B (meaning it
   has been running a service for a long time), we will collect
   a PSS sample from it.
6. If someone explicitly requests PSS data (for running services
   UI or dumpsys), record that.

Also:

- Finish moving the procstats output all to the new format.
- Record information about processes being killed due to excessive
  wake locks or CPU use in procstats.
- Rework how we structure common vs. per-package process stats to
  make it simpler to deal with.
- Optimize the Debug.getPss() implementation (we use it a lot now).
  Should probably optimize it further at some point.

Change-Id: I179f1f7ae5852c7e567de4127d8457b50d27e0f0
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bf89fa6..4568525 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -552,7 +552,7 @@
         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
         // Formatting for checkin service - update version if row format changes
-        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 2;
+        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
 
         private void updatePendingConfiguration(Configuration config) {
             synchronized (mPackages) {
@@ -972,43 +972,48 @@
                 pw.print(memInfo.nativePss); pw.print(',');
                 pw.print(memInfo.dalvikPss); pw.print(',');
                 pw.print(memInfo.otherPss); pw.print(',');
-                pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
+                pw.print(memInfo.getTotalPss()); pw.print(',');
 
-                // Heap info - proportional set size
+                // Heap info - swappable set size
                 pw.print(memInfo.nativeSwappablePss); pw.print(',');
                 pw.print(memInfo.dalvikSwappablePss); pw.print(',');
                 pw.print(memInfo.otherSwappablePss); pw.print(',');
-                pw.print(memInfo.nativeSwappablePss + memInfo.dalvikSwappablePss + memInfo.otherSwappablePss); pw.print(',');
+                pw.print(memInfo.getTotalSwappablePss()); pw.print(',');
 
                 // Heap info - shared dirty
                 pw.print(memInfo.nativeSharedDirty); pw.print(',');
                 pw.print(memInfo.dalvikSharedDirty); pw.print(',');
                 pw.print(memInfo.otherSharedDirty); pw.print(',');
-                pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
-                        + memInfo.otherSharedDirty); pw.print(',');
+                pw.print(memInfo.getTotalSharedDirty()); pw.print(',');
 
                 // Heap info - shared clean
                 pw.print(memInfo.nativeSharedClean); pw.print(',');
                 pw.print(memInfo.dalvikSharedClean); pw.print(',');
                 pw.print(memInfo.otherSharedClean); pw.print(',');
-                pw.print(memInfo.nativeSharedClean + memInfo.dalvikSharedClean
-                        + memInfo.otherSharedClean); pw.print(',');
+                pw.print(memInfo.getTotalSharedClean()); pw.print(',');
 
                 // Heap info - private Dirty
                 pw.print(memInfo.nativePrivateDirty); pw.print(',');
                 pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
                 pw.print(memInfo.otherPrivateDirty); pw.print(',');
-                pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
-                        + memInfo.otherPrivateDirty); pw.print(',');
-
+                pw.print(memInfo.getTotalPrivateDirty()); pw.print(',');
 
                 // Heap info - private Clean
                 pw.print(memInfo.nativePrivateClean); pw.print(',');
                 pw.print(memInfo.dalvikPrivateClean); pw.print(',');
                 pw.print(memInfo.otherPrivateClean); pw.print(',');
-                pw.print(memInfo.nativePrivateClean + memInfo.dalvikPrivateClean
-                        + memInfo.otherPrivateClean); pw.print(',');
+                pw.print(memInfo.getTotalPrivateClean()); pw.print(',');
 
+                // Heap info - other areas
+                for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+                    pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
+                    pw.print(memInfo.getOtherPss(i)); pw.print(',');
+                    pw.print(memInfo.getOtherSwappablePss(i)); pw.print(',');
+                    pw.print(memInfo.getOtherSharedDirty(i)); pw.print(',');
+                    pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
+                    pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
+                    pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
+                }
 
                 // Object counts
                 pw.print(viewInstanceCount); pw.print(',');
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index f4cf2ee..8b7f3dd 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -394,12 +394,16 @@
     if (fp == 0) return 0;
 
     while (true) {
-        if (fgets(line, 1024, fp) == 0) {
+        if (fgets(line, 1024, fp) == NULL) {
             break;
         }
 
-        if (sscanf(line, "Pss: %d kB", &temp) == 1) {
-            pss += temp;
+        if (strncmp(line, "Pss: ", 5) == 0) {
+            char* c = line + 5;
+            while (*c != 0 && (*c < '0' || *c > '9')) {
+                c++;
+            }
+            pss += atoi(c);
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e37eec6..f201563 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessStats;
 import com.android.internal.os.TransferPipe;
@@ -266,6 +267,20 @@
     // The minimum amount of time between successive GC requests for a process.
     static final int GC_MIN_INTERVAL = 60*1000;
 
+    // The minimum amount of time between successive PSS requests for a process.
+    static final int PSS_MIN_INTERVAL = 2*60*1000;
+
+    // The amount of time we will sample PSS of the current top process while the
+    // screen is on.
+    static final int PSS_TOP_INTERVAL = 5*60*1000;
+
+    // The maximum amount of time for a process to be around until we will take
+    // a PSS snapshot on its next oom change.
+    static final int PSS_MAX_INTERVAL = 30*60*1000;
+
+    // The minimum amount of time between successive PSS requests for a process.
+    static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
+
     // The rate at which we check for apps using excessive power -- 15 mins.
     static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
 
@@ -495,8 +510,17 @@
     /**
      * List of processes that should gc as soon as things are idle.
      */
-    final ArrayList<ProcessRecord> mProcessesToGc
-            = new ArrayList<ProcessRecord>();
+    final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
+
+    /**
+     * Processes we want to collect PSS data from.
+     */
+    final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
+
+    /**
+     * Last time we requested PSS data of all processes.
+     */
+    long mLastFullPssTime = SystemClock.uptimeMillis();
 
     /**
      * This is the process holding what we currently consider to be
@@ -1480,6 +1504,51 @@
         }
     };
 
+    static final int COLLECT_PSS_BG_MSG = 1;
+
+    final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case COLLECT_PSS_BG_MSG: {
+                int i=0;
+                long start = SystemClock.uptimeMillis();
+                do {
+                    ProcessRecord proc;
+                    int oomAdj;
+                    int pid;
+                    synchronized (ActivityManagerService.this) {
+                        if (i >= mPendingPssProcesses.size()) {
+                            Slog.i(TAG, "Collected PSS of " + i + " processes in "
+                                    + (SystemClock.uptimeMillis()-start) + "ms");
+                            mPendingPssProcesses.clear();
+                            return;
+                        }
+                        proc = mPendingPssProcesses.get(i);
+                        if (proc.thread != null) {
+                            oomAdj = proc.setAdj;
+                            pid = proc.pid;
+                            i++;
+                        } else {
+                            proc = null;
+                            oomAdj = 0;
+                            pid = 0;
+                        }
+                    }
+                    if (proc != null) {
+                        long pss = Debug.getPss(pid);
+                        synchronized (ActivityManagerService.this) {
+                            if (proc.thread != null && proc.setAdj == oomAdj && proc.pid == pid) {
+                                proc.baseProcessTracker.addPss(pss, true);
+                            }
+                        }
+                    }
+                } while (true);
+            }
+            }
+        }
+    };
+
     public static void setSystemProcess() {
         try {
             ActivityManagerService m = mSelf;
@@ -3906,8 +3975,24 @@
         enforceNotIsolatedCaller("getProcessMemoryInfo");
         Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
         for (int i=pids.length-1; i>=0; i--) {
+            ProcessRecord proc;
+            int oomAdj;
+            synchronized (this) {
+                synchronized (mPidsSelfLocked) {
+                    proc = mPidsSelfLocked.get(pids[i]);
+                    oomAdj = proc != null ? proc.setAdj : 0;
+                }
+            }
             infos[i] = new Debug.MemoryInfo();
             Debug.getMemoryInfo(pids[i], infos[i]);
+            if (proc != null) {
+                synchronized (this) {
+                    if (proc.thread != null && proc.setAdj == oomAdj) {
+                        // Record this for posterity if the process has been stable.
+                        proc.baseProcessTracker.addPss(infos[i].getTotalPss(), false);
+                    }
+                }
+            }
         }
         return infos;
     }
@@ -3917,7 +4002,23 @@
         enforceNotIsolatedCaller("getProcessPss");
         long[] pss = new long[pids.length];
         for (int i=pids.length-1; i>=0; i--) {
+            ProcessRecord proc;
+            int oomAdj;
+            synchronized (this) {
+                synchronized (mPidsSelfLocked) {
+                    proc = mPidsSelfLocked.get(pids[i]);
+                    oomAdj = proc != null ? proc.setAdj : 0;
+                }
+            }
             pss[i] = Debug.getPss(pids[i]);
+            if (proc != null) {
+                synchronized (this) {
+                    if (proc.thread != null && proc.setAdj == oomAdj) {
+                        // Record this for posterity if the process has been stable.
+                        proc.baseProcessTracker.addPss(pss[i], false);
+                    }
+                }
+            }
         }
         return pss;
     }
@@ -4350,7 +4451,7 @@
             thread.asBinder().linkToDeath(adr, 0);
             app.deathRecipient = adr;
         } catch (RemoteException e) {
-            app.resetPackageList();
+            app.resetPackageList(mProcessTracker);
             startProcessLocked(app, "link fail", processName);
             return false;
         }
@@ -4442,7 +4543,7 @@
             // an infinite loop of restarting processes...
             Slog.w(TAG, "Exception thrown during bind!", e);
 
-            app.resetPackageList();
+            app.resetPackageList(mProcessTracker);
             app.unlinkDeathRecipient();
             startProcessLocked(app, "bind fail", processName);
             return false;
@@ -4630,8 +4731,19 @@
                         final int userId = mStartedUsers.keyAt(i);
                         Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                        broadcastIntentLocked(null, null, intent,
-                                null, null, 0, null, null,
+                        broadcastIntentLocked(null, null, intent, null,
+                                new IIntentReceiver.Stub() {
+                                    @Override
+                                    public void performReceive(Intent intent, int resultCode,
+                                            String data, Bundle extras, boolean ordered,
+                                            boolean sticky, int sendingUser) {
+                                        synchronized (ActivityManagerService.this) {
+                                            requestPssAllProcsLocked(SystemClock.uptimeMillis(),
+                                                    true);
+                                        }
+                                    }
+                                },
+                                0, null, null,
                                 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
                                 AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
                                 userId);
@@ -10934,7 +11046,7 @@
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
 
-        if (procs.size() == 1 || isCheckinRequest) {
+        if (!brief && !oomOnly && (procs.size() == 1 || isCheckinRequest)) {
             dumpDetails = true;
         }
 
@@ -10960,17 +11072,24 @@
 
         long totalPss = 0;
 
+        Debug.MemoryInfo mi = null;
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = procs.get(i);
-            if (r.thread != null) {
+            IApplicationThread thread;
+            int oomAdj;
+            synchronized (this) {
+                thread = r.thread;
+                oomAdj = r.setAdj;
+            }
+            if (thread != null) {
                 if (!isCheckinRequest && dumpDetails) {
                     pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
                     pw.flush();
                 }
-                Debug.MemoryInfo mi = null;
                 if (dumpDetails) {
                     try {
-                        mi = r.thread.dumpMemInfo(fd, isCheckinRequest, true, dumpDalvik, innerArgs);
+                        mi = null;
+                        mi = thread.dumpMemInfo(fd, isCheckinRequest, true, dumpDalvik, innerArgs);
                     } catch (RemoteException e) {
                         if (!isCheckinRequest) {
                             pw.println("Got RemoteException!");
@@ -10978,21 +11097,31 @@
                         }
                     }
                 } else {
-                    mi = new Debug.MemoryInfo();
-                    Debug.getMemoryInfo(r.pid, mi);
+                    if (mi == null) {
+                        mi = new Debug.MemoryInfo();
+                    }
+                    if (!brief && !oomOnly) {
+                        Debug.getMemoryInfo(r.pid, mi);
+                    } else {
+                        mi.dalvikPss = (int)Debug.getPss(r.pid);
+                    }
+                }
+
+                final long myTotalPss = mi.getTotalPss();
+
+                synchronized (this) {
+                    if (r.thread != null && oomAdj == r.setAdj) {
+                        // Record this for posterity if the process has been stable.
+                        r.baseProcessTracker.addPss(myTotalPss, true);
+                    }
                 }
 
                 if (!isCheckinRequest && mi != null) {
-                    long myTotalPss = mi.getTotalPss();
                     totalPss += myTotalPss;
                     MemItem pssItem = new MemItem(r.processName + " (pid " + r.pid + ")",
                             r.processName, myTotalPss, 0);
                     procMems.add(pssItem);
 
-                    synchronized (this) {
-                        r.baseProcessTracker.addPss(myTotalPss);
-                    }
-
                     nativePss += mi.nativePss;
                     dalvikPss += mi.dalvikPss;
                     otherPss += mi.otherPss;
@@ -11070,7 +11199,7 @@
                             }
                         }
                         for (int j=0; j<miCat.subitems.size(); j++) {
-                            MemItem mi = miCat.subitems.get(j);
+                            MemItem memi = miCat.subitems.get(j);
                             if (j > 0) {
                                 if (outTag != null) {
                                     outTag.append(" ");
@@ -11080,10 +11209,10 @@
                                 }
                             }
                             if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
-                                appendMemBucket(outTag, mi.pss, mi.shortLabel, false);
+                                appendMemBucket(outTag, memi.pss, memi.shortLabel, false);
                             }
                             if (outStack != null) {
-                                appendMemBucket(outStack, mi.pss, mi.shortLabel, true);
+                                appendMemBucket(outStack, memi.pss, memi.shortLabel, true);
                             }
                         }
                         if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
@@ -11109,7 +11238,7 @@
             }
             pw.println("Total PSS by OOM adjustment:");
             dumpMemItems(pw, "  ", oomMems, false);
-            if (!oomOnly) {
+            if (!brief && !oomOnly) {
                 PrintWriter out = categoryPw != null ? categoryPw : pw;
                 out.println();
                 out.println("Total PSS by category:");
@@ -11117,29 +11246,31 @@
             }
             pw.println();
             pw.print("Total PSS: "); pw.print(totalPss); pw.println(" kB");
-            final int[] SINGLE_LONG_FORMAT = new int[] {
-                Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
-            };
-            long[] longOut = new long[1];
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            longOut[0] = 0;
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            longOut[0] = 0;
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            longOut[0] = 0;
-            Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
-                    SINGLE_LONG_FORMAT, null, longOut, null);
-            long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-            pw.print("      KSM: "); pw.print(sharing); pw.print(" kB saved from shared ");
-                    pw.print(shared); pw.println(" kB");
-            pw.print("           "); pw.print(unshared); pw.print(" kB unshared; ");
-                    pw.print(voltile); pw.println(" kB volatile");
+            if (!brief) {
+                final int[] SINGLE_LONG_FORMAT = new int[] {
+                    Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+                };
+                long[] longOut = new long[1];
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                longOut[0] = 0;
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                longOut[0] = 0;
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                longOut[0] = 0;
+                Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+                        SINGLE_LONG_FORMAT, null, longOut, null);
+                long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                pw.print("      KSM: "); pw.print(sharing); pw.print(" kB saved from shared ");
+                        pw.print(shared); pw.println(" kB");
+                pw.print("           "); pw.print(unshared); pw.print(" kB unshared; ");
+                        pw.print(voltile); pw.println(" kB volatile");
+            }
         }
     }
 
@@ -11236,6 +11367,7 @@
         }
 
         mProcessesToGc.remove(app);
+        mPendingPssProcesses.remove(app);
         
         // Dismiss any open dialogs.
         if (app.crashDialog != null && !app.forceCrashReport) {
@@ -11254,7 +11386,7 @@
         app.crashing = false;
         app.notResponding = false;
         
-        app.resetPackageList();
+        app.resetPackageList(mProcessTracker);
         app.unlinkDeathRecipient();
         app.thread = null;
         app.forcingToForeground = null;
@@ -13749,6 +13881,41 @@
     }
 
     /**
+     * Schedule PSS collection of a process.
+     */
+    void requestPssLocked(ProcessRecord proc, long now, boolean always) {
+        if (!always && now < (proc.lastPssTime+PSS_MIN_INTERVAL)) {
+            return;
+        }
+        if (mPendingPssProcesses.contains(proc)) {
+            return;
+        }
+        proc.lastPssTime = now;
+        if (mPendingPssProcesses.size() == 0) {
+            mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+        }
+        mPendingPssProcesses.add(proc);
+    }
+
+    /**
+     * Schedule PSS collection of all processes.
+     */
+    void requestPssAllProcsLocked(long now, boolean always) {
+        if (!always && now < (mLastFullPssTime+FULL_PSS_MIN_INTERVAL)) {
+            return;
+        }
+        mLastFullPssTime = now;
+        mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
+        mPendingPssProcesses.clear();
+        for (int i=mLruProcesses.size()-1; i>=0; i--) {
+            ProcessRecord app = mLruProcesses.get(i);
+            app.lastPssTime = now;
+            mPendingPssProcesses.add(app);
+        }
+        mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+    }
+
+    /**
      * Ask a given process to GC right now.
      */
     final void performAppGcLocked(ProcessRecord app) {
@@ -13959,6 +14126,7 @@
                             + " during " + realtimeSince);
                     EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
                             app.processName, app.setAdj, "excessive wake lock");
+                    app.baseProcessTracker.reportExcessiveWake(app.pkgList);
                     Process.killProcessQuiet(app.pid);
                 } else if (doCpuKills && uptimeSince > 0
                         && ((cputimeUsed*100)/uptimeSince) >= 50) {
@@ -13971,6 +14139,7 @@
                             + " during " + uptimeSince);
                     EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
                             app.processName, app.setAdj, "excessive cpu");
+                    app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
                     Process.killProcessQuiet(app.pid);
                 } else {
                     app.lastWakeTime = wtime;
@@ -14012,11 +14181,23 @@
             app.setRawAdj = app.curRawAdj;
         }
 
+        if (app == TOP_APP && now > (app.lastPssTime+PSS_TOP_INTERVAL)) {
+            requestPssLocked(app, now, true);
+        }
+
         if (app.curAdj != app.setAdj) {
             if (Process.setOomAdj(app.pid, app.curAdj)) {
                 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                     TAG, "Set " + app.pid + " " + app.processName +
                     " adj " + app.curAdj + ": " + app.adjType);
+                if (app.setAdj == ProcessList.SERVICE_ADJ
+                        && app.curAdj == ProcessList.SERVICE_B_ADJ) {
+                    // If a service is dropping to the B list, it has been running for
+                    // a while, take a PSS snapshot.
+                    requestPssLocked(app, now, false);
+                } else if (now > (app.lastPssTime+PSS_MAX_INTERVAL)) {
+                    requestPssLocked(app, now, true);
+                }
                 app.setAdj = app.curAdj;
                 app.setAdjChanged = true;
                 if (!doingAll) {
@@ -14406,6 +14587,9 @@
                 }
             }
         }
+        if (allChanged) {
+            requestPssAllProcsLocked(now, false);
+        }
 
         if (DEBUG_OOM_ADJ) {
             Slog.d(TAG, "Did OOM ADJ in " + (SystemClock.uptimeMillis()-now) + "ms");
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 561dd0f..44b61d0 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -222,7 +222,7 @@
                 if (lastLaunchTime == 0) pw.print("0");
                 else TimeUtils.formatDuration(lastLaunchTime, now, pw);
                 pw.println();
-        pw.print(prefix); pw.print(" haveState="); pw.print(haveState);
+        pw.print(prefix); pw.print("haveState="); pw.print(haveState);
                 pw.print(" icicle="); pw.println(icicle);
         pw.print(prefix); pw.print("state="); pw.print(state);
                 pw.print(" stopped="); pw.print(stopped);
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 8d98109..92a1523 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1707,6 +1707,7 @@
                 r.idle = true;
                 if (allResumedActivitiesIdle()) {
                     mService.scheduleAppGcsLocked();
+                    mService.requestPssLocked(r.app, SystemClock.uptimeMillis(), false);
                 }
                 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
                     sendThumbnail = r.app.thread;
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index e72656f..365009d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -62,6 +62,7 @@
     boolean starting;           // True if the process is being started
     long lastActivityTime;      // For managing the LRU list
     long lruWeight;             // Weight for ordering in LRU list
+    long lastPssTime;           // Last time we requested PSS data
     int maxAdj;                 // Maximum OOM adjustment for this process
     int cachedAdj;              // If cached, this is the adjustment to use
     int clientCachedAdj;        // If empty but cached client, this is the adjustment to use
@@ -112,7 +113,6 @@
     boolean reportLowMemory;    // Set to true when waiting to report low mem
     boolean empty;              // Is this an empty background process?
     boolean cached;             // Is this a cached process?
-    int lastPss;                // Last pss size reported by app.
     String adjType;             // Debugging: primary thing impacting oom_adj.
     int adjTypeCode;            // Debugging: adj code to report to app.
     Object adjSource;           // Debugging: option dependent object.
@@ -180,7 +180,12 @@
         pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir);
                 pw.print(" publicDir="); pw.print(info.publicSourceDir);
                 pw.print(" data="); pw.println(info.dataDir);
-        pw.print(prefix); pw.print("packageList="); pw.println(pkgList);
+        pw.print(prefix); pw.print("packageList={");
+        for (int i=0; i<pkgList.size(); i++) {
+            if (i > 0) pw.print(", ");
+            pw.print(pkgList.keyAt(i));
+        }
+        pw.println("}");
         pw.print(prefix); pw.print("compat="); pw.println(compat);
         if (instrumentationClass != null || instrumentationProfileFile != null
                 || instrumentationArguments != null) {
@@ -198,7 +203,7 @@
         }
         pw.print(prefix); pw.print("thread="); pw.println(thread);
         pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
-                pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
+                pw.println(starting);
         pw.print(prefix); pw.print("lastActivityTime=");
                 TimeUtils.formatDuration(lastActivityTime, now, pw);
                 pw.print(" lruWeight="); pw.print(lruWeight);
@@ -220,7 +225,8 @@
                 pw.print(" systemNoUi="); pw.print(systemNoUi);
                 pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
-                pw.print(" lruSeq="); pw.println(lruSeq);
+                pw.print(" lruSeq="); pw.print(lruSeq);
+                pw.print(" lastPssTime="); pw.println(lastPssTime);
         if (hasShownUi || pendingUiClean || hasAboveClient) {
             pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
                     pw.print(" pendingUiClean="); pw.print(pendingUiClean);
@@ -345,6 +351,7 @@
         curAdj = setAdj = -100;
         persistent = false;
         removed = false;
+        lastPssTime = SystemClock.uptimeMillis();
     }
 
     public void setPid(int _pid) {
@@ -451,21 +458,20 @@
             ProcessList plist) {
         int state = this == TOP_APP ? ProcessTracker.STATE_TOP
                 : plist.adjToTrackedState(setAdj);
-        if (pkgList.size() > 0) {
-            pkgList.valueAt(0).setState(state, memFactor, now, pkgList);
-        }
+        baseProcessTracker.setState(state, memFactor, now, pkgList);
     }
 
     /*
      *  Delete all packages from list except the package indicated in info
      */
-    public void resetPackageList() {
+    public void resetPackageList(ProcessTracker tracker) {
         long now = SystemClock.uptimeMillis();
-        if (pkgList.size() > 0) {
-            pkgList.valueAt(0).setState(ProcessTracker.STATE_NOTHING, 0, now, pkgList);
+        baseProcessTracker.setState(ProcessTracker.STATE_NOTHING, 0, now, pkgList);
+        if (pkgList.size() != 1) {
+            pkgList.clear();
+            pkgList.put(info.packageName, tracker.getProcessStateLocked(
+                    info.packageName, info.uid, processName));
         }
-        pkgList.clear();
-        pkgList.put(info.packageName, baseProcessTracker);
     }
     
     public String[] getPackageList() {
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
index 30470f1..82b2158 100644
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ b/services/java/com/android/server/am/ProcessTracker.java
@@ -48,6 +48,11 @@
     public static final int STATE_CACHED = 9;
     public static final int STATE_COUNT = STATE_CACHED+1;
 
+    static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, STATE_TOP,
+            STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, STATE_BACKUP,
+            STATE_SERVICE, STATE_HOME, STATE_PREVIOUS, STATE_CACHED
+    };
+
     public static final int PSS_SAMPLE_COUNT = 0;
     public static final int PSS_MINIMUM = 1;
     public static final int PSS_AVERAGE = 2;
@@ -65,6 +70,10 @@
     public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
     public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
 
+    static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
+    static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, ADJ_MEM_FACTOR_MODERATE,
+            ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
+
     // Most data is kept in a sparse data structure: an integer array which integer
     // holds the type of the entry, and the identifier for a long array that data
     // exists in and the offset into the array to find it.  The constants below
@@ -110,7 +119,7 @@
 
     static final String[] STATE_TAGS = new String[] {
             "p", "t", "f", "v", "t",
-            "b", "s", "h", "v", "c"
+            "b", "s", "h", "r", "c"
     };
 
     static final String CSV_SEP = "\t";
@@ -132,9 +141,14 @@
         int mCurState = STATE_NOTHING;
         long mStartTime;
 
+        int mLastPssState = STATE_NOTHING;
+        long mLastPssTime;
         int[] mPssTable;
         int mPssTableSize;
 
+        int mNumExcessiveWake;
+        int mNumExcessiveCpu;
+
         boolean mMultiPackage;
 
         long mTmpTotalTime;
@@ -145,7 +159,7 @@
          */
         public ProcessState(State state, String pkg, int uid, String name) {
             mState = state;
-            mCommonProcess = null;
+            mCommonProcess = this;
             mPackage = pkg;
             mUid = uid;
             mName = name;
@@ -199,6 +213,8 @@
                 pnew.mPssTableSize = mState.mFindTableSize;
             }
             */
+            pnew.mNumExcessiveWake = mNumExcessiveWake;
+            pnew.mNumExcessiveCpu = mNumExcessiveCpu;
             return pnew;
         }
 
@@ -208,30 +224,16 @@
                 state += memFactor*STATE_COUNT;
             }
 
-            if (mCommonProcess != null) {
-                // First update the common process.
-                mCommonProcess.setState(state, now);
-                if (!mCommonProcess.mMultiPackage) {
-                    // This common process is for a single package, so it is shared
-                    // with the per-package state.  Nothing more to do.
-                    return;
-                }
+            // First update the common process.
+            mCommonProcess.setState(state, now);
+
+            // If the common process is not multi-package, there is nothing else to do.
+            if (!mCommonProcess.mMultiPackage) {
+                return;
             }
 
             for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                ProcessState proc = pkgList.valueAt(ip);
-                if (proc.mMultiPackage) {
-                    // The array map is still pointing to a common process state
-                    // that is now shared across packages.  Update it to point to
-                    // the new per-package state.
-                    proc = mState.mPackages.get(pkgList.keyAt(ip),
-                            proc.mUid).mProcesses.get(proc.mName);
-                    if (proc == null) {
-                        throw new IllegalStateException("Didn't create per-package process");
-                    }
-                    pkgList.setValueAt(ip, proc);
-                }
-                proc.setState(state, now);
+                pullFixedProc(pkgList, ip).setState(state, now);
             }
         }
 
@@ -258,7 +260,15 @@
             }
         }
 
-        public void addPss(long pss) {
+        public void addPss(long pss, boolean always) {
+            if (!always) {
+                if (mLastPssState == mCurState && SystemClock.uptimeMillis()
+                        < (mLastPssTime+(30*1000))) {
+                    return;
+                }
+            }
+            mLastPssState = mCurState;
+            mLastPssTime = SystemClock.uptimeMillis();
             if (mCurState != STATE_NOTHING) {
                 int idx = State.binarySearch(mPssTable, mPssTableSize, mCurState);
                 int off;
@@ -284,7 +294,8 @@
                     if (longs[idx+PSS_MINIMUM] > pss) {
                         longs[idx+PSS_MINIMUM] = pss;
                     }
-                    longs[idx+PSS_AVERAGE] = ((longs[idx+PSS_AVERAGE]*count)+pss)/(count+1);
+                    longs[idx+PSS_AVERAGE] = (long)( ((longs[idx+PSS_AVERAGE]*(double)count)+pss)
+                            / (count+1) );
                     if (longs[idx+PSS_MAXIMUM] < pss) {
                         longs[idx+PSS_MAXIMUM] = pss;
                     }
@@ -292,6 +303,45 @@
             }
         }
 
+        public void reportExcessiveWake(ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
+            mCommonProcess.mNumExcessiveWake++;
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                pullFixedProc(pkgList, ip).mNumExcessiveWake++;
+            }
+        }
+
+        public void reportExcessiveCpu(ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
+            mCommonProcess.mNumExcessiveCpu++;
+            if (!mCommonProcess.mMultiPackage) {
+                return;
+            }
+
+            for (int ip=pkgList.size()-1; ip>=0; ip--) {
+                pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
+            }
+        }
+
+        private ProcessState pullFixedProc(ArrayMap<String, ProcessTracker.ProcessState> pkgList,
+                int index) {
+            ProcessState proc = pkgList.valueAt(index);
+            if (proc.mMultiPackage) {
+                // The array map is still pointing to a common process state
+                // that is now shared across packages.  Update it to point to
+                // the new per-package state.
+                proc = mState.mPackages.get(pkgList.keyAt(index),
+                        proc.mUid).mProcesses.get(proc.mName);
+                if (proc == null) {
+                    throw new IllegalStateException("Didn't create per-package process");
+                }
+                pkgList.setValueAt(index, proc);
+            }
+            return proc;
+        }
+
         long getDuration(int state, long now) {
             int idx = State.binarySearch(mDurationsTable, mDurationsTableSize, state);
             long time = idx >= 0 ? mState.getLong(mDurationsTable[idx], 0) : 0;
@@ -685,7 +735,7 @@
         }
     }
 
-    static void dumpSingleTimeCsv(PrintWriter pw, String sep, long[] durations,
+    static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
             int curState, long curStartTime, long now) {
         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
@@ -694,8 +744,9 @@
                 if (curState == state) {
                     time += now - curStartTime;
                 }
-                pw.print(sep);
-                pw.print(time);
+                if (time != 0) {
+                    printAdjTagAndValue(pw, state, time);
+                }
             }
         }
     }
@@ -714,11 +765,11 @@
         pw.print(",");
         pw.print(serviceName);
         pw.print(opCount);
-        dumpSingleTimeCsv(pw, ",", durations, curState, curStartTime, now);
+        dumpAdjTimesCheckin(pw, ",", durations, curState, curStartTime, now);
         pw.println();
     }
 
-    long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
+    static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
                 int[] procStates, long now) {
         long totalTime = 0;
         /*
@@ -756,10 +807,7 @@
                 PackageState state = procs.valueAt(iu);
                 for (int iproc=0; iproc<state.mProcesses.size(); iproc++) {
                     ProcessState proc = state.mProcesses.valueAt(iproc);
-                    if (proc.mCommonProcess != null) {
-                        proc = proc.mCommonProcess;
-                    }
-                    foundProcs.add(proc);
+                    foundProcs.add(proc.mCommonProcess);
                 }
             }
         }
@@ -785,8 +833,8 @@
         return outProcs;
     }
 
-    void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
-            int[] memStates, int[] procStates, long now) {
+    static void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc,
+            int[] screenStates, int[] memStates, int[] procStates, long now) {
         long totalTime = 0;
         int printedScreen = -1;
         for (int is=0; is<screenStates.length; is++) {
@@ -833,7 +881,7 @@
         }
     }
 
-    void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
+    static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
             int[] memStates, int[] procStates) {
         boolean printedHeader = false;
         int printedScreen = -1;
@@ -877,9 +925,17 @@
                 }
             }
         }
+        if (proc.mNumExcessiveWake != 0) {
+            pw.print(prefix); pw.print("Killed for excessive wake locks: ");
+                    pw.print(proc.mNumExcessiveWake); pw.println(" times");
+        }
+        if (proc.mNumExcessiveCpu != 0) {
+            pw.print(prefix); pw.print("Killed for excessive CPU use: ");
+                    pw.print(proc.mNumExcessiveCpu); pw.println(" times");
+        }
     }
 
-    void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
+    static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
             int[] memStates, int[] procStates) {
         final int NS = screenStates != null ? screenStates.length : 1;
         final int NM = memStates != null ? memStates.length : 1;
@@ -911,7 +967,7 @@
         }
     }
 
-    void dumpProcessStateCsv(PrintWriter pw, ProcessState proc,
+    static void dumpProcessStateCsv(PrintWriter pw, ProcessState proc,
             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
             boolean sepProcStates, int[] procStates, long now) {
         final int NSS = sepScreenStates ? screenStates.length : 1;
@@ -946,7 +1002,7 @@
         }
     }
 
-    void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
+    static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
             int[] screenStates, int[] memStates, int[] procStates, long now) {
         String innerPrefix = prefix + "  ";
         for (int i=procs.size()-1; i>=0; i--) {
@@ -966,7 +1022,7 @@
         }
     }
 
-    void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
+    static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
             boolean sepProcStates, int[] procStates, long now) {
         pw.print("process");
@@ -1014,44 +1070,6 @@
         return false;
     }
 
-    void dumpAllProcessState(PrintWriter pw, String prefix, ProcessState proc, long now) {
-        long totalTime = 0;
-        int printedScreen = -1;
-        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
-            int printedMem = -1;
-            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
-                for (int is=0; is<STATE_NAMES.length; is++) {
-                    int bucket = is+(STATE_COUNT*(imem+iscreen));
-                    long time = proc.getDuration(bucket, now);
-                    String running = "";
-                    if (proc.mCurState == bucket) {
-                        running = " (running)";
-                    }
-                    if (time != 0) {
-                        pw.print(prefix);
-                        printScreenLabel(pw, printedScreen != iscreen
-                                ? iscreen : STATE_NOTHING);
-                        printedScreen = iscreen;
-                        printMemLabel(pw, printedMem != imem
-                                ? imem : STATE_NOTHING);
-                        printedMem = imem;
-                        pw.print(STATE_NAMES[is]); pw.print(": ");
-                        TimeUtils.formatDuration(time, pw); pw.println(running);
-                        totalTime += time;
-                    }
-                }
-            }
-        }
-        if (totalTime != 0) {
-            pw.print(prefix);
-            printScreenLabel(pw, STATE_NOTHING);
-            printMemLabel(pw, STATE_NOTHING);
-            pw.print("TOTAL      : ");
-            TimeUtils.formatDuration(totalTime, pw);
-            pw.println();
-        }
-    }
-
     static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
         int index = value/mod;
         if (index >= 0 && index < array.length) {
@@ -1062,20 +1080,32 @@
         return value - index*mod;
     }
 
-    void printProcStateTag(PrintWriter pw, int state) {
+    static void printProcStateTag(PrintWriter pw, int state) {
         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
         state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
         printArrayEntry(pw, STATE_TAGS,  state, 1);
     }
 
-    void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
+    static void printAdjTag(PrintWriter pw, int state) {
+        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
+        printArrayEntry(pw, ADJ_MEM_TAGS,  state, 1);
+    }
+
+    static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
         pw.print(',');
         printProcStateTag(pw, state);
         pw.print(':');
         pw.print(value);
     }
 
-    void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
+    static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
+        pw.print(',');
+        printAdjTag(pw, state);
+        pw.print(':');
+        pw.print(value);
+    }
+
+    static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
         boolean didCurState = false;
         for (int i=0; i<proc.mDurationsTableSize; i++) {
             int off = proc.mDurationsTable[i];
@@ -1092,7 +1122,7 @@
         }
     }
 
-    void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc, long now) {
+    static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
         for (int i=0; i<proc.mPssTableSize; i++) {
             int off = proc.mPssTable[i];
             int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
@@ -1154,7 +1184,7 @@
         return finalRes;
     }
 
-    private void dumpHelp(PrintWriter pw) {
+    static private void dumpHelp(PrintWriter pw) {
         pw.println("Process stats (procstats) dump options:");
         pw.println("    [--checkin|--csv] [csv-screen] [csv-proc] [csv-mem]");
         pw.println("    [--reset] [-h] [<package.name>]");
@@ -1165,6 +1195,7 @@
         pw.println("  --csv-proc: pers, top, fore, vis, precept, backup,");
         pw.println("    service, home, prev, cached");
         pw.println("  --reset: reset the stats, clearing all current data.");
+        pw.println("  -a: print everything.");
         pw.println("  -h: print this help text.");
         pw.println("  <package.name>: optional name of package to filter output by.");
     }
@@ -1174,6 +1205,7 @@
 
         boolean isCheckin = false;
         boolean isCsv = false;
+        boolean dumpAll = false;
         String reqPackage = null;
         boolean csvSepScreenStats = false;
         int[] csvScreenStats = new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON};
@@ -1248,7 +1280,7 @@
                     dumpHelp(pw);
                     return;
                 } else if ("-a".equals(arg)) {
-                    // ignore
+                    dumpAll = true;
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     dumpHelp(pw);
@@ -1332,8 +1364,6 @@
                     if (NPROCS > 0 || NSRVS > 0) {
                         if (!printedHeader) {
                             pw.println("Per-Package Process Stats:");
-                            pw.print("  Num long arrays: "); pw.println(mState.mLongs.size());
-                            pw.print("  Next long entry: "); pw.println(mState.mNextLong);
                             printedHeader = true;
                         }
                         pw.print("  * "); pw.print(pkgName); pw.print(" / ");
@@ -1349,7 +1379,10 @@
                         pw.print(proc.mDurationsTableSize);
                         pw.print(" entries)");
                         pw.println(":");
-                        dumpAllProcessState(pw, "        ", proc, now);
+                        dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                ALL_PROC_STATES, now);
+                        dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                                ALL_PROC_STATES);
                     } else {
                         pw.print("pkgproc,");
                         pw.print(pkgName);
@@ -1359,6 +1392,29 @@
                         pw.print(state.mProcesses.keyAt(iproc));
                         dumpAllProcessStateCheckin(pw, proc, now);
                         pw.println();
+                        if (proc.mPssTableSize > 0) {
+                            pw.print("pkgpss,");
+                            pw.print(pkgName);
+                            pw.print(",");
+                            pw.print(uid);
+                            pw.print(",");
+                            pw.print(state.mProcesses.keyAt(iproc));
+                            dumpAllProcessPssCheckin(pw, proc);
+                            pw.println();
+                        }
+                        if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0) {
+                            pw.print("pkgkills,");
+                            pw.print(pkgName);
+                            pw.print(",");
+                            pw.print(uid);
+                            pw.print(",");
+                            pw.print(state.mProcesses.keyAt(iproc));
+                            pw.print(",");
+                            pw.print(proc.mNumExcessiveWake);
+                            pw.print(",");
+                            pw.print(proc.mNumExcessiveCpu);
+                            pw.println();
+                        }
                     }
                 }
                 for (int isvc=0; isvc<NSRVS; isvc++) {
@@ -1431,6 +1487,12 @@
             pw.println("Run time Stats:");
             dumpSingleTime(pw, "  ", mState.mMemFactorDurations, mState.mMemFactor,
                     mState.mStartTime, now);
+            if (dumpAll) {
+                pw.println();
+                pw.println("Internal state:");
+                pw.print("  Num long arrays: "); pw.println(mState.mLongs.size());
+                pw.print("  Next long entry: "); pw.println(mState.mNextLong);
+            }
         } else {
             ArrayMap<String, SparseArray<ProcessState>> procMap = mState.mProcesses.getMap();
             for (int ip=0; ip<procMap.size(); ip++) {
@@ -1452,13 +1514,24 @@
                         pw.print(procName);
                         pw.print(",");
                         pw.print(uid);
-                        dumpAllProcessPssCheckin(pw, state, now);
+                        dumpAllProcessPssCheckin(pw, state);
+                        pw.println();
+                    }
+                    if (state.mNumExcessiveWake > 0 || state.mNumExcessiveCpu > 0) {
+                        pw.print("kills,");
+                        pw.print(uid);
+                        pw.print(",");
+                        pw.print(procName);
+                        pw.print(",");
+                        pw.print(state.mNumExcessiveWake);
+                        pw.print(",");
+                        pw.print(state.mNumExcessiveCpu);
                         pw.println();
                     }
                 }
             }
             pw.print("total");
-            dumpSingleTimeCsv(pw, ",", mState.mMemFactorDurations, mState.mMemFactor,
+            dumpAdjTimesCheckin(pw, ",", mState.mMemFactorDurations, mState.mMemFactor,
                     mState.mStartTime, now);
             pw.println();
         }