Improve logging of first wake lock, history size.

We now try to have a better label for the first wake lock
that is acquired in the log.  This is done in two ways:

- The alarm manager now sorts the alarms it is going to
  execute so that wakeup alarms are first, which are more
  important w.r.t. which one should be logged.
- There is a new power manager facility to make a wake lock
  as "unimportant for logging," which just means in battery
  stats that a wake lock acquired after that can be considered
  the actual one to log.  This is only used by the alarm manager
  to mark its TIME_TICK alarms as unimportant for logging.

Also reworked the battery history code to be cleaner and a bit
smaller.  There is no longer a separate EVENT command, instead
the event code and tag are just another thing that can be included
in an UPDATE command.

The bits used in the first history int are also re-arrange, so
that only the ones that really change a fair amount in the state
bits are up at the top and there is no longer space used for
the command code (since now it is always just UPDATE).  This
allows us to have more room for the time delta at the bottom,
to better avoid situations where we need to write an int delta.

Change-Id: I1bb860ae5b558a248800b090b03a84fbf7acd68a
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 27c0f5d..4879be6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -507,10 +507,7 @@
         
         public long time;
 
-        // The command codes 0-3 can be written with delta updates; all others require
-        // that a full entry be written.
-        public static final byte CMD_UPDATE = 0;
-        public static final byte CMD_EVENT = 1;
+        public static final byte CMD_UPDATE = 0;        // These can be written as deltas
         public static final byte CMD_NULL = -1;
         public static final byte CMD_START = 4;
         public static final byte CMD_OVERFLOW = 5;
@@ -520,15 +517,8 @@
         /**
          * Return whether the command code is a delta data update.
          */
-        public static boolean isDeltaData(byte cmd) {
-            return cmd >= 0 && cmd <= 3;
-        }
-
-        /**
-         * Return whether the command code is a delta data update.
-         */
         public boolean isDeltaData() {
-            return cmd >= 0 && cmd <= 3;
+            return cmd == CMD_UPDATE;
         }
 
         public byte batteryLevel;
@@ -555,16 +545,16 @@
         // These states always appear directly in the first int token
         // of a delta change; they should be ones that change relatively
         // frequently.
-        public static final int STATE_WAKE_LOCK_FLAG = 1<<30;
-        public static final int STATE_SENSOR_ON_FLAG = 1<<29;
-        public static final int STATE_GPS_ON_FLAG = 1<<28;
-        public static final int STATE_PHONE_SCANNING_FLAG = 1<<27;
-        public static final int STATE_WIFI_RUNNING_FLAG = 1<<26;
-        public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<25;
-        public static final int STATE_WIFI_SCAN_FLAG = 1<<24;
-        public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<23;
+        public static final int STATE_WAKE_LOCK_FLAG = 1<<31;
+        public static final int STATE_SENSOR_ON_FLAG = 1<<30;
+        public static final int STATE_GPS_ON_FLAG = 1<<29;
+        public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
+        public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
+        public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
         // These are on the lower bits used for the command; if they change
         // we need to write another int of data.
+        public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
+        public static final int STATE_PHONE_SCANNING_FLAG = 1<<23;
         public static final int STATE_AUDIO_ON_FLAG = 1<<22;
         public static final int STATE_VIDEO_ON_FLAG = 1<<21;
         public static final int STATE_SCREEN_ON_FLAG = 1<<20;
@@ -628,7 +618,8 @@
             } else {
                 dest.writeInt(0);
             }
-            if (cmd == CMD_EVENT) {
+            dest.writeInt(eventCode);
+            if (eventCode != EVENT_NONE) {
                 dest.writeInt(eventCode);
                 eventTag.writeToParcel(dest, flags);
             }
@@ -652,13 +643,10 @@
             } else {
                 wakelockTag = null;
             }
-            if (cmd == CMD_EVENT) {
-                eventCode = src.readInt();
+            eventCode = src.readInt();
+            if (eventCode != EVENT_NONE) {
                 eventTag = localEventTag;
                 eventTag.readFromParcel(src);
-            } else {
-                eventCode = EVENT_NONE;
-                eventTag = null;
             }
             numReadInts += (src.dataPosition()-start)/4;
         }
