diff options
| author | 2014-02-03 10:50:53 -0800 | |
|---|---|---|
| committer | 2014-02-03 10:58:50 -0800 | |
| commit | 71fc13eb583eecc677b177b8010538a08aebb43d (patch) | |
| tree | ac68e4deb3c7bf260ef590144b299325ebc1c453 | |
| parent | 2b033dce9f252ae30ac88c9ba1569d18afaaf2cf (diff) | |
More battery history improvements.
- Better batching of history items.  Fixed problems where empty
  entries would be created because state toggles got lost.
- The string pool is now a HistoryTag pool, containing both a string
  and uid; now an entry only requires 16 bits in the history data.
- Acquiring the first wake lock also now includes a HistoryTag
  identifying who did the aquisition.
- Cleaned up printing of signal strengths and cell radio types.
- There was code that tried to allow you to add new history entries
  while iterating the history...  but these should never happen
  together, so turned that into a failure...  and fixed an issue
  where we could leave the battery stats in a state where it
  thinks it is continually iterating.
Change-Id: I1afa57ee2d66b186932c502dbdd633cdd4aed353
| -rw-r--r-- | core/java/android/os/BatteryStats.java | 322 | ||||
| -rw-r--r-- | core/java/com/android/internal/os/BatteryStatsImpl.java | 244 | 
2 files changed, 424 insertions, 142 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 2afea1fbc87d..27c0f5da99c9 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -452,6 +452,56 @@ public abstract class BatteryStats implements Parcelable {          }      } +    public final static class HistoryTag { +        public String string; +        public int uid; + +        public int poolIdx; + +        public void setTo(HistoryTag o) { +            string = o.string; +            uid = o.uid; +            poolIdx = o.poolIdx; +        } + +        public void setTo(String _string, int _uid) { +            string = _string; +            uid = _uid; +            poolIdx = -1; +        } + +        public void writeToParcel(Parcel dest, int flags) { +            dest.writeString(string); +            dest.writeInt(uid); +        } + +        public void readFromParcel(Parcel src) { +            string = src.readString(); +            uid = src.readInt(); +            poolIdx = -1; +        } + +        @Override +        public boolean equals(Object o) { +            if (this == o) return true; +            if (o == null || getClass() != o.getClass()) return false; + +            HistoryTag that = (HistoryTag) o; + +            if (uid != that.uid) return false; +            if (!string.equals(that.string)) return false; + +            return true; +        } + +        @Override +        public int hashCode() { +            int result = string.hashCode(); +            result = 31 * result + uid; +            return result; +        } +    } +      public final static class HistoryItem implements Parcelable {          public HistoryItem next; @@ -500,7 +550,7 @@ public abstract class BatteryStats implements Parcelable {          public static final int STATE_PHONE_STATE_MASK = 0x7 << STATE_PHONE_STATE_SHIFT;          // Constants from DATA_CONNECTION_*          public static final int STATE_DATA_CONNECTION_SHIFT = 9; -        public static final int STATE_DATA_CONNECTION_MASK = 0x1f; +        public static final int STATE_DATA_CONNECTION_MASK = 0x1f << STATE_DATA_CONNECTION_SHIFT;          // These states always appear directly in the first int token          // of a delta change; they should be ones that change relatively @@ -529,21 +579,30 @@ public abstract class BatteryStats implements Parcelable {          public int states; +        // The wake lock that was acquired at this point. +        public HistoryTag wakelockTag; +          public static final int EVENT_NONE = 0;          public static final int EVENT_PROC_STARTED = 1;          public static final int EVENT_PROC_FINISHED = 2;          // For CMD_EVENT.          public int eventCode; -        public String eventName; -        public int eventNameIdx;    // only filled in when iterating. -        public int eventUid; +        public HistoryTag eventTag; + +        // Meta-data when reading. +        public int numReadInts; + +        // Pre-allocated objects. +        public final HistoryTag localWakelockTag = new HistoryTag(); +        public final HistoryTag localEventTag = new HistoryTag();          public HistoryItem() {          }          public HistoryItem(long time, Parcel src) {              this.time = time; +            numReadInts = 2;              readFromParcel(src);          } @@ -563,14 +622,20 @@ public abstract class BatteryStats implements Parcelable {                      | ((((int)batteryVoltage)<<16)&0xffff0000);              dest.writeInt(bat);              dest.writeInt(states); +            if (wakelockTag != null) { +                dest.writeInt(1); +                wakelockTag.writeToParcel(dest, flags); +            } else { +                dest.writeInt(0); +            }              if (cmd == CMD_EVENT) {                  dest.writeInt(eventCode); -                dest.writeInt(eventUid); -                dest.writeString(eventName); +                eventTag.writeToParcel(dest, flags);              }          }          public void readFromParcel(Parcel src) { +            int start = src.dataPosition();              int bat = src.readInt();              cmd = (byte)(bat&0xff);              batteryLevel = (byte)((bat>>8)&0xff); @@ -581,14 +646,21 @@ public abstract class BatteryStats implements Parcelable {              batteryTemperature = (short)(bat&0xffff);              batteryVoltage = (char)((bat>>16)&0xffff);              states = src.readInt(); +            if (src.readInt() != 0) { +                wakelockTag = localWakelockTag; +                wakelockTag.readFromParcel(src); +            } else { +                wakelockTag = null; +            }              if (cmd == CMD_EVENT) {                  eventCode = src.readInt(); -                eventUid = src.readInt(); -                eventName = src.readString(); -                eventNameIdx = 0; +                eventTag = localEventTag; +                eventTag.readFromParcel(src);              } else {                  eventCode = EVENT_NONE; +                eventTag = null;              } +            numReadInts += (src.dataPosition()-start)/4;          }          public void clear() { @@ -601,9 +673,9 @@ public abstract class BatteryStats implements Parcelable {              batteryTemperature = 0;              batteryVoltage = 0;              states = 0; +            wakelockTag = null;              eventCode = EVENT_NONE; -            eventUid = 0; -            eventName = null; +            eventTag = null;          }          public void setTo(HistoryItem o) { @@ -616,10 +688,19 @@ public abstract class BatteryStats implements Parcelable {              batteryTemperature = o.batteryTemperature;              batteryVoltage = o.batteryVoltage;              states = o.states; +            if (o.wakelockTag != null) { +                wakelockTag = localWakelockTag; +                wakelockTag.setTo(o.wakelockTag); +            } else { +                wakelockTag = null; +            }              eventCode = o.eventCode; -            eventUid = o.eventUid; -            eventName = o.eventName; -            eventNameIdx = o.eventNameIdx; +            if (o.eventTag != null) { +                eventTag = localEventTag; +                eventTag.setTo(o.eventTag); +            } else { +                eventTag = null; +            }          }          public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName, @@ -627,9 +708,12 @@ public abstract class BatteryStats implements Parcelable {              this.time = time;              this.cmd = cmd;              this.eventCode = eventCode; -            this.eventUid = eventUid; -            this.eventName = eventName; -            this.eventNameIdx = 0; +            if (eventCode != EVENT_NONE) { +                eventTag = localEventTag; +                eventTag.setTo(eventName, eventUid); +            } else { +                eventTag = null; +            }              batteryLevel = o.batteryLevel;              batteryStatus = o.batteryStatus;              batteryHealth = o.batteryHealth; @@ -637,6 +721,12 @@ public abstract class BatteryStats implements Parcelable {              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) { @@ -650,13 +740,26 @@ public abstract class BatteryStats implements Parcelable {          }          public boolean same(HistoryItem o) { -            if (!sameNonEvent(o) || eventCode != o.eventCode || eventUid != o.eventUid) { +            if (!sameNonEvent(o) || eventCode != o.eventCode) {                  return false;              } -            if (eventName == o.eventName) { -                return true; +            if (wakelockTag != o.wakelockTag) { +                if (wakelockTag == null || o.wakelockTag == null) { +                    return false; +                } +                if (!wakelockTag.equals(o.wakelockTag)) { +                    return false; +                } +            } +            if (eventTag != o.eventTag) { +                if (eventTag == null || o.eventTag == null) { +                    return false; +                } +                if (!eventTag.equals(o.eventTag)) { +                    return false; +                }              } -            return eventName != null && o.eventName != null && eventName.equals(o.eventName); +            return true;          }      } @@ -688,11 +791,19 @@ public abstract class BatteryStats implements Parcelable {          }      } +    public abstract int getHistoryTotalSize(); + +    public abstract int getHistoryUsedSize(); +      public abstract boolean startIteratingHistoryLocked();      public abstract int getHistoryStringPoolSize(); -    public abstract String getHistoryStringPoolItem(int index); +    public abstract int getHistoryStringPoolBytes(); + +    public abstract String getHistoryTagPoolString(int index); + +    public abstract int getHistoryTagPoolUid(int index);      public abstract boolean getNextHistoryLocked(HistoryItem out); @@ -1746,14 +1857,14 @@ public abstract class BatteryStats implements Parcelable {          sb.setLength(0);          sb.append(prefix); -        sb.append("  Signal levels: "); +        sb.append("  Signal levels:");          didOne = false;          for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {              final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);              if (time == 0) {                  continue;              } -            if (didOne) sb.append(", "); +            sb.append("\n    ");              didOne = true;              sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]);              sb.append(" "); @@ -1764,7 +1875,7 @@ public abstract class BatteryStats implements Parcelable {              sb.append(getPhoneSignalStrengthCount(i, which));              sb.append("x");          } -        if (!didOne) sb.append("No activity"); +        if (!didOne) sb.append(" (no activity)");          pw.println(sb.toString());          sb.setLength(0); @@ -1775,14 +1886,14 @@ public abstract class BatteryStats implements Parcelable {          sb.setLength(0);          sb.append(prefix); -        sb.append("  Radio types: "); +        sb.append("  Radio types:");          didOne = false;          for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {              final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);              if (time == 0) {                  continue;              } -            if (didOne) sb.append(", "); +            sb.append("\n    ");              didOne = true;              sb.append(DATA_CONNECTION_NAMES[i]);              sb.append(" "); @@ -1793,7 +1904,7 @@ public abstract class BatteryStats implements Parcelable {              sb.append(getPhoneDataConnectionCount(i, which));              sb.append("x");          } -        if (!didOne) sb.append("No activity"); +        if (!didOne) sb.append(" (no activity)");          pw.println(sb.toString());          sb.setLength(0); @@ -2259,21 +2370,30 @@ public abstract class BatteryStats implements Parcelable {          }      } -    static void printBitDescriptions(PrintWriter pw, int oldval, int newval, +    static void printBitDescriptions(PrintWriter pw, int oldval, int newval, HistoryTag wakelockTag,              BitDescription[] descriptions, boolean longNames) {          int diff = oldval ^ newval;          if (diff == 0) return; +        boolean didWake = false;          for (int i=0; i<descriptions.length; i++) {              BitDescription bd = descriptions[i]; -            int mask = bd.mask; -            if (bd.shift > 0) { -                mask <<= bd.shift; -            } -            if ((diff&mask) != 0) { +            if ((diff&bd.mask) != 0) {                  pw.print(longNames ? " " : ",");                  if (bd.shift < 0) { -                    pw.print((newval&mask) != 0 ? "+" : "-"); +                    pw.print((newval&bd.mask) != 0 ? "+" : "-");                      pw.print(longNames ? bd.name : bd.shortName); +                    if (bd.mask == HistoryItem.STATE_WAKE_LOCK_FLAG && wakelockTag != null) { +                        didWake = true; +                        pw.print("="); +                        if (longNames) { +                            UserHandle.formatUid(pw, wakelockTag.uid); +                            pw.print(":\""); +                            pw.print(wakelockTag.string); +                            pw.print("\""); +                        } else { +                            pw.print(wakelockTag.poolIdx); +                        } +                    }                  } else {                      pw.print(longNames ? bd.name : bd.shortName);                      pw.print("="); @@ -2286,6 +2406,17 @@ public abstract class BatteryStats implements Parcelable {                  }              }          } +        if (!didWake && wakelockTag != null) { +            pw.print(longNames ? "wake_lock=" : "w="); +            if (longNames) { +                UserHandle.formatUid(pw, wakelockTag.uid); +                pw.print(":\""); +                pw.print(wakelockTag.string); +                pw.print("\""); +            } else { +                pw.print(wakelockTag.poolIdx); +            } +        }      }      public void prepareForDumpLocked() { @@ -2305,7 +2436,9 @@ public abstract class BatteryStats implements Parcelable {              if (!checkin) {                  pw.print("  ");                  TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); -                pw.print(" "); +                pw.print(" ("); +                pw.print(rec.numReadInts); +                pw.print(") ");              } else {                  if (lastTime < 0) {                      pw.print("@"); @@ -2427,7 +2560,7 @@ public abstract class BatteryStats implements Parcelable {                      pw.print(checkin ? ",Bv=" : " volt=");                      pw.print(oldVolt);                  } -                printBitDescriptions(pw, oldState, rec.states, +                printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,                          HISTORY_STATE_DESCRIPTIONS, !checkin);                  if (rec.eventCode != HistoryItem.EVENT_NONE) {                      switch (rec.eventCode) { @@ -2450,15 +2583,12 @@ public abstract class BatteryStats implements Parcelable {                              break;                      }                      if (checkin) { -                        pw.print(rec.eventUid); -                    } else { -                        UserHandle.formatUid(pw, rec.eventUid); -                    } -                    pw.print(":"); -                    if (checkin) { -                        pw.print(rec.eventNameIdx); +                        pw.print(rec.eventTag.poolIdx);                      } else { -                        pw.print(rec.eventName); +                        UserHandle.formatUid(pw, rec.eventTag.uid); +                        pw.print(":\""); +                        pw.print(rec.eventTag.string); +                        pw.print("\"");                      }                  }                  pw.println(); @@ -2467,6 +2597,33 @@ public abstract class BatteryStats implements Parcelable {          }      } +    private void printSizeValue(PrintWriter pw, long size) { +        float result = size; +        String suffix = ""; +        if (result >= 10*1024) { +            suffix = "KB"; +            result = result / 1024; +        } +        if (result >= 10*1024) { +            suffix = "MB"; +            result = result / 1024; +        } +        if (result >= 10*1024) { +            suffix = "GB"; +            result = result / 1024; +        } +        if (result >= 10*1024) { +            suffix = "TB"; +            result = result / 1024; +        } +        if (result >= 10*1024) { +            suffix = "PB"; +            result = result / 1024; +        } +        pw.print((int)result); +        pw.print(suffix); +    } +      /**       * Dumps a human-readable summary of the battery statistics to the given PrintWriter.       * @@ -2480,24 +2637,42 @@ public abstract class BatteryStats implements Parcelable {          long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();          final HistoryItem rec = new HistoryItem(); +        final long historyTotalSize = getHistoryTotalSize(); +        final long historyUsedSize = getHistoryUsedSize();          if (startIteratingHistoryLocked()) { -            pw.println("Battery History:"); -            HistoryPrinter hprinter = new HistoryPrinter(); -            while (getNextHistoryLocked(rec)) { -                hprinter.printNextItem(pw, rec, now, false); +            try { +                pw.print("Battery History ("); +                pw.print((100*historyUsedSize)/historyTotalSize); +                pw.print("% used, "); +                printSizeValue(pw, historyUsedSize); +                pw.print(" used of "); +                printSizeValue(pw, historyTotalSize); +                pw.print(", "); +                pw.print(getHistoryStringPoolSize()); +                pw.print(" strings using "); +                printSizeValue(pw, getHistoryStringPoolBytes()); +                pw.println("):"); +                HistoryPrinter hprinter = new HistoryPrinter(); +                while (getNextHistoryLocked(rec)) { +                    hprinter.printNextItem(pw, rec, now, false); +                } +                pw.println(); +            } finally { +                finishIteratingHistoryLocked();              } -            finishIteratingHistoryLocked(); -            pw.println("");          }          if (startIteratingOldHistoryLocked()) { -            pw.println("Old battery History:"); -            HistoryPrinter hprinter = new HistoryPrinter(); -            while (getNextOldHistoryLocked(rec)) { -                hprinter.printNextItem(pw, rec, now, false); +            try { +                pw.println("Old battery History:"); +                HistoryPrinter hprinter = new HistoryPrinter(); +                while (getNextOldHistoryLocked(rec)) { +                    hprinter.printNextItem(pw, rec, now, false); +                } +                pw.println(); +            } finally { +                finishIteratingOldHistoryLocked();              } -            finishIteratingOldHistoryLocked(); -            pw.println("");          }          if (historyOnly) { @@ -2553,21 +2728,26 @@ public abstract class BatteryStats implements Parcelable {          if (includeHistory || historyOnly) {              final HistoryItem rec = new HistoryItem();              if (startIteratingHistoryLocked()) { -                for (int i=0; i<getHistoryStringPoolSize(); i++) { -                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); -                    pw.print(HISTORY_STRING_POOL); pw.print(','); -                    pw.print(i); -                    pw.print(','); -                    pw.print(getHistoryStringPoolItem(i)); -                    pw.println(); -                } -                HistoryPrinter hprinter = new HistoryPrinter(); -                while (getNextHistoryLocked(rec)) { -                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); -                    pw.print(HISTORY_DATA); pw.print(','); -                    hprinter.printNextItem(pw, rec, now, true); +                try { +                    for (int i=0; i<getHistoryStringPoolSize(); i++) { +                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); +                        pw.print(HISTORY_STRING_POOL); pw.print(','); +                        pw.print(i); +                        pw.print(','); +                        pw.print(getHistoryTagPoolString(i)); +                        pw.print(','); +                        pw.print(getHistoryTagPoolUid(i)); +                        pw.println(); +                    } +                    HistoryPrinter hprinter = new HistoryPrinter(); +                    while (getNextHistoryLocked(rec)) { +                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); +                        pw.print(HISTORY_DATA); pw.print(','); +                        hprinter.printNextItem(pw, rec, now, true); +                    } +                } finally { +                    finishIteratingHistoryLocked();                  } -                finishIteratingHistoryLocked();              }          } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 742544536319..68c41fa581f9 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -87,7 +87,7 @@ public final class BatteryStatsImpl extends BatteryStats {      private static final int MAGIC = 0xBA757475; // 'BATSTATS'      // Current on-disk Parcel version -    private static final int VERSION = 71 + (USE_OLD_HISTORY ? 1000 : 0); +    private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);      // Maximum number of items we will record in the history.      private static final int MAX_HISTORY_ITEMS = 2000; @@ -189,9 +189,12 @@ public final class BatteryStatsImpl extends BatteryStats {      final HistoryItem mHistoryLastWritten = new HistoryItem();      final HistoryItem mHistoryLastLastWritten = new HistoryItem();      final HistoryItem mHistoryReadTmp = new HistoryItem(); -    final HashMap<String, Integer> mHistoryStringPool = new HashMap<String, Integer>(); +    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>();      String[] mReadHistoryStrings; -    int mNextHistoryStringIdx = 0; +    int[] mReadHistoryUids; +    int mReadHistoryChars; +    int mNextHistoryTagIdx = 0; +    int mNumHistoryTagChars = 0;      int mHistoryBufferLastPos = -1;      boolean mHistoryOverflow = false;      long mLastHistoryTime = 0; @@ -1486,18 +1489,43 @@ public final class BatteryStatsImpl extends BatteryStats {          mBtHeadset = headset;      } +    private int writeHistoryTag(HistoryTag tag) { +        Integer idxObj = mHistoryTagPool.get(tag); +        int idx; +        if (idxObj != null) { +            idx = idxObj; +        } else { +            idx = mNextHistoryTagIdx; +            HistoryTag key = new HistoryTag(); +            key.setTo(tag); +            tag.poolIdx = idx; +            mHistoryTagPool.put(key, idx); +            mNextHistoryTagIdx++; +            mNumHistoryTagChars += key.string.length() + 1; +        } +        return idx; +    } + +    private void readHistoryTag(int index, HistoryTag tag) { +        tag.string = mReadHistoryStrings[index]; +        tag.uid = mReadHistoryUids[index]; +        tag.poolIdx = index; +    } +      // Part of initial delta int that specifies the time delta. -    static final int DELTA_TIME_MASK = 0x3ffff; -    static final int DELTA_TIME_ABS = 0x3fffd;    // Following is an entire abs update. -    static final int DELTA_TIME_INT = 0x3fffe;    // The delta is a following int -    static final int DELTA_TIME_LONG = 0x3ffff;   // The delta is a following long +    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 = 18; +    static final int DELTA_CMD_SHIFT = 17;      // Flag in delta int: a new battery level int follows. -    static final int DELTA_BATTERY_LEVEL_FLAG = 1<<20; +    static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;      // Flag in delta int: a new full state and battery status int follows. -    static final int DELTA_STATE_FLAG = 1<<21; +    static final int DELTA_STATE_FLAG = 0x00100000; +    // Flag in delta int: contains a wakelock tag. +    static final int DELTA_WAKELOCK_FLAG = 0x00200000;      static final int DELTA_STATE_MASK = 0xffc00000;      public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) { @@ -1532,6 +1560,9 @@ public final class BatteryStatsImpl extends BatteryStats {          if (stateIntChanged) {              firstToken |= DELTA_STATE_FLAG;          } +        if (cur.wakelockTag != null) { +            firstToken |= DELTA_WAKELOCK_FLAG; +        }          dest.writeInt(firstToken);          if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)                  + " deltaTime=" + deltaTime); @@ -1562,20 +1593,19 @@ public final class BatteryStatsImpl extends BatteryStats {                      + " batteryPlugType=" + cur.batteryPlugType                      + " states=0x" + Integer.toHexString(cur.states));          } +        if (cur.wakelockTag != null) { +            int index = writeHistoryTag(cur.wakelockTag); +            dest.writeInt(index); +            if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx +                + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); +        }          if (cur.cmd == HistoryItem.CMD_EVENT) { -            Integer idxObj = mHistoryStringPool.get(cur.eventName); -            int codeAndIndex = (cur.eventCode&0xffff); -            int idx; -            if (idxObj != null) { -                idx = idxObj; -            } else { -                idx = mNextHistoryStringIdx; -                mHistoryStringPool.put(cur.eventName, mNextHistoryStringIdx); -                mNextHistoryStringIdx++; -            } -            codeAndIndex |= (idx<<16); +            int index = writeHistoryTag(cur.eventTag); +            int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);              dest.writeInt(codeAndIndex); -            dest.writeInt(cur.eventUid); +            if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#" +                    + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" +                    + cur.eventTag.string);          }      } @@ -1596,6 +1626,7 @@ public final class BatteryStatsImpl extends BatteryStats {          int firstToken = src.readInt();          int deltaTimeToken = firstToken&DELTA_TIME_MASK;          cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK); +        cur.numReadInts = 1;          if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)                  + " deltaTimeToken=" + deltaTimeToken); @@ -1603,16 +1634,20 @@ public final class BatteryStatsImpl extends BatteryStats {              cur.time += deltaTimeToken;          } else if (deltaTimeToken == DELTA_TIME_ABS) {              cur.time = src.readLong(); +            cur.numReadInts += 2; +            if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);              cur.readFromParcel(src);              return;          } else if (deltaTimeToken == DELTA_TIME_INT) {              int delta = src.readInt();              cur.time += delta; +            cur.numReadInts += 1;              if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);          } else {              long delta = src.readLong();              if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);              cur.time += delta; +            cur.numReadInts += 2;          }          if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) { @@ -1620,6 +1655,7 @@ public final class BatteryStatsImpl extends BatteryStats {              cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);              cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);              cur.batteryVoltage = (char)(batteryLevelInt&0x3fff); +            cur.numReadInts += 1;              if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"                      + Integer.toHexString(batteryLevelInt)                      + " batteryLevel=" + cur.batteryLevel @@ -1633,6 +1669,7 @@ public final class BatteryStatsImpl extends BatteryStats {              cur.batteryStatus = (byte)((stateInt>>28)&0xf);              cur.batteryHealth = (byte)((stateInt>>24)&0xf);              cur.batteryPlugType = (byte)((stateInt>>22)&0x3); +            cur.numReadInts += 1;              if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"                      + Integer.toHexString(stateInt)                      + " batteryStatus=" + cur.batteryStatus @@ -1643,55 +1680,78 @@ public final class BatteryStatsImpl extends BatteryStats {              cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK));          } +        if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) { +            cur.wakelockTag = cur.localWakelockTag; +            int index = src.readInt(); +            readHistoryTag(index, cur.wakelockTag); +            cur.numReadInts += 1; +            if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx +                + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); +        } else { +            cur.wakelockTag = null; +        } +          if (cur.cmd == HistoryItem.CMD_EVENT) { -            int codeAndIndex = src.readInt(); +            cur.eventTag = cur.localEventTag; +            final int codeAndIndex = src.readInt();              cur.eventCode = (codeAndIndex&0xffff); -            int index = ((codeAndIndex>>16)&0xffff); -            cur.eventName = mReadHistoryStrings[index]; -            cur.eventNameIdx = index; -            cur.eventUid = src.readInt(); +            final int index = ((codeAndIndex>>16)&0xffff); +            readHistoryTag(index, cur.eventTag); +            cur.numReadInts += 1; +            if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#" +                    + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" +                    + cur.eventTag.string);          } else {              cur.eventCode = HistoryItem.EVENT_NONE;          }      } -    int mChangedBufferStates = 0; -      void addHistoryBufferLocked(long curTime) {          if (!mHaveBatteryLevel || !mRecordingHistory) {              return;          }          final long timeDiff = (mHistoryBaseTime+curTime) - mHistoryLastWritten.time; +        final int diffStates = mHistoryLastWritten.states^mHistoryCur.states; +        final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states; +        if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff=" +                + Integer.toHexString(diffStates) + " lastDiff=" +                + Integer.toHexString(lastDiffStates));          if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE -                && timeDiff < 2000 -                && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) { -            // If the current is the same as the one before, then we no -            // longer need the entry. +                && timeDiff < 1000 && (diffStates&lastDiffStates) == 0 +                && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null) +                && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel +                && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus +                && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth +                && mHistoryLastWritten.batteryPlugType == mHistoryCur.batteryPlugType +                && mHistoryLastWritten.batteryTemperature == mHistoryCur.batteryTemperature +                && mHistoryLastWritten.batteryVoltage == mHistoryCur.batteryVoltage) { +            // We can merge this new change in with the last one.  Merging is +            // allows as long as only the states have changed, and within those states +            // as long as no bit has changed both between now and the last entry, as +            // well as the last entry and the one before it (so we capture any toggles). +            if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos);              mHistoryBuffer.setDataSize(mHistoryBufferLastPos);              mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);              mHistoryBufferLastPos = -1; -            if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE -                    && timeDiff < 500 && mHistoryLastLastWritten.sameNonEvent(mHistoryCur)) { -                // If this results in us returning to the state written -                // prior to the last one, then we can just delete the last -                // written one and drop the new one.  Nothing more to do. -                mHistoryLastWritten.setTo(mHistoryLastLastWritten); -                mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL; -                return; -            } -            mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states;              curTime = mHistoryLastWritten.time - mHistoryBaseTime; +            // If the last written history had a wakelock tag, 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 a wakelock tag. +            if (mHistoryLastWritten.wakelockTag != null) { +                mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; +                mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag); +            }              mHistoryLastWritten.setTo(mHistoryLastLastWritten); -        } else { -            mChangedBufferStates = 0;          }          final int dataSize = mHistoryBuffer.dataSize();          if (dataSize >= MAX_HISTORY_BUFFER) {              if (!mHistoryOverflow) {                  mHistoryOverflow = true; +                addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);                  addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW); +                return;              }              // Once we've reached the maximum number of items, we only @@ -1704,6 +1764,9 @@ public final class BatteryStatsImpl extends BatteryStats {                                      & HistoryItem.MOST_INTERESTING_STATES) == 0)) {                  return;              } + +            addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE); +            return;          }          addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE); @@ -1719,10 +1782,8 @@ public final class BatteryStatsImpl extends BatteryStats {      private void addHistoryBufferLocked(long curTime, byte cmd,              int eventCode, String eventName, int eventUid) { -        int origPos = 0;          if (mIteratingHistory) { -            origPos = mHistoryBuffer.dataPosition(); -            mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); +            throw new IllegalStateException("Can't do this while iterating history!");          }          mHistoryBufferLastPos = mHistoryBuffer.dataPosition();          mHistoryLastLastWritten.setTo(mHistoryLastWritten); @@ -1730,12 +1791,10 @@ public final class BatteryStatsImpl extends BatteryStats {                  eventCode, eventUid, eventName, mHistoryCur);          writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);          mLastHistoryTime = curTime; +        mHistoryCur.wakelockTag = null;          if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos                  + " now " + mHistoryBuffer.dataPosition()                  + " size is now " + mHistoryBuffer.dataSize()); -        if (mIteratingHistory) { -            mHistoryBuffer.setDataPosition(origPos); -        }      }      int mChangedStates = 0; @@ -1845,11 +1904,12 @@ public final class BatteryStatsImpl extends BatteryStats {          mHistoryBuffer.setDataSize(0);          mHistoryBuffer.setDataPosition(0); -        mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2); +        mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);          mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;          mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; -        mHistoryStringPool.clear(); -        mNextHistoryStringIdx = 0; +        mHistoryTagPool.clear(); +        mNextHistoryTagIdx = 0; +        mNumHistoryTagChars = 0;          mHistoryBufferLastPos = -1;          mHistoryOverflow = false;      } @@ -1914,6 +1974,9 @@ public final class BatteryStatsImpl extends BatteryStats {                  mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;                  if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "                          + Integer.toHexString(mHistoryCur.states)); +                mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag; +                mHistoryCur.wakelockTag.string = name; +                mHistoryCur.wakelockTag.uid = uid;                  addHistoryRecordLocked(SystemClock.elapsedRealtime());              }              mWakeLockNesting++; @@ -2161,7 +2224,7 @@ public final class BatteryStatsImpl extends BatteryStats {              // Fake a wake lock, so we consider the device waked as long              // as the screen is on. -            noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL); +            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);              // Update discharge amounts.              if (mOnBatteryInternal) { @@ -4854,11 +4917,14 @@ public final class BatteryStatsImpl extends BatteryStats {      public boolean startIteratingOldHistoryLocked() {          if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()                  + " pos=" + mHistoryBuffer.dataPosition()); +        if ((mHistoryIterator = mHistory) == null) { +            return false; +        }          mHistoryBuffer.setDataPosition(0);          mHistoryReadTmp.clear();          mReadOverflow = false;          mIteratingHistory = true; -        return (mHistoryIterator = mHistory) != null; +        return true;      }      @Override @@ -4898,6 +4964,15 @@ public final class BatteryStatsImpl extends BatteryStats {      public void finishIteratingOldHistoryLocked() {          mIteratingHistory = false;          mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); +        mHistoryIterator = null; +    } + +    public int getHistoryTotalSize() { +        return MAX_HISTORY_BUFFER; +    } + +    public int getHistoryUsedSize() { +        return mHistoryBuffer.dataSize();      }      @Override @@ -4907,9 +4982,15 @@ public final class BatteryStatsImpl extends BatteryStats {          mHistoryBuffer.setDataPosition(0);          mReadOverflow = false;          mIteratingHistory = true; -        mReadHistoryStrings = new String[mHistoryStringPool.size()]; -        for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) { -            mReadHistoryStrings[ent.getValue()] = ent.getKey(); +        mReadHistoryStrings = new String[mHistoryTagPool.size()]; +        mReadHistoryUids = new int[mHistoryTagPool.size()]; +        mReadHistoryChars = 0; +        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { +            final HistoryTag tag = ent.getKey(); +            final int idx = ent.getValue(); +            mReadHistoryStrings[idx] = tag.string; +            mReadHistoryUids[idx] = tag.uid; +            mReadHistoryChars += tag.string.length() + 1;          }          return mHistoryBuffer.dataSize() > 0;      } @@ -4920,11 +5001,23 @@ public final class BatteryStatsImpl extends BatteryStats {      }      @Override -    public String getHistoryStringPoolItem(int index) { +    public int getHistoryStringPoolBytes() { +        // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size +        // Each string character is 2 bytes. +        return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2); +    } + +    @Override +    public String getHistoryTagPoolString(int index) {          return mReadHistoryStrings[index];      }      @Override +    public int getHistoryTagPoolUid(int index) { +        return mReadHistoryUids[index]; +    } + +    @Override      public boolean getNextHistoryLocked(HistoryItem out) {          final int pos = mHistoryBuffer.dataPosition();          if (pos == 0) { @@ -5717,17 +5810,24 @@ public final class BatteryStatsImpl extends BatteryStats {          mHistoryBuffer.setDataSize(0);          mHistoryBuffer.setDataPosition(0); -        mHistoryStringPool.clear(); -        mNextHistoryStringIdx = 0; +        mHistoryTagPool.clear(); +        mNextHistoryTagIdx = 0; +        mNumHistoryTagChars = 0; -        int numStrings = in.readInt(); -        for (int i=0; i<numStrings; i++) { -            String str = in.readString(); +        int numTags = in.readInt(); +        for (int i=0; i<numTags; i++) {              int idx = in.readInt(); -            mHistoryStringPool.put(str, idx); -            if (idx >= mNextHistoryStringIdx) { -                mNextHistoryStringIdx = idx+1; +            String str = in.readString(); +            int uid = in.readInt(); +            HistoryTag tag = new HistoryTag(); +            tag.string = str; +            tag.uid = uid; +            tag.poolIdx = idx; +            mHistoryTagPool.put(tag, idx); +            if (idx >= mNextHistoryTagIdx) { +                mNextHistoryTagIdx = idx+1;              } +            mNumHistoryTagChars += tag.string.length() + 1;          }          int bufSize = in.readInt(); @@ -5797,10 +5897,12 @@ public final class BatteryStatsImpl extends BatteryStats {              Slog.i(TAG, sb.toString());          }          out.writeLong(mHistoryBaseTime + mLastHistoryTime); -        out.writeInt(mHistoryStringPool.size()); -        for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) { -            out.writeString(ent.getKey()); +        out.writeInt(mHistoryTagPool.size()); +        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) { +            HistoryTag tag = ent.getKey();              out.writeInt(ent.getValue()); +            out.writeString(tag.string); +            out.writeInt(tag.uid);          }          out.writeInt(mHistoryBuffer.dataSize());          if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "  |