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
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 2afea1f..27c0f5d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -452,6 +452,56 @@
}
}
+ 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 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 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 @@
| ((((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 @@
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 @@
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 @@
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 @@
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 @@
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 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;
+ }
}
- return eventName != null && o.eventName != null && eventName.equals(o.eventName);
+ if (eventTag != o.eventTag) {
+ if (eventTag == null || o.eventTag == null) {
+ return false;
+ }
+ if (!eventTag.equals(o.eventTag)) {
+ return false;
+ }
+ }
+ return true;
}
}
@@ -688,11 +791,19 @@
}
}
+ 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
}
}
}
+ 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 @@
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 @@
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 @@
break;
}
if (checkin) {
- pw.print(rec.eventUid);
+ pw.print(rec.eventTag.poolIdx);
} else {
- UserHandle.formatUid(pw, rec.eventUid);
- }
- pw.print(":");
- if (checkin) {
- pw.print(rec.eventNameIdx);
- } 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 @@
}
}
+ 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 @@
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 @@
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();
+ 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();
}
- 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);
- }
- finishIteratingHistoryLocked();
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7425445..68c41fa 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -87,7 +87,7 @@
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 @@
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 @@
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 @@
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 @@
+ " 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
& HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
+
+ addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
+ return;
}
addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
@@ -1719,10 +1782,8 @@
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 @@
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 @@
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 @@
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 @@
// 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 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 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 @@
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 @@
}
@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 @@
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 @@
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: "