@@ -681,6 +669,16 @@
         public void setTo(HistoryItem o) {
             time = o.time;
             cmd = o.cmd;
+            setToCommon(o);
+        }
+
+        public void setTo(long time, byte cmd, HistoryItem o) {
+            this.time = time;
+            this.cmd = cmd;
+            setToCommon(o);
+        }
+
+        private void setToCommon(HistoryItem o) {
             batteryLevel = o.batteryLevel;
             batteryStatus = o.batteryStatus;
             batteryHealth = o.batteryHealth;
@@ -703,32 +701,6 @@
             }
         }
 
-        public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
-                HistoryItem o) {
-            this.time = time;
-            this.cmd = cmd;
-            this.eventCode = eventCode;
-            if (eventCode != EVENT_NONE) {
-                eventTag = localEventTag;
-                eventTag.setTo(eventName, eventUid);
-            } else {
-                eventTag = null;
-            }
-            batteryLevel = o.batteryLevel;
-            batteryStatus = o.batteryStatus;
-            batteryHealth = o.batteryHealth;
-            batteryPlugType = o.batteryPlugType;
-            batteryTemperature = o.batteryTemperature;
-            batteryVoltage = o.batteryVoltage;
-            states = o.states;
-            if (o.wakelockTag != null) {
-                wakelockTag = localWakelockTag;
-                wakelockTag.setTo(o.wakelockTag);
-            } else {
-                wakelockTag = null;
-            }
-        }
-
         public boolean sameNonEvent(HistoryItem o) {
             return batteryLevel == o.batteryLevel
                     && batteryStatus == o.batteryStatus
@@ -938,36 +910,36 @@
     
     public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS
             = new BitDescription[] {
-        new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
-        new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
+        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
         new BitDescription(HistoryItem.STATE_GPS_ON_FLAG, "gps", "g"),
-        new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
-        new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
-        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
-        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
         new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"),
         new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
         new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
-        new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
+        new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
         new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
         new BitDescription(HistoryItem.STATE_VIDEO_ON_FLAG, "video", "v"),
-        new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
-        new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
-        new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
-                HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
-                SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
+        new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
+        new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
+        new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
+        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
+        new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
+        new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
+                HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
+                DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+        new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
+                HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
+                new String[] {"in", "out", "emergency", "off"},
+                new String[] {"in", "out", "em", "off"}),
         new BitDescription(HistoryItem.STATE_SIGNAL_STRENGTH_MASK,
                 HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT, "signal_strength", "Pss",
                 SignalStrength.SIGNAL_STRENGTH_NAMES, new String[] {
                     "0", "1", "2", "3", "4"
         }),
-        new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK,
-                HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
-                new String[] {"in", "out", "emergency", "off"},
-                new String[] {"in", "out", "em", "off"}),
-        new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
-                HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
-                DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
+        new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
+                HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
+                SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
     };
 
     /**
@@ -2464,7 +2436,8 @@
                     else if (rec.batteryLevel < 100) pw.print("0");
                     pw.print(rec.batteryLevel);
                     pw.print(" ");
-                    if (rec.states < 0x10) pw.print("0000000");
+                    if (rec.states < 0) ;
+                    else if (rec.states < 0x10) pw.print("0000000");
                     else if (rec.states < 0x100) pw.print("000000");
                     else if (rec.states < 0x1000) pw.print("00000");
                     else if (rec.states < 0x10000) pw.print("0000");
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3a9611e..0439eeb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -223,6 +223,13 @@
     public static final int ON_AFTER_RELEASE = 0x20000000;
 
     /**
+     * Wake lock flag: This wake lock is not important for logging events.  If a later
+     * wake lock is acquired that is important, it will be considered the one to log.
+     * @hide
+     */
+    public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000;
+
+    /**
      * Flag for {@link WakeLock#release release(int)} to defer releasing a
      * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor returns
      * a negative value.
@@ -634,8 +641,8 @@
      * </p>
      */
     public final class WakeLock {
-        private final int mFlags;
-        private final String mTag;
+        private int mFlags;
+        private String mTag;
         private final String mPackageName;
         private final IBinder mToken;
         private int mCount;
@@ -829,6 +836,17 @@
             }
         }
 
