Merge "Start really collecting PSS data for process stats."
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 ad6ae43..ed9416e 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);
@@ -10956,7 +11068,7 @@
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
 
-        if (procs.size() == 1 || isCheckinRequest) {
+        if (!brief && !oomOnly && (procs.size() == 1 || isCheckinRequest)) {
             dumpDetails = true;
         }
 
@@ -10982,17 +11094,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!");
@@ -11000,21 +11119,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;
@@ -11092,7 +11221,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(" ");
@@ -11102,10 +11231,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) {
@@ -11131,7 +11260,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:");
@@ -11139,29 +11268,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");
+            }
         }
     }
 
@@ -11258,6 +11389,7 @@
         }
 
         mProcessesToGc.remove(app);
+        mPendingPssProcesses.remove(app);
         
         // Dismiss any open dialogs.
         if (app.crashDialog != null && !app.forceCrashReport) {
@@ -11276,7 +11408,7 @@
         app.crashing = false;
         app.notResponding = false;
         
-        app.resetPackageList();
+        app.resetPackageList(mProcessTracker);
         app.unlinkDeathRecipient();
         app.thread = null;
         app.forcingToForeground = null;
@@ -13771,6 +13903,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) {
@@ -13981,6 +14148,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) {
@@ -13993,6 +14161,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;
@@ -14034,11 +14203,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) {
@@ -14428,6 +14609,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 f730e07..973b9aa 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();
         }