resolved conflicts for merge of 8952a448 to master

Change-Id: I9c752a5d10ae8d8e5ead1243b6abd4795204fc0b
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index f901bfb..4dee350 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,6 +19,7 @@
 package com.android.commands.am;
 
 import android.app.ActivityManagerNative;
+import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IInstrumentationWatcher;
 import android.app.Instrumentation;
@@ -28,12 +29,18 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.AndroidException;
 import android.view.IWindowManager;
 
+import java.io.BufferedReader;
+import java.io.DataInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.PrintStream;
 import java.net.URISyntaxException;
 import java.util.Iterator;
@@ -99,6 +106,8 @@
             runProfile();
         } else if (op.equals("dumpheap")) {
             runDumpHeap();
+        } else if (op.equals("monitor")) {
+            runMonitor();
         } else {
             throw new IllegalArgumentException("Unknown command: " + op);
         }
@@ -472,6 +481,210 @@
         }
     }
 
+    class MyActivityController extends IActivityController.Stub {
+        static final int STATE_NORMAL = 0;
+        static final int STATE_CRASHED = 1;
+        static final int STATE_EARLY_ANR = 2;
+        static final int STATE_ANR = 3;
+
+        int mState;
+
+        static final int RESULT_DEFAULT = 0;
+
+        static final int RESULT_CRASH_DIALOG = 0;
+        static final int RESULT_CRASH_KILL = 1;
+
+        static final int RESULT_EARLY_ANR_CONTINUE = 0;
+        static final int RESULT_EARLY_ANR_KILL = 1;
+
+        static final int RESULT_ANR_DIALOG = 0;
+        static final int RESULT_ANR_KILL = 1;
+        static final int RESULT_ANR_WAIT = 1;
+
+        int mResult;
+
+        @Override
+        public boolean activityResuming(String pkg) throws RemoteException {
+            synchronized (this) {
+                System.out.println("** Activity resuming: " + pkg);
+            }
+            return true;
+        }
+
+        @Override
+        public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
+            synchronized (this) {
+                System.out.println("** Activity starting: " + pkg);
+            }
+            return true;
+        }
+
+        @Override
+        public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
+                long timeMillis, String stackTrace) throws RemoteException {
+            synchronized (this) {
+                System.out.println("** ERROR: PROCESS CRASHED");
+                System.out.println("processName: " + processName);
+                System.out.println("processPid: " + pid);
+                System.out.println("shortMsg: " + shortMsg);
+                System.out.println("longMsg: " + longMsg);
+                System.out.println("timeMillis: " + timeMillis);
+                System.out.println("stack:");
+                System.out.print(stackTrace);
+                System.out.println("#");
+                int result = waitControllerLocked(STATE_CRASHED);
+                return result == RESULT_CRASH_KILL ? false : true;
+            }
+        }
+
+        @Override
+        public int appEarlyNotResponding(String processName, int pid, String annotation)
+                throws RemoteException {
+            synchronized (this) {
+                System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING");
+                System.out.println("processName: " + processName);
+                System.out.println("processPid: " + pid);
+                System.out.println("annotation: " + annotation);
+                int result = waitControllerLocked(STATE_EARLY_ANR);
+                if (result == RESULT_EARLY_ANR_KILL) return -1;
+                return 0;
+            }
+        }
+
+        @Override
+        public int appNotResponding(String processName, int pid, String processStats)
+                throws RemoteException {
+            synchronized (this) {
+                System.out.println("** ERROR: PROCESS NOT RESPONDING");
+                System.out.println("processName: " + processName);
+                System.out.println("processPid: " + pid);
+                System.out.println("processStats:");
+                System.out.print(processStats);
+                System.out.println("#");
+                int result = waitControllerLocked(STATE_ANR);
+                if (result == RESULT_ANR_KILL) return -1;
+                if (result == RESULT_ANR_WAIT) return 1;
+                return 0;
+            }
+        }
+
+        int waitControllerLocked(int state) {
+            mState = state;
+            System.out.println("");
+            printMessageForState();
+
+            while (mState != STATE_NORMAL) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+
+            return mResult;
+        }
+
+        void resumeController(int result) {
+            synchronized (this) {
+                mState = STATE_NORMAL;
+                mResult = result;
+                notifyAll();
+            }
+        }
+
+        void printMessageForState() {
+            switch (mState) {
+                case STATE_NORMAL:
+                    System.out.println("Monitoring activity manager...  available commands:");
+                    break;
+                case STATE_CRASHED:
+                    System.out.println("Waiting after crash...  available commands:");
+                    System.out.println("(c)ontinue: show crash dialog");
+                    System.out.println("(k)ill: immediately kill app");
+                    break;
+                case STATE_EARLY_ANR:
+                    System.out.println("Waiting after early ANR...  available commands:");
+                    System.out.println("(c)ontinue: standard ANR processing");
+                    System.out.println("(k)ill: immediately kill app");
+                    break;
+                case STATE_ANR:
+                    System.out.println("Waiting after ANR...  available commands:");
+                    System.out.println("(c)ontinue: show ANR dialog");
+                    System.out.println("(k)ill: immediately kill app");
+                    System.out.println("(w)ait: wait some more");
+                    break;
+            }
+            System.out.println("(q)uit: finish monitoring");
+        }
+
+        void run() throws RemoteException {
+            try {
+                printMessageForState();
+
+                mAm.setActivityController(this);
+                mState = STATE_NORMAL;
+
+                InputStreamReader converter = new InputStreamReader(System.in);
+                BufferedReader in = new BufferedReader(converter);
+                String line;
+
+                while ((line = in.readLine()) != null) {
+                    boolean addNewline = true;
+                    if (line.length() <= 0) {
+                        addNewline = false;
+                    } else if ("q".equals(line) || "quit".equals(line)) {
+                        resumeController(RESULT_DEFAULT);
+                        break;
+                    } else if (mState == STATE_CRASHED) {
+                        if ("c".equals(line) || "continue".equals(line)) {
+                            resumeController(RESULT_CRASH_DIALOG);
+                        } else if ("k".equals(line) || "kill".equals(line)) {
+                            resumeController(RESULT_CRASH_KILL);
+                        } else {
+                            System.out.println("Invalid command: " + line);
+                        }
+                    } else if (mState == STATE_ANR) {
+                        if ("c".equals(line) || "continue".equals(line)) {
+                            resumeController(RESULT_ANR_DIALOG);
+                        } else if ("k".equals(line) || "kill".equals(line)) {
+                            resumeController(RESULT_ANR_KILL);
+                        } else if ("w".equals(line) || "wait".equals(line)) {
+                            resumeController(RESULT_ANR_WAIT);
+                        } else {
+                            System.out.println("Invalid command: " + line);
+                        }
+                    } else if (mState == STATE_EARLY_ANR) {
+                        if ("c".equals(line) || "continue".equals(line)) {
+                            resumeController(RESULT_EARLY_ANR_CONTINUE);
+                        } else if ("k".equals(line) || "kill".equals(line)) {
+                            resumeController(RESULT_EARLY_ANR_KILL);
+                        } else {
+                            System.out.println("Invalid command: " + line);
+                        }
+                    } else {
+                        System.out.println("Invalid command: " + line);
+                    }
+
+                    synchronized (this) {
+                        if (addNewline) {
+                            System.out.println("");
+                        }
+                        printMessageForState();
+                    }
+                }
+
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                mAm.setActivityController(null);
+            }
+        }
+    }
+
+    private void runMonitor() throws Exception {
+        MyActivityController controller = new MyActivityController();
+        controller.run();
+    }
+
     private class IntentReceiver extends IIntentReceiver.Stub {
         private boolean mFinished = false;
 
@@ -649,6 +862,8 @@
                 "    dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" +
                 "        -n: dump native heap instead of managed heap\n" +
                 "\n" +
+                "    start monitoring: am monitor\n" +
+                "\n" +
                 "    <INTENT> specifications include these flags:\n" +
                 "        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                 "        [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3f74904..2ff88da 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -61,6 +61,7 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.LogPrinter;
 import android.util.Slog;
 import android.view.Display;
 import android.view.HardwareRenderer;
@@ -121,6 +122,7 @@
     private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
     private static final boolean DEBUG = false;
     static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+    static final boolean DEBUG_MESSAGES = false;
     static final boolean DEBUG_BROADCAST = false;
     private static final boolean DEBUG_RESULTS = false;
     private static final boolean DEBUG_BACKUP = false;
@@ -913,7 +915,7 @@
         public static final int DUMP_HEAP               = 135;
         public static final int DUMP_ACTIVITY           = 136;
         String codeToString(int code) {
-            if (localLOGV) {
+            if (DEBUG_MESSAGES) {
                 switch (code) {
                     case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
                     case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
@@ -957,6 +959,7 @@
             return "(unknown)";
         }
         public void handleMessage(Message msg) {
+            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
             switch (msg.what) {
                 case LAUNCH_ACTIVITY: {
                     ActivityClientRecord r = (ActivityClientRecord)msg.obj;
@@ -1084,6 +1087,7 @@
                     handleDumpActivity((DumpComponentInfo)msg.obj);
                     break;
             }
+            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
         }
 
         void maybeSnapshot() {
@@ -1550,7 +1554,7 @@
 
     private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
         synchronized (this) {
-            if (localLOGV) Slog.v(
+            if (DEBUG_MESSAGES) Slog.v(
                 TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
                 + ": " + arg1 + " / " + obj);
             Message msg = Message.obtain();
@@ -3699,6 +3703,11 @@
         ActivityThread thread = new ActivityThread();
         thread.attach(false);
 
+        if (false) {
+            Looper.myLooper().setMessageLogging(new
+                    LogPrinter(Log.DEBUG, "ActivityThread"));
+        }
+
         Looper.loop();
 
         if (Process.supportsProcesses()) {
diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl
index c76a517..aca8305 100644
--- a/core/java/android/app/IActivityController.aidl
+++ b/core/java/android/app/IActivityController.aidl
@@ -48,6 +48,11 @@
             long timeMillis, String stackTrace);
     
     /**
+     * Early call as soon as an ANR is detected.
+     */
+    int appEarlyNotResponding(String processName, int pid, String annotation);
+
+    /**
      * An application process is not responding.  Return 0 to show the "app
      * not responding" dialog, 1 to continue waiting, or -1 to kill it
      * immediately.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ba8014f2..d49c8be 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -301,7 +301,11 @@
          */
         public static abstract class Proc {
 
-            public static class ExcessiveWake {
+            public static class ExcessivePower {
+                public static final int TYPE_WAKE = 1;
+                public static final int TYPE_CPU = 2;
+
+                public int type;
                 public long overTime;
                 public long usedTime;
             }
@@ -343,9 +347,9 @@
              */
             public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
 
-            public abstract int countExcessiveWakes();
+            public abstract int countExcessivePowers();
 
-            public abstract ExcessiveWake getExcessiveWake(int i);
+            public abstract ExcessivePower getExcessivePower(int i);
         }
 
         /**
@@ -1593,7 +1597,7 @@
                     systemTime = ps.getSystemTime(which);
                     starts = ps.getStarts(which);
                     numExcessive = which == STATS_SINCE_CHARGED
-                            ? ps.countExcessiveWakes() : 0;
+                            ? ps.countExcessivePowers() : 0;
 
                     if (userTime != 0 || systemTime != 0 || starts != 0
                             || numExcessive != 0) {
@@ -1609,9 +1613,17 @@
                         }
                         pw.println(sb.toString());
                         for (int e=0; e<numExcessive; e++) {
-                            Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e);
+                            Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
                             if (ew != null) {
-                                pw.print(prefix); pw.print("      * Killed for wake lock use: ");
+                                pw.print(prefix); pw.print("      * Killed for ");
+                                        if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
+                                            pw.print("wake lock");
+                                        } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
+                                            pw.print("cpu");
+                                        } else {
+                                            pw.print("unknown");
+                                        }
+                                        pw.print(" use: ");
                                         TimeUtils.formatDuration(ew.usedTime, pw);
                                         pw.print(" over ");
                                         TimeUtils.formatDuration(ew.overTime, pw);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4e61ddf..66149ac 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -67,7 +67,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 51;
+    private static final int VERSION = 52;
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -85,7 +85,7 @@
 
     static final int MSG_UPDATE_WAKELOCKS = 1;
     static final int MSG_REPORT_POWER_CHANGE = 2;
-    static final long DELAY_UPDATE_WAKELOCKS = 15*1000;
+    static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
 
     public interface BatteryCallback {
         public void batteryNeedsCpuUpdate();
@@ -1476,6 +1476,13 @@
         }
     }
 
+    public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.reportExcessiveCpuLocked(proc, overTime, usedTime);
+        }
+    }
+
     int mSensorNesting;
 
     public void noteStartSensorLocked(int uid, int sensor) {
@@ -2977,7 +2984,7 @@
 
             SamplingCounter[] mSpeedBins;
 
-            ArrayList<ExcessiveWake> mExcessiveWake;
+            ArrayList<ExcessivePower> mExcessivePower;
 
             Proc() {
                 mUnpluggables.add(this);
@@ -3005,55 +3012,69 @@
                 }
             }
             
-            public int countExcessiveWakes() {
-                return mExcessiveWake != null ? mExcessiveWake.size() : 0;
+            public int countExcessivePowers() {
+                return mExcessivePower != null ? mExcessivePower.size() : 0;
             }
 
-            public ExcessiveWake getExcessiveWake(int i) {
-                if (mExcessiveWake != null) {
-                    return mExcessiveWake.get(i);
+            public ExcessivePower getExcessivePower(int i) {
+                if (mExcessivePower != null) {
+                    return mExcessivePower.get(i);
                 }
                 return null;
             }
 
             public void addExcessiveWake(long overTime, long usedTime) {
-                if (mExcessiveWake == null) {
-                    mExcessiveWake = new ArrayList<ExcessiveWake>();
+                if (mExcessivePower == null) {
+                    mExcessivePower = new ArrayList<ExcessivePower>();
                 }
-                ExcessiveWake ew = new ExcessiveWake();
+                ExcessivePower ew = new ExcessivePower();
+                ew.type = ExcessivePower.TYPE_WAKE;
                 ew.overTime = overTime;
                 ew.usedTime = usedTime;
-                mExcessiveWake.add(ew);
+                mExcessivePower.add(ew);
             }
 
-            void writeExcessiveWakeToParcelLocked(Parcel out) {
-                if (mExcessiveWake == null) {
+            public void addExcessiveCpu(long overTime, long usedTime) {
+                if (mExcessivePower == null) {
+                    mExcessivePower = new ArrayList<ExcessivePower>();
+                }
+                ExcessivePower ew = new ExcessivePower();
+                ew.type = ExcessivePower.TYPE_CPU;
+                ew.overTime = overTime;
+                ew.usedTime = usedTime;
+                mExcessivePower.add(ew);
+            }
+
+            void writeExcessivePowerToParcelLocked(Parcel out) {
+                if (mExcessivePower == null) {
                     out.writeInt(0);
                     return;
                 }
 
-                final int N = mExcessiveWake.size();
+                final int N = mExcessivePower.size();
                 out.writeInt(N);
                 for (int i=0; i<N; i++) {
-                    ExcessiveWake ew = mExcessiveWake.get(i);
+                    ExcessivePower ew = mExcessivePower.get(i);
+                    out.writeInt(ew.type);
                     out.writeLong(ew.overTime);
                     out.writeLong(ew.usedTime);
                 }
             }
 
-            void readExcessiveWakeFromParcelLocked(Parcel in) {
+            void readExcessivePowerFromParcelLocked(Parcel in) {
                 final int N = in.readInt();
                 if (N == 0) {
-                    mExcessiveWake = null;
+                    mExcessivePower = null;
                     return;
                 }
 
-                mExcessiveWake = new ArrayList<ExcessiveWake>();
+                mExcessivePower = new ArrayList<ExcessivePower>();
                 for (int i=0; i<N; i++) {
-                    ExcessiveWake ew = new ExcessiveWake();
+                    ExcessivePower ew = new ExcessivePower();
+                    ew.type = in.readInt();
                     ew.overTime = in.readLong();
                     ew.usedTime = in.readLong();
-                    mExcessiveWake.add(ew);
+                    mExcessivePower.add(ew);
                 }
             }
 
@@ -3082,7 +3103,7 @@
                     }
                 }
 
-                writeExcessiveWakeToParcelLocked(out);
+                writeExcessivePowerToParcelLocked(out);
             }
 
             void readFromParcelLocked(Parcel in) {
@@ -3112,7 +3133,7 @@
                     }
                 }
 
-                readExcessiveWakeFromParcelLocked(in);
+                readExcessivePowerFromParcelLocked(in);
             }
 
             public BatteryStatsImpl getBatteryStats() {
@@ -3746,6 +3767,13 @@
             }
         }
         
+        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
+            Proc p = getProcessStatsLocked(proc);
+            if (p != null) {
+                p.addExcessiveCpu(overTime, usedTime);
+            }
+        }
+
         public void noteStartSensor(int sensor) {
             StopwatchTimer t = getSensorTimerLocked(sensor, true);
             if (t != null) {
@@ -4688,7 +4716,7 @@
                         p.mSpeedBins[i].readSummaryFromParcelLocked(in);
                     }
                 }
-                p.readExcessiveWakeFromParcelLocked(in);
+                p.readExcessivePowerFromParcelLocked(in);
             }
 
             NP = in.readInt();
@@ -4887,7 +4915,7 @@
                             out.writeInt(0);
                         }
                     }
-                    ps.writeExcessiveWakeToParcelLocked(out);
+                    ps.writeExcessivePowerToParcelLocked(out);
                 }
             }
 
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index 5bdadcc..43dbcc0 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -80,16 +80,24 @@
         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
         PROC_SPACE_TERM,
         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
-        PROC_SPACE_TERM|PROC_OUT_LONG                   // 14: stime
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: stime
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 21: vsize
     };
 
     static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
     static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
     static final int PROCESS_FULL_STAT_UTIME = 3;
     static final int PROCESS_FULL_STAT_STIME = 4;
+    static final int PROCESS_FULL_STAT_VSIZE = 5;
 
-    private final String[] mProcessFullStatsStringData = new String[5];
-    private final long[] mProcessFullStatsData = new long[5];
+    private final String[] mProcessFullStatsStringData = new String[6];
+    private final long[] mProcessFullStatsData = new long[6];
 
     private static final int[] SYSTEM_CPU_FORMAT = new int[] {
         PROC_SPACE_TERM|PROC_COMBINE,
@@ -171,6 +179,8 @@
         final ArrayList<Stats> threadStats;
         final ArrayList<Stats> workingThreads;
         
+        public boolean interesting;
+
         public String baseName;
         public String name;
         int nameWidth;
@@ -349,59 +359,62 @@
                         + (parentPid < 0 ? "process" : "thread")
                         + " pid " + pid + ": " + st);
 
-                final long uptime = SystemClock.uptimeMillis();
+                if (st.interesting) {
+                    final long uptime = SystemClock.uptimeMillis();
 
-                final long[] procStats = mProcessStatsData;
-                if (!Process.readProcFile(st.statFile.toString(),
-                        PROCESS_STATS_FORMAT, null, procStats, null)) {
-                    continue;
-                }
-                
-                final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
-                final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
-                final long utime = procStats[PROCESS_STAT_UTIME];
-                final long stime = procStats[PROCESS_STAT_STIME];
-
-                if (utime == st.base_utime && stime == st.base_stime) {
-                    st.rel_utime = 0;
-                    st.rel_stime = 0;
-                    st.rel_minfaults = 0;
-                    st.rel_majfaults = 0;
-                    if (st.active) {
-                        st.active = false;
+                    final long[] procStats = mProcessStatsData;
+                    if (!Process.readProcFile(st.statFile.toString(),
+                            PROCESS_STATS_FORMAT, null, procStats, null)) {
+                        continue;
                     }
-                    continue;
-                }
                     
-                if (!st.active) {
-                    st.active = true;
-                }
+                    final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
+                    final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
+                    final long utime = procStats[PROCESS_STAT_UTIME];
+                    final long stime = procStats[PROCESS_STAT_STIME];
 
-                if (parentPid < 0) {
-                    getName(st, st.cmdlineFile);
-                    if (st.threadStats != null) {
-                        mCurThreadPids = collectStats(st.threadsDir, pid, false,
-                                mCurThreadPids, st.threadStats);
+                    if (utime == st.base_utime && stime == st.base_stime) {
+                        st.rel_utime = 0;
+                        st.rel_stime = 0;
+                        st.rel_minfaults = 0;
+                        st.rel_majfaults = 0;
+                        if (st.active) {
+                            st.active = false;
+                        }
+                        continue;
                     }
+
+                    if (!st.active) {
+                        st.active = true;
+                    }
+
+                    if (parentPid < 0) {
+                        getName(st, st.cmdlineFile);
+                        if (st.threadStats != null) {
+                            mCurThreadPids = collectStats(st.threadsDir, pid, false,
+                                    mCurThreadPids, st.threadStats);
+                        }
+                    }
+
+                    if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
+                            + " utime=" + utime + "-" + st.base_utime
+                            + " stime=" + stime + "-" + st.base_stime
+                            + " minfaults=" + minfaults + "-" + st.base_minfaults
+                            + " majfaults=" + majfaults + "-" + st.base_majfaults);
+
+                    st.rel_uptime = uptime - st.base_uptime;
+                    st.base_uptime = uptime;
+                    st.rel_utime = (int)(utime - st.base_utime);
+                    st.rel_stime = (int)(stime - st.base_stime);
+                    st.base_utime = utime;
+                    st.base_stime = stime;
+                    st.rel_minfaults = (int)(minfaults - st.base_minfaults);
+                    st.rel_majfaults = (int)(majfaults - st.base_majfaults);
+                    st.base_minfaults = minfaults;
+                    st.base_majfaults = majfaults;
+                    st.working = true;
                 }
 
-                if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
-                        + " utime=" + utime + "-" + st.base_utime
-                        + " stime=" + stime + "-" + st.base_stime
-                        + " minfaults=" + minfaults + "-" + st.base_minfaults
-                        + " majfaults=" + majfaults + "-" + st.base_majfaults);
-
-                st.rel_uptime = uptime - st.base_uptime;
-                st.base_uptime = uptime;
-                st.rel_utime = (int)(utime - st.base_utime);
-                st.rel_stime = (int)(stime - st.base_stime);
-                st.base_utime = utime;
-                st.base_stime = stime;
-                st.rel_minfaults = (int)(minfaults - st.base_minfaults);
-                st.rel_majfaults = (int)(majfaults - st.base_majfaults);
-                st.base_minfaults = minfaults;
-                st.base_majfaults = majfaults;
-                st.working = true;
                 continue;
             }
             
@@ -421,12 +434,24 @@
                 if (Process.readProcFile(st.statFile.toString(),
                         PROCESS_FULL_STATS_FORMAT, procStatsString,
                         procStats, null)) {
-                    st.baseName = procStatsString[0];
-                    st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
-                    st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
-                    st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
-                    st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
+                    // This is a possible way to filter out processes that
+                    // are actually kernel threads...  do we want to?  Some
+                    // of them do use CPU, but there can be a *lot* that are
+                    // not doing anything.
+                    if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
+                        st.interesting = true;
+                        st.baseName = procStatsString[0];
+                        st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
+                        st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
+                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
+                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
+                    } else {
+                        Slog.i(TAG, "Skipping kernel process pid " + pid
+                                + " name " + procStatsString[0]);
+                        st.baseName = procStatsString[0];
+                    }
                 } else {
+                    Slog.w(TAG, "Skipping unknown process pid " + pid);
                     st.baseName = "<unknown>";
                     st.base_utime = st.base_stime = 0;
                     st.base_minfaults = st.base_majfaults = 0;
@@ -438,7 +463,7 @@
                         mCurThreadPids = collectStats(st.threadsDir, pid, true,
                                 mCurThreadPids, st.threadStats);
                     }
-                } else {
+                } else if (st.interesting) {
                     st.name = st.baseName;
                     st.nameWidth = onMeasureProcessName(st.name);
                 }
@@ -452,7 +477,7 @@
                 st.rel_minfaults = 0;
                 st.rel_majfaults = 0;
                 st.added = true;
-                if (!first) {
+                if (!first && st.interesting) {
                     st.working = true;
                 }
                 continue;
@@ -624,6 +649,14 @@
         }
     }
 
+    final public int countStats() {
+        return mProcStats.size();
+    }
+
+    final public Stats getStats(int index) {
+        return mProcStats.get(index);
+    }
+
     final public int countWorkingStats() {
         buildWorkingProcs();
         return mWorkingProcs.size();
@@ -788,7 +821,8 @@
 
     private void getName(Stats st, String cmdlineFile) {
         String newName = st.name;
-        if (st.name == null || st.name.equals("app_process")) {
+        if (st.name == null || st.name.equals("app_process")
+                || st.name.equals("<pre-initialized>")) {
             String cmdName = readFile(cmdlineFile, '\0');
             if (cmdName != null && cmdName.length() > 1) {
                 newName = cmdName;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6b5b3bd..8e22652 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -122,6 +122,8 @@
 import java.lang.IllegalStateException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -145,6 +147,7 @@
     static final boolean DEBUG_BROADCAST = localLOGV || false;
     static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
     static final boolean DEBUG_SERVICE = localLOGV || false;
+    static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
     static final boolean DEBUG_VISBILITY = localLOGV || false;
     static final boolean DEBUG_PROCESSES = localLOGV || false;
     static final boolean DEBUG_PROVIDER = localLOGV || false;
@@ -153,6 +156,8 @@
     static final boolean DEBUG_RESULTS = localLOGV || false;
     static final boolean DEBUG_BACKUP = localLOGV || false;
     static final boolean DEBUG_CONFIGURATION = localLOGV || false;
+    static final boolean DEBUG_POWER = localLOGV || false;
+    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
     
@@ -198,8 +203,16 @@
     // The minimum amount of time between successive GC requests for a process.
     static final int GC_MIN_INTERVAL = 60*1000;
 
-    // The rate at which we check for apps using excessive wake locks -- 15 mins.
-    static final int WAKE_LOCK_CHECK_DELAY = 15*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;
+
+    // The minimum sample duration we will allow before deciding we have
+    // enough data on wake locks to start killing things.
+    static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
+
+    // The minimum sample duration we will allow before deciding we have
+    // enough data on CPU usage to start killing things.
+    static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
 
     // How long we allow a receiver to run before giving up on it.
     static final int BROADCAST_TIMEOUT = 10*1000;
@@ -780,9 +793,14 @@
     boolean mDidAppSwitch;
     
     /**
-     * Last time (in realtime) at which we checked for wake lock usage.
+     * Last time (in realtime) at which we checked for power usage.
      */
-    long mLastWakeLockCheckTime;
+    long mLastPowerCheckRealtime;
+
+    /**
+     * Last time (in uptime) at which we checked for power usage.
+     */
+    long mLastPowerCheckUptime;
 
     /**
      * Set while we are wanting to sleep, to prevent any
@@ -1195,12 +1213,10 @@
             } break;
             case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    checkExcessiveWakeLocksLocked(true);
+                    checkExcessivePowerUsageLocked(true);
                     removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                    if (mSleeping) {
-                        Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                        sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
-                    }
+                    Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
+                    sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
                 }
             } break;
             }
@@ -1395,7 +1411,8 @@
                 systemDir, "batterystats.bin").toString());
         mBatteryStatsService.getActiveStatistics().readLocked();
         mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
-        mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery();
+        mOnBattery = DEBUG_POWER ? true
+                : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
         mBatteryStatsService.getActiveStatistics().setCallback(this);
         
         mUsageStatsService = new UsageStatsService(new File(
@@ -1515,10 +1532,12 @@
                             int perc = bstats.startAddingCpuLocked();
                             int totalUTime = 0;
                             int totalSTime = 0;
-                            final int N = mProcessStats.countWorkingStats();
+                            final int N = mProcessStats.countStats();
                             for (int i=0; i<N; i++) {
-                                ProcessStats.Stats st
-                                        = mProcessStats.getWorkingStats(i);
+                                ProcessStats.Stats st = mProcessStats.getStats(i);
+                                if (!st.working) {
+                                    continue;
+                                }
                                 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
                                 int otherUTime = (st.rel_utime*perc)/100;
                                 int otherSTime = (st.rel_stime*perc)/100;
@@ -1529,6 +1548,7 @@
                                     ps.addCpuTimeLocked(st.rel_utime-otherUTime,
                                             st.rel_stime-otherSTime);
                                     ps.addSpeedStepTimes(cpuSpeedTimes);
+                                    pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps =
                                             bstats.getProcessStatsLocked(st.name, st.pid);
@@ -1565,7 +1585,7 @@
         updateCpuStatsNow();
         synchronized (this) {
             synchronized(mPidsSelfLocked) {
-                mOnBattery = onBattery;
+                mOnBattery = DEBUG_POWER ? true : onBattery;
             }
         }
     }
@@ -2795,6 +2815,16 @@
         ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
         SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
 
+        if (mController != null) {
+            try {
+                // 0 == continue, -1 = kill process immediately
+                int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation);
+                if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
+            } catch (RemoteException e) {
+                mController = null;
+            }
+        }
+
         long anrTime = SystemClock.uptimeMillis();
         if (MONITOR_CPU_USAGE) {
             updateCpuStatsNow();
@@ -2845,10 +2875,6 @@
             }
         }
 
-        final ProcessStats processStats = new ProcessStats(true);
-
-        File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids);
-
         // Log the ANR to the main log.
         StringBuilder info = mStringBuilder;
         info.setLength(0);
@@ -2864,6 +2890,10 @@
             info.append("Parent: ").append(parent.shortComponentName).append("\n");
         }
 
+        final ProcessStats processStats = new ProcessStats(true);
+
+        File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids);
+
         String cpuInfo = null;
         if (MONITOR_CPU_USAGE) {
             updateCpuStatsNow();
@@ -3742,7 +3772,7 @@
             if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
                 // Start looking for apps that are abusing wake locks.
                 Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
+                mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
                 broadcastIntentLocked(null, null,
@@ -5655,10 +5685,10 @@
             }
 
             // Initialize the wake times of all processes.
-            checkExcessiveWakeLocksLocked(false);
+            checkExcessivePowerUsageLocked(false);
             mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
             Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-            mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY);
+            mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
         }
     }
 
@@ -5708,7 +5738,6 @@
             mWindowManager.setEventDispatching(true);
             mSleeping = false;
             mMainStack.resumeTopActivityLocked(null);
-            mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
         }
     }
 
@@ -7055,12 +7084,13 @@
                 pw.println("Activity manager dump options:");
                 pw.println("  [-a] [-h] [cmd] ...");
                 pw.println("  cmd may be one of:");
-                pw.println("    activities: activity stack state");
-                pw.println("    broadcasts: broadcast state");
-                pw.println("    intents: pending intent state");
-                pw.println("    processes: process state");
-                pw.println("    providers: content provider state");
-                pw.println("    services: service state");
+                pw.println("    a[ctivities]: activity stack state");
+                pw.println("    b[roadcasts]: broadcast state");
+                pw.println("    i[ntents]: pending intent state");
+                pw.println("    p[rocesses]: process state");
+                pw.println("    o[om]: out of memory management");
+                pw.println("    prov[iders]: content provider state");
+                pw.println("    s[ervices]: service state");
                 pw.println("    service [name]: service client-side state");
                 return;
             } else {
@@ -7092,6 +7122,11 @@
                     dumpProcessesLocked(fd, pw, args, opti, true);
                 }
                 return;
+            } else if ("oom".equals(cmd) || "o".equals(cmd)) {
+                synchronized (this) {
+                    dumpOomLocked(fd, pw, args, opti, true);
+                }
+                return;
             } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
                 synchronized (this) {
                     dumpProvidersLocked(fd, pw, args, opti, true);
@@ -7213,7 +7248,7 @@
         
         return true;
     }
-        
+
     boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll) {
         boolean needSep = false;
@@ -7243,8 +7278,8 @@
             if (needSep) pw.println(" ");
             needSep = true;
             pw.println("  Running processes (most recent first):");
-            dumpProcessList(pw, this, mLruProcesses, "    ",
-                    "Proc", "PERS", true);
+            dumpProcessOomList(pw, this, mLruProcesses, "    ",
+                    "Proc", "PERS", false);
             needSep = true;
         }
 
@@ -7275,7 +7310,7 @@
             needSep = true;
             pw.println("  Persisent processes that are starting:");
             dumpProcessList(pw, this, mPersistentStartingProcesses, "    ",
-                    "Starting Norm", "Restarting PERS", false);
+                    "Starting Norm", "Restarting PERS");
         }
 
         if (mStartingProcesses.size() > 0) {
@@ -7283,7 +7318,7 @@
             needSep = true;
             pw.println("  Processes that are starting:");
             dumpProcessList(pw, this, mStartingProcesses, "    ",
-                    "Starting Norm", "Starting PERS", false);
+                    "Starting Norm", "Starting PERS");
         }
 
         if (mRemovedProcesses.size() > 0) {
@@ -7291,7 +7326,7 @@
             needSep = true;
             pw.println("  Processes that are being removed:");
             dumpProcessList(pw, this, mRemovedProcesses, "    ",
-                    "Removed Norm", "Removed PERS", false);
+                    "Removed Norm", "Removed PERS");
         }
         
         if (mProcessesOnHold.size() > 0) {
@@ -7299,26 +7334,10 @@
             needSep = true;
             pw.println("  Processes that are on old until the system is ready:");
             dumpProcessList(pw, this, mProcessesOnHold, "    ",
-                    "OnHold Norm", "OnHold PERS", false);
+                    "OnHold Norm", "OnHold PERS");
         }
 
-        if (mProcessesToGc.size() > 0) {
-            if (needSep) pw.println(" ");
-            needSep = true;
-            pw.println("  Processes that are waiting to GC:");
-            long now = SystemClock.uptimeMillis();
-            for (int i=0; i<mProcessesToGc.size(); i++) {
-                ProcessRecord proc = mProcessesToGc.get(i);
-                pw.print("    Process "); pw.println(proc);
-                pw.print("      lowMem="); pw.print(proc.reportLowMemory);
-                        pw.print(", last gced=");
-                        pw.print(now-proc.lastRequestedGc);
-                        pw.print(" ms ago, last lowMem=");
-                        pw.print(now-proc.lastLowMemory);
-                        pw.println(" ms ago");
-                
-            }
-        }
+        needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll);
         
         if (mProcessCrashTimes.getMap().size() > 0) {
             if (needSep) pw.println(" ");
@@ -7382,6 +7401,12 @@
             pw.println("  mBooting=" + mBooting
                     + " mBooted=" + mBooted
                     + " mFactoryTest=" + mFactoryTest);
+            pw.print("  mLastPowerCheckRealtime=");
+                    TimeUtils.formatDuration(mLastPowerCheckRealtime, pw);
+                    pw.println("");
+            pw.print("  mLastPowerCheckUptime=");
+                    TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
+                    pw.println("");
             pw.println("  mGoingToSleep=" + mMainStack.mGoingToSleep);
             pw.println("  mLaunchingActivity=" + mMainStack.mLaunchingActivity);
             pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
@@ -7390,6 +7415,75 @@
         return true;
     }
 
+    boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args,
+            int opti, boolean needSep, boolean dumpAll) {
+        if (mProcessesToGc.size() > 0) {
+            if (needSep) pw.println(" ");
+            needSep = true;
+            pw.println("  Processes that are waiting to GC:");
+            long now = SystemClock.uptimeMillis();
+            for (int i=0; i<mProcessesToGc.size(); i++) {
+                ProcessRecord proc = mProcessesToGc.get(i);
+                pw.print("    Process "); pw.println(proc);
+                pw.print("      lowMem="); pw.print(proc.reportLowMemory);
+                        pw.print(", last gced=");
+                        pw.print(now-proc.lastRequestedGc);
+                        pw.print(" ms ago, last lowMem=");
+                        pw.print(now-proc.lastLowMemory);
+                        pw.println(" ms ago");
+
+            }
+        }
+        return needSep;
+    }
+
+    boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+            int opti, boolean dumpAll) {
+        boolean needSep = false;
+
+        if (mLruProcesses.size() > 0) {
+            ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mLruProcesses);
+
+            Comparator<ProcessRecord> comparator = new Comparator<ProcessRecord>() {
+                @Override
+                public int compare(ProcessRecord object1, ProcessRecord object2) {
+                    if (object1.setAdj != object2.setAdj) {
+                        return object1.setAdj > object2.setAdj ? -1 : 1;
+                    }
+                    if (object1.setSchedGroup != object2.setSchedGroup) {
+                        return object1.setSchedGroup > object2.setSchedGroup ? -1 : 1;
+                    }
+                    if (object1.keeping != object2.keeping) {
+                        return object1.keeping ? -1 : 1;
+                    }
+                    if (object1.pid != object2.pid) {
+                        return object1.pid > object2.pid ? -1 : 1;
+                    }
+                    return 0;
+                }
+            };
+
+            Collections.sort(procs, comparator);
+
+            if (needSep) pw.println(" ");
+            needSep = true;
+            pw.println("  Process OOM control:");
+            dumpProcessOomList(pw, this, procs, "    ",
+                    "Proc", "PERS", true);
+            needSep = true;
+        }
+
+        needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll);
+
+        pw.println(" ");
+        pw.println("  mHomeProcess: " + mHomeProcess);
+        if (mHeavyWeightProcess != null) {
+            pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
+        }
+
+        return true;
+    }
+
     /**
      * There are three ways to call this:
      *  - no service specified: dump all the services
@@ -7833,84 +7927,14 @@
     
     private static final int dumpProcessList(PrintWriter pw,
             ActivityManagerService service, List list,
-            String prefix, String normalLabel, String persistentLabel,
-            boolean inclOomAdj) {
+            String prefix, String normalLabel, String persistentLabel) {
         int numPers = 0;
         final int N = list.size()-1;
         for (int i=N; i>=0; i--) {
             ProcessRecord r = (ProcessRecord)list.get(i);
-            if (false) {
-                pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
-                      + " #" + i + ":");
-                r.dump(pw, prefix + "  ");
-            } else if (inclOomAdj) {
-                String oomAdj;
-                if (r.setAdj >= EMPTY_APP_ADJ) {
-                    oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
-                } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
-                    oomAdj = buildOomTag("bak", "  ", r.setAdj, HIDDEN_APP_MIN_ADJ);
-                } else if (r.setAdj >= HOME_APP_ADJ) {
-                    oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
-                } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
-                    oomAdj = buildOomTag("svc", "  ", r.setAdj, SECONDARY_SERVER_ADJ);
-                } else if (r.setAdj >= BACKUP_APP_ADJ) {
-                    oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
-                } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) {
-                    oomAdj = buildOomTag("hvy  ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ);
-                } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) {
-                    oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ);
-                } else if (r.setAdj >= VISIBLE_APP_ADJ) {
-                    oomAdj = buildOomTag("vis  ", null, r.setAdj, VISIBLE_APP_ADJ);
-                } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
-                    oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
-                } else if (r.setAdj >= CORE_SERVER_ADJ) {
-                    oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
-                } else if (r.setAdj >= SYSTEM_ADJ) {
-                    oomAdj = buildOomTag("sys  ", null, r.setAdj, SYSTEM_ADJ);
-                } else {
-                    oomAdj = Integer.toString(r.setAdj);
-                }
-                String schedGroup;
-                switch (r.setSchedGroup) {
-                    case Process.THREAD_GROUP_BG_NONINTERACTIVE:
-                        schedGroup = "B";
-                        break;
-                    case Process.THREAD_GROUP_DEFAULT:
-                        schedGroup = "F";
-                        break;
-                    default:
-                        schedGroup = Integer.toString(r.setSchedGroup);
-                        break;
-                }
-                pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
-                        prefix, (r.persistent ? persistentLabel : normalLabel),
-                        N-i, oomAdj, schedGroup, r.toShortString(), r.adjType));
-                if (r.adjSource != null || r.adjTarget != null) {
-                    pw.print(prefix);
-                    pw.print("          ");
-                    if (r.adjTarget instanceof ComponentName) {
-                        pw.print(((ComponentName)r.adjTarget).flattenToShortString());
-                    } else if (r.adjTarget != null) {
-                        pw.print(r.adjTarget.toString());
-                    } else {
-                        pw.print("{null}");
-                    }
-                    pw.print("<=");
-                    if (r.adjSource instanceof ProcessRecord) {
-                        pw.print("Proc{");
-                        pw.print(((ProcessRecord)r.adjSource).toShortString());
-                        pw.println("}");
-                    } else if (r.adjSource != null) {
-                        pw.println(r.adjSource.toString());
-                    } else {
-                        pw.println("{null}");
-                    }
-                }
-            } else {
-                pw.println(String.format("%s%s #%2d: %s",
-                        prefix, (r.persistent ? persistentLabel : normalLabel),
-                        i, r.toString()));
-            }
+            pw.println(String.format("%s%s #%2d: %s",
+                    prefix, (r.persistent ? persistentLabel : normalLabel),
+                    i, r.toString()));
             if (r.persistent) {
                 numPers++;
             }
@@ -7918,6 +7942,132 @@
         return numPers;
     }
 
+    private static final void dumpProcessOomList(PrintWriter pw,
+            ActivityManagerService service, List<ProcessRecord> list,
+            String prefix, String normalLabel, String persistentLabel,
+            boolean inclDetails) {
+
+        final long curRealtime = SystemClock.elapsedRealtime();
+        final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime;
+        final long curUptime = SystemClock.uptimeMillis();
+        final long uptimeSince = curUptime - service.mLastPowerCheckUptime;
+
+        final int N = list.size()-1;
+        for (int i=N; i>=0; i--) {
+            ProcessRecord r = list.get(i);
+            String oomAdj;
+            if (r.setAdj >= EMPTY_APP_ADJ) {
+                oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
+            } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
+                oomAdj = buildOomTag("bak", "  ", r.setAdj, HIDDEN_APP_MIN_ADJ);
+            } else if (r.setAdj >= HOME_APP_ADJ) {
+                oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
+            } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
+                oomAdj = buildOomTag("svc", "  ", r.setAdj, SECONDARY_SERVER_ADJ);
+            } else if (r.setAdj >= BACKUP_APP_ADJ) {
+                oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
+            } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) {
+                oomAdj = buildOomTag("hvy  ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ);
+            } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) {
+                oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ);
+            } else if (r.setAdj >= VISIBLE_APP_ADJ) {
+                oomAdj = buildOomTag("vis  ", null, r.setAdj, VISIBLE_APP_ADJ);
+            } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
+                oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
+            } else if (r.setAdj >= CORE_SERVER_ADJ) {
+                oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
+            } else if (r.setAdj >= SYSTEM_ADJ) {
+                oomAdj = buildOomTag("sys  ", null, r.setAdj, SYSTEM_ADJ);
+            } else {
+                oomAdj = Integer.toString(r.setAdj);
+            }
+            String schedGroup;
+            switch (r.setSchedGroup) {
+                case Process.THREAD_GROUP_BG_NONINTERACTIVE:
+                    schedGroup = "B";
+                    break;
+                case Process.THREAD_GROUP_DEFAULT:
+                    schedGroup = "F";
+                    break;
+                default:
+                    schedGroup = Integer.toString(r.setSchedGroup);
+                    break;
+            }
+            pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
+                    prefix, (r.persistent ? persistentLabel : normalLabel),
+                    N-i, oomAdj, schedGroup, r.toShortString(), r.adjType));
+            if (r.adjSource != null || r.adjTarget != null) {
+                pw.print(prefix);
+                pw.print("          ");
+                if (r.adjTarget instanceof ComponentName) {
+                    pw.print(((ComponentName)r.adjTarget).flattenToShortString());
+                } else if (r.adjTarget != null) {
+                    pw.print(r.adjTarget.toString());
+                } else {
+                    pw.print("{null}");
+                }
+                pw.print("<=");
+                if (r.adjSource instanceof ProcessRecord) {
+                    pw.print("Proc{");
+                    pw.print(((ProcessRecord)r.adjSource).toShortString());
+                    pw.println("}");
+                } else if (r.adjSource != null) {
+                    pw.println(r.adjSource.toString());
+                } else {
+                    pw.println("{null}");
+                }
+            }
+            if (inclDetails) {
+                pw.print(prefix);
+                pw.print("    ");
+                pw.print("oom: max="); pw.print(r.maxAdj);
+                pw.print(" hidden="); pw.print(r.hiddenAdj);
+                pw.print(" curRaw="); pw.print(r.curRawAdj);
+                pw.print(" setRaw="); pw.print(r.setRawAdj);
+                pw.print(" cur="); pw.print(r.curAdj);
+                pw.print(" set="); pw.println(r.setAdj);
+                pw.print(prefix);
+                pw.print("    ");
+                pw.print("keeping="); pw.print(r.keeping);
+                pw.print(" hidden="); pw.print(r.hidden);
+                pw.print(" empty="); pw.println(r.empty);
+
+                if (!r.keeping) {
+                    if (r.lastWakeTime != 0) {
+                        long wtime;
+                        BatteryStatsImpl stats = service.mBatteryStatsService.getActiveStatistics();
+                        synchronized (stats) {
+                            wtime = stats.getProcessWakeTime(r.info.uid,
+                                    r.pid, curRealtime);
+                        }
+                        long timeUsed = wtime - r.lastWakeTime;
+                        pw.print(prefix);
+                        pw.print("    ");
+                        pw.print("keep awake over ");
+                        TimeUtils.formatDuration(realtimeSince, pw);
+                        pw.print(" used ");
+                        TimeUtils.formatDuration(timeUsed, pw);
+                        pw.print(" (");
+                        pw.print((timeUsed*100)/realtimeSince);
+                        pw.println("%)");
+                    }
+                    if (r.lastCpuTime != 0) {
+                        long timeUsed = r.curCpuTime - r.lastCpuTime;
+                        pw.print(prefix);
+                        pw.print("    ");
+                        pw.print("run cpu over ");
+                        TimeUtils.formatDuration(uptimeSince, pw);
+                        pw.print(" used ");
+                        TimeUtils.formatDuration(timeUsed, pw);
+                        pw.print(" (");
+                        pw.print((timeUsed*100)/uptimeSince);
+                        pw.println("%)");
+                    }
+                }
+            }
+        }
+    }
+
     static final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, List list, String prefix, String[] args) {
         final boolean isCheckinRequest = scanArgs(args, "--checkin");
@@ -8544,7 +8694,11 @@
         return null;
     }
 
-    private final void bumpServiceExecutingLocked(ServiceRecord r) {
+    private final void bumpServiceExecutingLocked(ServiceRecord r, String why) {
+        if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING "
+                + why + " of " + r + " in app " + r.app);
+        else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING "
+                + why + " of " + r.shortName);
         long now = SystemClock.uptimeMillis();
         if (r.executeNesting == 0 && r.app != null) {
             if (r.app.executingServices.size() == 0) {
@@ -8582,8 +8736,7 @@
                     grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
                             r.packageName, si.intent, si.getUriPermissionsLocked());
                 }
-                if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r);
-                bumpServiceExecutingLocked(r);
+                bumpServiceExecutingLocked(r, "start");
                 if (!oomAdjusted) {
                     oomAdjusted = true;
                     updateOomAdjLocked(r.app);
@@ -8616,9 +8769,7 @@
         }
         if ((!i.requested || rebind) && i.apps.size() > 0) {
             try {
-                if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bind of " + r
-                        + " in " + i + ": shouldUnbind=" + i.hasBound);
-                bumpServiceExecutingLocked(r);
+                bumpServiceExecutingLocked(r, "bind");
                 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
                 if (!rebind) {
                     i.requested = true;
@@ -8653,8 +8804,7 @@
         r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
 
         app.services.add(r);
-        if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING create of " + r + " " + r.intent);
-        bumpServiceExecutingLocked(r);
+        bumpServiceExecutingLocked(r, "create");
         updateLruProcessLocked(app, true, true);
 
         boolean created = false;
@@ -8906,9 +9056,7 @@
                         + ": hasBound=" + ibr.hasBound);
                 if (r.app != null && r.app.thread != null && ibr.hasBound) {
                     try {
-                        if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bring down unbind of " + r
-                                + " for " + ibr);
-                        bumpServiceExecutingLocked(r);
+                        bumpServiceExecutingLocked(r, "bring down unbind");
                         updateOomAdjLocked(r.app);
                         ibr.hasBound = false;
                         r.app.thread.scheduleUnbindService(r,
@@ -8959,12 +9107,7 @@
             r.app.services.remove(r);
             if (r.app.thread != null) {
                 try {
-                    if (DEBUG_SERVICE) {
-                        RuntimeException here = new RuntimeException();
-                        here.fillInStackTrace();
-                        Slog.v(TAG, ">>> EXECUTING stop of " + r, here);
-                    }
-                    bumpServiceExecutingLocked(r);
+                    bumpServiceExecutingLocked(r, "stop");
                     mStoppingServices.add(r);
                     updateOomAdjLocked(r.app);
                     r.app.thread.scheduleStopService(r);
@@ -9420,9 +9563,7 @@
         if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                 && b.intent.hasBound) {
             try {
-                if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING unbind of " + s
-                        + " from " + b);
-                bumpServiceExecutingLocked(s);
+                bumpServiceExecutingLocked(s, "unbind");
                 updateOomAdjLocked(s.app);
                 b.intent.hasBound = false;
                 // Assume the client doesn't want to know about a rebind;
@@ -9643,14 +9784,20 @@
         if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
                 + ": nesting=" + r.executeNesting
                 + ", inStopping=" + inStopping + ", app=" + r.app);
+        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
         r.executeNesting--;
         if (r.executeNesting <= 0 && r.app != null) {
+            if (DEBUG_SERVICE) Slog.v(TAG,
+                    "Nesting at 0 of " + r.shortName);
             r.app.executingServices.remove(r);
             if (r.app.executingServices.size() == 0) {
+                if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
+                        "No more executingServices of " + r.shortName);
                 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
             }
             if (inStopping) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "doneExecuting remove stopping " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG,
+                        "doneExecuting remove stopping " + r);
                 mStoppingServices.remove(r);
             }
             updateOomAdjLocked(r.app);
@@ -11326,6 +11473,7 @@
             app.adjType = "fixed";
             app.adjSeq = mAdjSeq;
             app.curRawAdj = app.maxAdj;
+            app.keeping = true;
             app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
             return (app.curAdj=app.maxAdj);
        }
@@ -11333,6 +11481,7 @@
         app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
         app.adjSource = null;
         app.adjTarget = null;
+        app.keeping = false;
         app.empty = false;
         app.hidden = false;
 
@@ -11462,6 +11611,9 @@
                     if (adj > SECONDARY_SERVER_ADJ) {
                         app.adjType = "started-bg-services";
                     }
+                    // Don't kill this process because it is doing work; it
+                    // has said it is doing work.
+                    app.keeping = true;
                 }
                 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
                         || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
@@ -11495,6 +11647,9 @@
                                     if (!client.hidden) {
                                         app.hidden = false;
                                     }
+                                    if (client.keeping) {
+                                        app.keeping = true;
+                                    }
                                     app.adjType = "service";
                                     app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                             .REASON_SERVICE_IN_USE;
@@ -11528,7 +11683,7 @@
                 }
             }
             
-            // Finally, f this process has active services running in it, we
+            // Finally, if this process has active services running in it, we
             // would like to avoid killing it unless it would prevent the current
             // application from running.  By default we put the process in
             // with the rest of the background processes; as we scan through
@@ -11570,6 +11725,9 @@
                             if (!client.hidden) {
                                 app.hidden = false;
                             }
+                            if (client.keeping) {
+                                app.keeping = true;
+                            }
                             app.adjType = "provider";
                             app.adjTypeCode = ActivityManager.RunningAppProcessInfo
                                     .REASON_PROVIDER_IN_USE;
@@ -11589,6 +11747,7 @@
                         adj = FOREGROUND_APP_ADJ;
                         schedGroup = Process.THREAD_GROUP_DEFAULT;
                         app.hidden = false;
+                        app.keeping = true;
                         app.adjType = "provider";
                         app.adjTarget = cpr.name;
                     }
@@ -11606,6 +11765,9 @@
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             }
         }
+        if (adj < HIDDEN_APP_MIN_ADJ) {
+            app.keeping = true;
+        }
 
         app.curAdj = adj;
         app.curSchedGroup = schedGroup;
@@ -11743,57 +11905,99 @@
         }
     }
 
-    final void checkExcessiveWakeLocksLocked(boolean doKills) {
+    final void checkExcessivePowerUsageLocked(boolean doKills) {
+        updateCpuStatsNow();
+
         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-        if (mLastWakeLockCheckTime == 0) {
-            doKills = false;
+        boolean doWakeKills = doKills;
+        boolean doCpuKills = doKills;
+        if (mLastPowerCheckRealtime == 0) {
+            doWakeKills = false;
+        }
+        if (mLastPowerCheckUptime == 0) {
+            doCpuKills = false;
         }
         if (stats.isScreenOn()) {
-            doKills = false;
+            doWakeKills = false;
         }
         final long curRealtime = SystemClock.elapsedRealtime();
-        final long timeSince = curRealtime - mLastWakeLockCheckTime;
-        mLastWakeLockCheckTime = curRealtime;
-        if (timeSince < (WAKE_LOCK_CHECK_DELAY/3)) {
-            doKills = false;
+        final long realtimeSince = curRealtime - mLastPowerCheckRealtime;
+        final long curUptime = SystemClock.uptimeMillis();
+        final long uptimeSince = curUptime - mLastPowerCheckUptime;
+        mLastPowerCheckRealtime = curRealtime;
+        mLastPowerCheckUptime = curUptime;
+        if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) {
+            doWakeKills = false;
+        }
+        if (uptimeSince < CPU_MIN_CHECK_DURATION) {
+            doCpuKills = false;
         }
         int i = mLruProcesses.size();
         while (i > 0) {
             i--;
             ProcessRecord app = mLruProcesses.get(i);
-            if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+            if (!app.keeping) {
                 long wtime;
                 synchronized (stats) {
                     wtime = stats.getProcessWakeTime(app.info.uid,
                             app.pid, curRealtime);
                 }
-                long timeUsed = wtime - app.lastWakeTime;
-                if (false) {
+                long wtimeUsed = wtime - app.lastWakeTime;
+                long cputimeUsed = app.curCpuTime - app.lastCpuTime;
+                if (DEBUG_POWER) {
                     StringBuilder sb = new StringBuilder(128);
                     sb.append("Wake for ");
                     app.toShortString(sb);
                     sb.append(": over ");
-                    TimeUtils.formatDuration(timeSince, sb);
+                    TimeUtils.formatDuration(realtimeSince, sb);
                     sb.append(" used ");
-                    TimeUtils.formatDuration(timeUsed, sb);
+                    TimeUtils.formatDuration(wtimeUsed, sb);
                     sb.append(" (");
-                    sb.append((timeUsed*100)/timeSince);
+                    sb.append((wtimeUsed*100)/realtimeSince);
+                    sb.append("%)");
+                    Slog.i(TAG, sb.toString());
+                    sb.setLength(0);
+                    sb.append("CPU for ");
+                    app.toShortString(sb);
+                    sb.append(": over ");
+                    TimeUtils.formatDuration(uptimeSince, sb);
+                    sb.append(" used ");
+                    TimeUtils.formatDuration(cputimeUsed, sb);
+                    sb.append(" (");
+                    sb.append((cputimeUsed*100)/uptimeSince);
                     sb.append("%)");
                     Slog.i(TAG, sb.toString());
                 }
                 // If a process has held a wake lock for more
                 // than 50% of the time during this period,
                 // that sounds pad.  Kill!
-                if (doKills && timeSince > 0
-                        && ((timeUsed*100)/timeSince) >= 50) {
-                    Slog.i(TAG, "Excessive wake lock in " + app.processName
-                            + " (pid " + app.pid + "): held " + timeUsed
-                            + " during " + timeSince);
+                if (doWakeKills && realtimeSince > 0
+                        && ((wtimeUsed*100)/realtimeSince) >= 50) {
+                    synchronized (stats) {
+                        stats.reportExcessiveWakeLocked(app.info.uid, app.processName,
+                                realtimeSince, wtimeUsed);
+                    }
+                    Slog.w(TAG, "Excessive wake lock in " + app.processName
+                            + " (pid " + app.pid + "): held " + wtimeUsed
+                            + " during " + realtimeSince);
                     EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                             app.processName, app.setAdj, "excessive wake lock");
                     Process.killProcessQuiet(app.pid);
+                } else if (doCpuKills && uptimeSince > 0
+                        && ((cputimeUsed*100)/uptimeSince) >= 50) {
+                    synchronized (stats) {
+                        stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
+                                uptimeSince, cputimeUsed);
+                    }
+                    Slog.w(TAG, "Excessive CPU in " + app.processName
+                            + " (pid " + app.pid + "): used " + cputimeUsed
+                            + " during " + uptimeSince);
+                    EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                            app.processName, app.setAdj, "excessive cpu");
+                    Process.killProcessQuiet(app.pid);
                 } else {
                     app.lastWakeTime = wtime;
+                    app.lastCpuTime = app.curCpuTime;
                 }
             }
         }
@@ -11807,6 +12011,8 @@
             return true;
         }
 
+        final boolean wasKeeping = app.keeping;
+
         int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
 
         if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
@@ -11821,13 +12027,20 @@
                     // Likewise do a gc when an app is moving in to the
                     // background (such as a service stopping).
                     scheduleAppGcLocked(app);
-                    // And note its current wake lock time.
+                }
+
+                if (wasKeeping && !app.keeping) {
+                    // This app is no longer something we want to keep.  Note
+                    // its current wake lock time to later know to kill it if
+                    // it is not behaving well.
                     BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
                     synchronized (stats) {
                         app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
                                 app.pid, SystemClock.elapsedRealtime());
                     }
+                    app.lastCpuTime = app.curCpuTime;
                 }
+
                 app.setRawAdj = app.curRawAdj;
             }
             if (adj != app.setAdj) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 67df707..404c6be 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -60,6 +60,7 @@
     int setAdj;                 // Last set OOM adjustment for this process
     int curSchedGroup;          // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
+    boolean keeping;            // Actively running code so don't kill due to that?
     boolean setIsForeground;    // Running foreground UI when last set?
     boolean foregroundServices; // Running any services that are foreground?
     boolean bad;                // True if disabled in the bad process list
@@ -75,6 +76,8 @@
     ComponentName instrumentationResultClass;// copy of instrumentationClass
     BroadcastRecord curReceiver;// receiver currently running in the app
     long lastWakeTime;          // How long proc held wake lock at last check
+    long lastCpuTime;           // How long proc has run CPU at last check
+    long curCpuTime;            // How long proc has run CPU most recently
     long lastRequestedGc;       // When we last asked the app to do a gc
     long lastLowMemory;         // When we last told the app that memory is low
     boolean reportLowMemory;    // Set to true when waiting to report low mem
@@ -131,13 +134,6 @@
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
 
-        long wtime;
-        synchronized (batteryStats.getBatteryStats()) {
-            wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid,
-                    pid, SystemClock.elapsedRealtime());
-        }
-        long timeUsed = wtime - lastWakeTime;
-
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
         }
@@ -170,6 +166,7 @@
         pw.print(prefix); pw.print("lastActivityTime=");
                 TimeUtils.formatDuration(lastActivityTime, now, pw);
                 pw.print(" lruWeight="); pw.print(lruWeight);
+                pw.print(" keeping="); pw.print(keeping);
                 pw.print(" hidden="); pw.print(hidden);
                 pw.print(" empty="); pw.println(empty);
         pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
@@ -188,9 +185,20 @@
                 pw.print(" persistentActivities="); pw.println(persistentActivities);
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                 pw.print(" lruSeq="); pw.println(lruSeq);
-        pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime);
-                pw.print(" time used=");
-                TimeUtils.formatDuration(timeUsed, pw); pw.println("");
+        if (!keeping) {
+            long wtime;
+            synchronized (batteryStats.getBatteryStats()) {
+                wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid,
+                        pid, SystemClock.elapsedRealtime());
+            }
+            long timeUsed = wtime - lastWakeTime;
+            pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime);
+                    pw.print(" time used=");
+                    TimeUtils.formatDuration(timeUsed, pw); pw.println("");
+            pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime);
+                    pw.print(" time used=");
+                    TimeUtils.formatDuration(curCpuTime-lastCpuTime, pw); pw.println("");
+        }
         pw.print(prefix); pw.print("lastRequestedGc=");
                 TimeUtils.formatDuration(lastRequestedGc, now, pw);
                 pw.print(" lastLowMemory=");
diff --git a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
index 48c4520..5fb09a7 100644
--- a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
+++ b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java
@@ -25,6 +25,7 @@
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.TextView;
 
@@ -38,7 +39,6 @@
     TextView mLog;
     DateFormat mDateFormat;
     IntentFilter mFilter;
-    PowerManager.WakeLock mWakeLock;
     PowerManager.WakeLock mPartialWakeLock;
     SpinThread mThread;
 
@@ -65,24 +65,26 @@
         mFilter.addAction(Intent.ACTION_POWER_CONNECTED);
 
         PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "BatteryWaster");
-        mWakeLock.setReferenceCounted(false);
         mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BatteryWaster");
         mPartialWakeLock.setReferenceCounted(false);
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
-        stopRunning();
+    public void onResume() {
+        super.onResume();
+        if (((CheckBox)findViewById(R.id.checkbox)).isChecked()) {
+            startRunning();
+        }
+        if (((CheckBox)findViewById(R.id.checkbox_wake)).isChecked()) {
+            mWaking = true;
+            updateWakeLock();
+        }
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
-        if (mWakeLock.isHeld()) {
-            mWakeLock.release();
-        }
+        stopRunning();
         if (mPartialWakeLock.isHeld()) {
             mPartialWakeLock.release();
         }
@@ -140,13 +142,9 @@
 
     void updateWakeLock() {
         if (mWasting) {
-            if (!mWakeLock.isHeld()) {
-                mWakeLock.acquire();
-            }
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         } else {
-            if (mWakeLock.isHeld()) {
-                mWakeLock.release();
-            }
+            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         }
         if (mWaking) {
             if (!mPartialWakeLock.isHeld()) {