+        /** @hide */
+        public void setTag(String tag) {
+            mTag = tag;
+        }
+
+        /** @hide */
+        public void setUnimportantForLogging(boolean state) {
+            if (state) mFlags |= UNIMPORTANT_FOR_LOGGING;
+            else mFlags &= ~UNIMPORTANT_FOR_LOGGING;
+        }
+
         @Override
         public String toString() {
             synchronized (mToken) {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1946d86..9a04760 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -35,10 +35,11 @@
 
     void noteEvent(int code, String name, int uid);
 
-    void noteStartWakelock(int uid, int pid, String name, int type);
+    void noteStartWakelock(int uid, int pid, String name, int type, boolean unimportantForLogging);
     void noteStopWakelock(int uid, int pid, String name, int type);
 
-    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging);
     void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
 
     void noteVibratorOn(int uid, long durationMillis);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 68c41fa..21d2e52 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -77,7 +77,7 @@
  */
 public final class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
@@ -87,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 77 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -226,6 +226,9 @@
     long mRealtimeStart;
     long mLastRealtime;
 
+    int mWakeLockNesting;
+    boolean mWakeLockImportant;
+
     boolean mScreenOn;
     StopwatchTimer mScreenOnTimer;
 
@@ -1513,23 +1516,23 @@
     }
 
     // Part of initial delta int that specifies the time delta.
-    static final int DELTA_TIME_MASK = 0x1ffff;
-    static final int DELTA_TIME_LONG = 0x1ffff;   // The delta is a following long
-    static final int DELTA_TIME_INT = 0x1fffe;    // The delta is a following int
-    static final int DELTA_TIME_ABS = 0x1fffd;    // Following is an entire abs update.
-    // Part of initial delta int holding the command code.
-    static final int DELTA_CMD_MASK = 0x3;
-    static final int DELTA_CMD_SHIFT = 17;
+    static final int DELTA_TIME_MASK = 0xfffff;
+    static final int DELTA_TIME_LONG = 0xfffff;   // The delta is a following long
+    static final int DELTA_TIME_INT = 0xffffe;    // The delta is a following int
+    static final int DELTA_TIME_ABS = 0xffffd;    // Following is an entire abs update.
     // Flag in delta int: a new battery level int follows.
-    static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
+    static final int DELTA_BATTERY_LEVEL_FLAG   = 0x00400000;
     // Flag in delta int: a new full state and battery status int follows.
-    static final int DELTA_STATE_FLAG = 0x00100000;
+    static final int DELTA_STATE_FLAG           = 0x00800000;
     // Flag in delta int: contains a wakelock tag.
-    static final int DELTA_WAKELOCK_FLAG = 0x00200000;
-    static final int DELTA_STATE_MASK = 0xffc00000;
+    static final int DELTA_WAKELOCK_FLAG        = 0x01000000;
+    // Flag in delta int: contains an event description.
+    static final int DELTA_EVENT_FLAG           = 0x02000000;
+    // These upper bits are the frequently changing state bits.
+    static final int DELTA_STATE_MASK           = 0xfc000000;
 
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
-        if (last == null || !last.isDeltaData() || !cur.isDeltaData()) {
+        if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(DELTA_TIME_ABS);
             cur.writeToParcel(dest, 0);
             return;
@@ -1547,9 +1550,7 @@
         } else {
             deltaTimeToken = (int)deltaTime;
         }
-        int firstToken = deltaTimeToken
-                | (cur.cmd<<DELTA_CMD_SHIFT)
-                | (cur.states&DELTA_STATE_MASK);
+        int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
         final int batteryLevelInt = buildBatteryLevelInt(cur);
         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
         if (batteryLevelIntChanged) {
@@ -1563,6 +1564,9 @@
         if (cur.wakelockTag != null) {
             firstToken |= DELTA_WAKELOCK_FLAG;
         }
+        if (cur.eventCode != HistoryItem.EVENT_NONE) {
+            firstToken |= DELTA_EVENT_FLAG;
+        }
         dest.writeInt(firstToken);
         if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTime=" + deltaTime);
@@ -1599,7 +1603,7 @@
             if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
                 + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
         }
-        if (cur.cmd == HistoryItem.CMD_EVENT) {
+        if (cur.eventCode != HistoryItem.EVENT_NONE) {
             int index = writeHistoryTag(cur.eventTag);
             int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
             dest.writeInt(codeAndIndex);
@@ -1625,7 +1629,7 @@
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
-        cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+        cur.cmd = HistoryItem.CMD_UPDATE;
         cur.numReadInts = 1;
         if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTimeToken=" + deltaTimeToken);
@@ -1691,7 +1695,7 @@
             cur.wakelockTag = null;
         }
 
-        if (cur.cmd == HistoryItem.CMD_EVENT) {
+        if ((firstToken&DELTA_EVENT_FLAG) != 0) {
             cur.eventTag = cur.localEventTag;
             final int codeAndIndex = src.readInt();
             cur.eventCode = (codeAndIndex&0xffff);
@@ -1720,6 +1724,8 @@
         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
                 && timeDiff < 1000 && (diffStates&lastDiffStates) == 0
                 && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null)
+                && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
+                        || mHistoryCur.eventCode == HistoryItem.EVENT_NONE)
                 && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel
                 && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus
                 && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth
@@ -1742,6 +1748,14 @@
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
             }
+            // If the last written history had an event, we need to retain it.
+            // Note that the condition above made sure that we aren't in a case where
+            // both it and the current history item have an event.
+            if (mHistoryLastWritten.eventCode != HistoryItem.EVENT_NONE) {
+                mHistoryCur.eventCode = mHistoryLastWritten.eventCode;
+                mHistoryCur.eventTag = mHistoryCur.localEventTag;
+                mHistoryCur.eventTag.setTo(mHistoryLastWritten.eventTag);
+            }
             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
         }
 
@@ -1772,26 +1786,18 @@
         addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
     }
 
-    void addHistoryBufferLocked(long curTime, byte cmd) {
-        addHistoryBufferLocked(curTime, cmd, HistoryItem.EVENT_NONE, null, 0);
-    }
-
-    void addHistoryBufferEventLocked(long curTime, int eventCode, String eventName, int eventUid) {
-        addHistoryBufferLocked(curTime, HistoryItem.CMD_EVENT, eventCode, eventName, eventUid);
-    }
-
-    private void addHistoryBufferLocked(long curTime, byte cmd,
-            int eventCode, String eventName, int eventUid) {
+    private void addHistoryBufferLocked(long curTime, byte cmd) {
         if (mIteratingHistory) {
             throw new IllegalStateException("Can't do this while iterating history!");
         }
         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
-        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd,
-                eventCode, eventUid, eventName, mHistoryCur);
+        mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
         mLastHistoryTime = curTime;
         mHistoryCur.wakelockTag = null;
+        mHistoryCur.eventCode = HistoryItem.EVENT_NONE;
+        mHistoryCur.eventTag = null;
         if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
                 + " now " + mHistoryBuffer.dataPosition()
                 + " size is now " + mHistoryBuffer.dataSize());
@@ -1829,8 +1835,7 @@
                 mHistoryLastEnd = null;
             } else {
                 mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
-                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE,
-                        HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
             }
             return;
         }
@@ -1860,7 +1865,11 @@
     }
 
     void addHistoryEventLocked(long curTime, int code, String name, int uid) {
-        addHistoryBufferEventLocked(curTime, code, name, uid);
+        mHistoryCur.eventCode = code;
+        mHistoryCur.eventTag = mHistoryCur.localEventTag;
+        mHistoryCur.eventTag.string = name;
+        mHistoryCur.eventTag.uid = uid;
+        addHistoryBufferLocked(curTime);
     }
 
     void addHistoryRecordLocked(long curTime, byte cmd) {
@@ -1870,8 +1879,7 @@
         } else {
             rec = new HistoryItem();
         }
-        rec.setTo(mHistoryBaseTime + curTime, cmd,
-                HistoryItem.EVENT_NONE, 0, null, mHistoryCur);
+        rec.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
 
         addHistoryRecordLocked(rec);
     }
@@ -1905,8 +1913,8 @@
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
         mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
-        mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
-        mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+        mHistoryLastLastWritten.clear();
+        mHistoryLastWritten.clear();
         mHistoryTagPool.clear();
         mNextHistoryTagIdx = 0;
         mNumHistoryTagChars = 0;
@@ -1942,8 +1950,6 @@
         mBluetoothPingStart = -1;
     }
 
-    int mWakeLockNesting;
-
     public void addIsolatedUidLocked(int isolatedUid, int appUid) {
         mIsolatedUids.put(isolatedUid, appUid);
     }
@@ -1965,7 +1971,8 @@
         addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
     }
 
-    public void noteStartWakeLocked(int uid, int pid, String name, int type) {
+    public void noteStartWakeLocked(int uid, int pid, String name, int type,
+            boolean unimportantForLogging) {
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
@@ -1977,7 +1984,18 @@
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                 mHistoryCur.wakelockTag.string = name;
                 mHistoryCur.wakelockTag.uid = uid;
+                mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            } else if (!mWakeLockImportant && !unimportantForLogging) {
+                if (mHistoryLastWritten.wakelockTag != null) {
+                    // We'll try to update the last tag.
+                    mHistoryLastWritten.wakelockTag = null;
+                    mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.uid = uid;
+                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                }
+                mWakeLockImportant = true;
             }
             mWakeLockNesting++;
         }
@@ -2010,10 +2028,11 @@
         }
     }
 
-    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteStartWakeLocked(ws.get(i), pid, name, type);
+            noteStartWakeLocked(ws.get(i), pid, name, type, unimportantForLogging);
         }
     }
 
@@ -2224,7 +2243,7 @@
 
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
-            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
+            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, false);
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -4979,6 +4998,9 @@
     public boolean startIteratingHistoryLocked() {
         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
                 + " pos=" + mHistoryBuffer.dataPosition());
+        if (mHistoryBuffer.dataSize() <= 0) {
+            return false;
+        }
         mHistoryBuffer.setDataPosition(0);
         mReadOverflow = false;
         mIteratingHistory = true;
@@ -4992,7 +5014,7 @@
             mReadHistoryUids[idx] = tag.uid;
             mReadHistoryChars += tag.string.length() + 1;
         }
-        return mHistoryBuffer.dataSize() > 0;
+        return true;
     }
 
     @Override
@@ -5075,8 +5097,37 @@
         mDischargeAmountScreenOff = 0;
         mDischargeAmountScreenOffSinceCharge = 0;
     }
-    
-    public void resetAllStatsLocked() {
+
+    public void resetAllStatsCmdLocked() {
+        resetAllStatsLocked();
+        long uptime = SystemClock.uptimeMillis() * 1000;
+        long mSecRealtime = SystemClock.elapsedRealtime();
+        long realtime = mSecRealtime * 1000;
+        mDischargeStartLevel = mHistoryCur.batteryLevel;
+        pullPendingStateUpdatesLocked();
+        addHistoryRecordLocked(mSecRealtime);
+        mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+        if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0) {
+            mTrackBatteryPastUptime = 0;
+            mTrackBatteryPastRealtime = 0;
+        } else {
+            mTrackBatteryUptimeStart = uptime;
+            mTrackBatteryRealtimeStart = realtime;
+            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+            if (mScreenOn) {
+                mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
+                mDischargeScreenOffUnplugLevel = 0;
+            } else {
+                mDischargeScreenOnUnplugLevel = 0;
+                mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
+            }
+            mDischargeAmountScreenOn = 0;
+            mDischargeAmountScreenOff = 0;
+        }
+    }
+
+    private void resetAllStatsLocked() {
         mStartCount = 0;
         initTimes();
         mScreenOnTimer.reset(this, false);
@@ -5292,7 +5343,7 @@
             if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
                 // We don't record history while we are plugged in and fully charged.
                 // The next time we are unplugged, history will be cleared.
-                mRecordingHistory = false;
+                mRecordingHistory = DEBUG;
             }
         }
     }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index cb5ae96..eb347bb 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -39,8 +39,10 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -53,9 +55,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.Map;
 import java.util.TimeZone;
 
 import static android.app.AlarmManager.RTC_WAKEUP;
@@ -313,7 +313,22 @@
             return 0;
         }
     }
-    
+
+    final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
+        @Override
+        public int compare(Alarm lhs, Alarm rhs) {
+            if (lhs.wakeup != rhs.wakeup) {
+                return lhs.wakeup ? -1 : 1;
+            }
+            if (lhs.whenElapsed < rhs.whenElapsed) {
+                return -1;
+            } else if (lhs.whenElapsed > rhs.whenElapsed) {
+                return 1;
+            }
+            return 0;
+        }
+    };
+
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
     static final long MIN_FUZZABLE_INTERVAL = 10000;
     static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
@@ -442,6 +457,7 @@
     }
     
     static final class BroadcastStats {
+        final int mUid;
         final String mPackageName;
 
         long aggregateTime;
@@ -449,16 +465,17 @@
         int numWakeup;
         long startTime;
         int nesting;
-        final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
-                = new HashMap<Pair<String, ComponentName>, FilterStats>();
+        final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats
+                = new ArrayMap<Pair<String, ComponentName>, FilterStats>();
 
-        BroadcastStats(String packageName) {
+        BroadcastStats(int uid, String packageName) {
+            mUid = uid;
             mPackageName = packageName;
         }
     }
     
-    final HashMap<String, BroadcastStats> mBroadcastStats
-            = new HashMap<String, BroadcastStats>();
+    final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
+            = new SparseArray<ArrayMap<String, BroadcastStats>>();
     
     @Override
     public void onStart() {
@@ -470,7 +487,7 @@
         setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
 
         PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
         
         mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
@@ -743,24 +760,26 @@
                 }
             };
             int len = 0;
-            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
-                BroadcastStats bs = be.getValue();
-                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
-                        : bs.filterStats.entrySet()) {
-                    FilterStats fs = fe.getValue();
-                    int pos = len > 0
-                            ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
-                    if (pos < 0) {
-                        pos = -pos - 1;
-                    }
-                    if (pos < topFilters.length) {
-                        int copylen = topFilters.length - pos - 1;
-                        if (copylen > 0) {
-                            System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+                for (int ip=0; ip<uidStats.size(); ip++) {
+                    BroadcastStats bs = uidStats.valueAt(ip);
+                    for (int is=0; is<bs.filterStats.size(); is++) {
+                        FilterStats fs = bs.filterStats.valueAt(is);
+                        int pos = len > 0
+                                ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+                        if (pos < 0) {
+                            pos = -pos - 1;
                         }
-                        topFilters[pos] = fs;
-                        if (len < topFilters.length) {
-                            len++;
+                        if (pos < topFilters.length) {
+                            int copylen = topFilters.length - pos - 1;
+                            if (copylen > 0) {
+                                System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+                            }
+                            topFilters[pos] = fs;
+                            if (len < topFilters.length) {
+                                len++;
+                            }
                         }
                     }
                 }
@@ -774,7 +793,8 @@
                     TimeUtils.formatDuration(fs.aggregateTime, pw);
                     pw.print(" running, "); pw.print(fs.numWakeup);
                     pw.print(" wakeups, "); pw.print(fs.count);
-                    pw.print(" alarms: "); pw.print(fs.mBroadcastStats.mPackageName);
+                    pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid);
+                    pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName);
                     pw.println();
                     pw.print("      ");
                     if (fs.mTarget.first != null) {
@@ -790,35 +810,39 @@
             pw.println(" ");
             pw.println("  Alarm Stats:");
             final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
-            for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
-                BroadcastStats bs = be.getValue();
-                pw.print("  ");
-                if (bs.nesting > 0) pw.print("*ACTIVE* ");
-                pw.print(be.getKey());
-                pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
-                        pw.print(" running, "); pw.print(bs.numWakeup);
-                        pw.println(" wakeups:");
-                tmpFilters.clear();
-                for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
-                        : bs.filterStats.entrySet()) {
-                    tmpFilters.add(fe.getValue());
-                }
-                Collections.sort(tmpFilters, comparator);
-                for (int i=0; i<tmpFilters.size(); i++) {
-                    FilterStats fs = tmpFilters.get(i);
-                    pw.print("    ");
-                            if (fs.nesting > 0) pw.print("*ACTIVE* ");
-                            TimeUtils.formatDuration(fs.aggregateTime, pw);
-                            pw.print(" "); pw.print(fs.numWakeup);
-                            pw.print(" wakes " ); pw.print(fs.count);
-                            pw.print(" alarms:");
-                            if (fs.mTarget.first != null) {
-                                pw.print(" act="); pw.print(fs.mTarget.first);
-                            }
-                            if (fs.mTarget.second != null) {
-                                pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
-                            }
-                            pw.println();
+            for (int iu=0; iu<mBroadcastStats.size(); iu++) {
+                ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+                for (int ip=0; ip<uidStats.size(); ip++) {
+                    BroadcastStats bs = uidStats.valueAt(ip);
+                    pw.print("  ");
+                    if (bs.nesting > 0) pw.print("*ACTIVE* ");
+                    UserHandle.formatUid(pw, bs.mUid);
+                    pw.print(":");
+                    pw.print(bs.mPackageName);
+                    pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+                            pw.print(" running, "); pw.print(bs.numWakeup);
+                            pw.println(" wakeups:");
+                    tmpFilters.clear();
+                    for (int is=0; is<bs.filterStats.size(); is++) {
+                        tmpFilters.add(bs.filterStats.valueAt(is));
+                    }
+                    Collections.sort(tmpFilters, comparator);
+                    for (int i=0; i<tmpFilters.size(); i++) {
+                        FilterStats fs = tmpFilters.get(i);
+                        pw.print("    ");
+                                if (fs.nesting > 0) pw.print("*ACTIVE* ");
+                                TimeUtils.formatDuration(fs.aggregateTime, pw);
+                                pw.print(" "); pw.print(fs.numWakeup);
+                                pw.print(" wakes " ); pw.print(fs.count);
+                                pw.print(" alarms:");
+                                if (fs.mTarget.first != null) {
+                                    pw.print(" act="); pw.print(fs.mTarget.first);
+                                }
+                                if (fs.mTarget.second != null) {
+                                    pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString());
+                                }
+                                pw.println();
+                    }
                 }
             }
 
@@ -1037,7 +1061,8 @@
     private native int waitForAlarm(long nativeData);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
-    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
+            final long nowRTC) {
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
         // that is not yet deliverable
@@ -1076,6 +1101,14 @@
 
             }
         }
+
+        Collections.sort(triggerList, mAlarmDispatchComparator);
+
+        if (localLOGV) {
+            for (int i=0; i<triggerList.size(); i++) {
+                Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i));
+            }
+        }
     }
 
     /**
@@ -1096,7 +1129,8 @@
     }
     
     private static class Alarm {
-        public int type;
+        public final int type;
+        public final boolean wakeup;
         public int count;
         public long when;
         public long windowLength;
@@ -1109,6 +1143,8 @@
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
                 long _interval, PendingIntent _op, WorkSource _ws) {
             type = _type;
+            wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
+                    || _type == AlarmManager.RTC_WAKEUP;
             when = _when;
             whenElapsed = _whenElapsed;
             windowLength = _windowLength;
@@ -1126,6 +1162,8 @@
             sb.append(Integer.toHexString(System.identityHashCode(this)));
             sb.append(" type ");
             sb.append(type);
+            sb.append(" when ");
+            sb.append(when);
             sb.append(" ");
             sb.append(operation.getTargetPackage());
             sb.append('}');
@@ -1231,6 +1269,15 @@
                             // we have an active broadcast so stay awake.
                             if (mBroadcastRefCount == 0) {
                                 setWakelockWorkSource(alarm.operation, alarm.workSource);
+                                mWakeLock.setUnimportantForLogging(
+                                        alarm.operation == mTimeTickSender);
+                                // XXX debugging
+                                /*
+                                Intent intent = alarm.operation.getIntent();
+                                mWakeLock.setTag(intent.getAction() != null ? intent.getAction()
+                                        : (intent.getComponent() != null
+                                                ? intent.getComponent().toShortString() : TAG));
+                                */
                                 mWakeLock.acquire();
                             }
                             final InFlight inflight = new InFlight(AlarmManagerService.this,
@@ -1450,7 +1497,14 @@
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkg : pkgList) {
                         removeLocked(pkg);
-                        mBroadcastStats.remove(pkg);
+                        for (int i=mBroadcastStats.size()-1; i>=0; i--) {
+                            ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
+                            if (uidStats.remove(pkg) != null) {
+                                if (uidStats.size() <= 0) {
+                                    mBroadcastStats.removeAt(i);
+                                }
+                            }
+                        }
                     }
                 }
             }
@@ -1458,11 +1512,17 @@
     }
     
     private final BroadcastStats getStatsLocked(PendingIntent pi) {
-        String pkg = pi.getTargetPackage();
-        BroadcastStats bs = mBroadcastStats.get(pkg);
+        String pkg = pi.getCreatorPackage();
+        int uid = pi.getCreatorUid();
+        ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
+        if (uidStats == null) {
+            uidStats = new ArrayMap<String, BroadcastStats>();
+            mBroadcastStats.put(uid, uidStats);
+        }
+        BroadcastStats bs = uidStats.get(pkg);
         if (bs == null) {
-            bs = new BroadcastStats(pkg);
-            mBroadcastStats.put(pkg, bs);
+            bs = new BroadcastStats(uid, pkg);
+            uidStats.put(pkg, bs);
         }
         return bs;
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index eda08a9..8a29ac7 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -126,10 +126,11 @@
         }
     }
 
-    public void noteStartWakelock(int uid, int pid, String name, int type) {
+    public void noteStartWakelock(int uid, int pid, String name, int type,
+            boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeLocked(uid, pid, name, type);
+            mStats.noteStartWakeLocked(uid, pid, name, type, unimportantForLogging);
         }
     }
 
@@ -140,10 +141,11 @@
         }
     }
 
-    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type,
+            boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type);
+            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type, unimportantForLogging);
         }
     }
 
@@ -557,7 +559,7 @@
                     isUnpluggedOnly = true;
                 } else if ("--reset".equals(arg)) {
                     synchronized (mStats) {
-                        mStats.resetAllStatsLocked();
+                        mStats.resetAllStatsCmdLocked();
                         pw.println("Battery stats reset.");
                         noOutput = true;
                     }
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index f1be504..b63f625 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -536,6 +536,14 @@
 
         mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
                 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
+
+        // Initialize screen on state.
+        if (mPowerState.isScreenOn()) {
+            mNotifier.onScreenOn();
+        } else {
+            mNotifier.onScreenOff();
+        }
+        mNotifier.onScreenBrightness(mPowerState.getScreenBrightness());
     }
 
     private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 264e2e9..09be3a8 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -34,6 +34,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -139,10 +140,14 @@
 
         try {
             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
+                    && ownerUid == Process.SYSTEM_UID;
             if (workSource != null) {
-                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType,
+                        unimportantForLogging);
             } else {
-                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
+                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType,
+                        unimportantForLogging);
                 // XXX need to deal with disabled operations.
                 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);