Loading core/java/android/os/BatteryStats.java +23 −5 Original line number Diff line number Diff line Loading @@ -1655,6 +1655,8 @@ public abstract class BatteryStats { public abstract long[] getCpuFreqs(); public final static class HistoryTag { public static final int HISTORY_TAG_POOL_OVERFLOW = -1; public String string; public int uid; Loading Loading @@ -6786,10 +6788,11 @@ public abstract class BatteryStats { if (bd.mask == HistoryItem.STATE_WAKE_LOCK_FLAG && wakelockTag != null) { didWake = true; sb.append("="); if (longNames) { if (longNames || wakelockTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { UserHandle.formatUid(sb, wakelockTag.uid); sb.append(":\""); sb.append(wakelockTag.string); sb.append(wakelockTag.string.replace("\"", "\"\"")); sb.append("\""); } else { sb.append(wakelockTag.poolIdx); Loading @@ -6809,7 +6812,7 @@ public abstract class BatteryStats { } if (!didWake && wakelockTag != null) { sb.append(longNames ? " wake_lock=" : ",w="); if (longNames) { if (longNames || wakelockTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { UserHandle.formatUid(sb, wakelockTag.uid); sb.append(":\""); sb.append(wakelockTag.string); Loading Loading @@ -7070,7 +7073,14 @@ public abstract class BatteryStats { if (rec.wakeReasonTag != null) { if (checkin) { item.append(",wr="); if (rec.wakeReasonTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { item.append(sUidToString.applyAsString(rec.wakeReasonTag.uid)); item.append(":\""); item.append(rec.wakeReasonTag.string.replace("\"", "\"\"")); item.append("\""); } else { item.append(rec.wakeReasonTag.poolIdx); } } else { item.append(" wake_reason="); item.append(rec.wakeReasonTag.uid); Loading Loading @@ -7098,7 +7108,15 @@ public abstract class BatteryStats { } item.append("="); if (checkin) { if (rec.eventTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { item.append(HISTORY_EVENT_INT_FORMATTERS[idx] .applyAsString(rec.eventTag.uid)); item.append(":\""); item.append(rec.eventTag.string.replace("\"", "\"\"")); item.append("\""); } else { item.append(rec.eventTag.poolIdx); } } else { item.append(HISTORY_EVENT_INT_FORMATTERS[idx] .applyAsString(rec.eventTag.uid)); Loading core/java/com/android/internal/os/BatteryStatsHistory.java +2 −1 Original line number Diff line number Diff line Loading @@ -178,7 +178,7 @@ public class BatteryStatsHistory { private boolean mHaveBatteryLevel; private boolean mRecordingHistory; private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; private final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); Loading Loading @@ -1848,6 +1848,7 @@ public class BatteryStatsHistory { } return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; } else { tag.poolIdx = HistoryTag.HISTORY_TAG_POOL_OVERFLOW; // Tag pool overflow: include the tag itself in the parcel return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; } Loading core/java/com/android/internal/os/BatteryStatsHistoryIterator.java +5 −1 Original line number Diff line number Diff line Loading @@ -309,7 +309,11 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag(); tag.readFromParcel(src); tag.poolIdx = index & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; if (tag.poolIdx < BatteryStatsHistory.HISTORY_TAG_INDEX_LIMIT) { mHistoryTags.put(tag.poolIdx, tag); } else { tag.poolIdx = BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW; } outTag.setTo(tag); } else { Loading services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +89 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.BatteryStatsHistoryIterator; import com.android.internal.os.Clock; import org.junit.Before; import org.junit.Test; Loading @@ -64,8 +63,9 @@ public class BatteryStatsHistoryTest { private final Parcel mHistoryBuffer = Parcel.obtain(); private File mSystemDir; private File mHistoryDir; private final Clock mClock = new MockClock(); private final MockClock mClock = new MockClock(); private BatteryStatsHistory mHistory; private BatteryStats.HistoryPrinter mHistoryPrinter; @Mock private BatteryStatsHistory.TraceDelegate mTracer; @Mock Loading @@ -89,6 +89,8 @@ public class BatteryStatsHistoryTest { when(mStepDetailsCalculator.getHistoryStepDetails()) .thenReturn(new BatteryStats.HistoryStepDetails()); mHistoryPrinter = new BatteryStats.HistoryPrinter(); } @Test Loading Loading @@ -366,11 +368,95 @@ public class BatteryStatsHistoryTest { assertThat(checkin).contains("XC,10321,400,500,600"); } @Test public void largeTagPool() { // Keep the preserved part of history short - we only need to capture the very tail of // history. mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 1, 6000, mStepDetailsCalculator, mClock, mTracer); mHistory.forceRecordAllHistory(); mClock.realtime = 2_000_000; mClock.uptime = 1_000_000; // More than 32k strings final int tagCount = 0x7FFF + 20; for (int tag = 0; tag < tagCount;) { mClock.realtime += 10; mClock.uptime += 10; mHistory.recordEvent(mClock.realtime, mClock.uptime, HistoryItem.EVENT_ALARM_START, "a" + (tag++), 42); mHistory.setBatteryState(true, BatteryManager.BATTERY_STATUS_CHARGING, tag % 50, 0); mClock.realtime += 10; mClock.uptime += 10; mHistory.recordWakelockStartEvent(mClock.realtime, mClock.uptime, "w" + tag, 42); mClock.realtime += 10; mClock.uptime += 10; mHistory.recordWakelockStopEvent(mClock.realtime, mClock.uptime, "w" + tag, 42); tag++; mHistory.recordWakeupEvent(mClock.realtime, mClock.uptime, "wr" + (tag++)); } int eventTagsPooled = 0; int eventTagsUnpooled = 0; int wakelockTagsPooled = 0; int wakelockTagsUnpooled = 0; int wakeReasonTagsPooled = 0; int wakeReasonTagsUnpooled = 0; for (BatteryStatsHistoryIterator iterator = mHistory.iterate(); iterator.hasNext(); ) { HistoryItem item = iterator.next(); if (item.cmd != HistoryItem.CMD_UPDATE) { continue; } String checkinDump = toString(item, true); if (item.eventCode == HistoryItem.EVENT_ALARM_START) { if (item.eventTag.poolIdx != BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { eventTagsPooled++; assertThat(checkinDump).contains("+Eal=" + item.eventTag.poolIdx); } else { eventTagsUnpooled++; assertThat(checkinDump).contains("+Eal=42:\"" + item.eventTag.string + "\""); } } if (item.wakelockTag != null) { if (item.wakelockTag.poolIdx != BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { wakelockTagsPooled++; assertThat(checkinDump).contains("w=" + item.wakelockTag.poolIdx); } else { wakelockTagsUnpooled++; assertThat(checkinDump).contains("w=42:\"" + item.wakelockTag.string + "\""); } } if (item.wakeReasonTag != null) { if (item.wakeReasonTag.poolIdx != BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { wakeReasonTagsPooled++; assertThat(checkinDump).contains("wr=" + item.wakeReasonTag.poolIdx); } else { wakeReasonTagsUnpooled++; assertThat(checkinDump).contains("wr=0:\"" + item.wakeReasonTag.string + "\""); } } } // Self-check - ensure that we have all cases represented in the test assertThat(eventTagsPooled).isGreaterThan(0); assertThat(eventTagsUnpooled).isGreaterThan(0); assertThat(wakelockTagsPooled).isGreaterThan(0); assertThat(wakelockTagsUnpooled).isGreaterThan(0); assertThat(wakeReasonTagsPooled).isGreaterThan(0); assertThat(wakeReasonTagsUnpooled).isGreaterThan(0); } private String toString(BatteryStats.HistoryItem item, boolean checkin) { BatteryStats.HistoryPrinter printer = new BatteryStats.HistoryPrinter(); StringWriter writer = new StringWriter(); PrintWriter pw = new PrintWriter(writer); printer.printNextItem(pw, item, 0, checkin, /* verbose */ true); mHistoryPrinter.printNextItem(pw, item, 0, checkin, /* verbose */ false); pw.flush(); return writer.toString(); } Loading Loading
core/java/android/os/BatteryStats.java +23 −5 Original line number Diff line number Diff line Loading @@ -1655,6 +1655,8 @@ public abstract class BatteryStats { public abstract long[] getCpuFreqs(); public final static class HistoryTag { public static final int HISTORY_TAG_POOL_OVERFLOW = -1; public String string; public int uid; Loading Loading @@ -6786,10 +6788,11 @@ public abstract class BatteryStats { if (bd.mask == HistoryItem.STATE_WAKE_LOCK_FLAG && wakelockTag != null) { didWake = true; sb.append("="); if (longNames) { if (longNames || wakelockTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { UserHandle.formatUid(sb, wakelockTag.uid); sb.append(":\""); sb.append(wakelockTag.string); sb.append(wakelockTag.string.replace("\"", "\"\"")); sb.append("\""); } else { sb.append(wakelockTag.poolIdx); Loading @@ -6809,7 +6812,7 @@ public abstract class BatteryStats { } if (!didWake && wakelockTag != null) { sb.append(longNames ? " wake_lock=" : ",w="); if (longNames) { if (longNames || wakelockTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { UserHandle.formatUid(sb, wakelockTag.uid); sb.append(":\""); sb.append(wakelockTag.string); Loading Loading @@ -7070,7 +7073,14 @@ public abstract class BatteryStats { if (rec.wakeReasonTag != null) { if (checkin) { item.append(",wr="); if (rec.wakeReasonTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { item.append(sUidToString.applyAsString(rec.wakeReasonTag.uid)); item.append(":\""); item.append(rec.wakeReasonTag.string.replace("\"", "\"\"")); item.append("\""); } else { item.append(rec.wakeReasonTag.poolIdx); } } else { item.append(" wake_reason="); item.append(rec.wakeReasonTag.uid); Loading Loading @@ -7098,7 +7108,15 @@ public abstract class BatteryStats { } item.append("="); if (checkin) { if (rec.eventTag.poolIdx == HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { item.append(HISTORY_EVENT_INT_FORMATTERS[idx] .applyAsString(rec.eventTag.uid)); item.append(":\""); item.append(rec.eventTag.string.replace("\"", "\"\"")); item.append("\""); } else { item.append(rec.eventTag.poolIdx); } } else { item.append(HISTORY_EVENT_INT_FORMATTERS[idx] .applyAsString(rec.eventTag.uid)); Loading
core/java/com/android/internal/os/BatteryStatsHistory.java +2 −1 Original line number Diff line number Diff line Loading @@ -178,7 +178,7 @@ public class BatteryStatsHistory { private boolean mHaveBatteryLevel; private boolean mRecordingHistory; private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; private final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>(); Loading Loading @@ -1848,6 +1848,7 @@ public class BatteryStatsHistory { } return idx | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; } else { tag.poolIdx = HistoryTag.HISTORY_TAG_POOL_OVERFLOW; // Tag pool overflow: include the tag itself in the parcel return HISTORY_TAG_INDEX_LIMIT | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; } Loading
core/java/com/android/internal/os/BatteryStatsHistoryIterator.java +5 −1 Original line number Diff line number Diff line Loading @@ -309,7 +309,11 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag(); tag.readFromParcel(src); tag.poolIdx = index & ~BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG; if (tag.poolIdx < BatteryStatsHistory.HISTORY_TAG_INDEX_LIMIT) { mHistoryTags.put(tag.poolIdx, tag); } else { tag.poolIdx = BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW; } outTag.setTo(tag); } else { Loading
services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +89 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.BatteryStatsHistoryIterator; import com.android.internal.os.Clock; import org.junit.Before; import org.junit.Test; Loading @@ -64,8 +63,9 @@ public class BatteryStatsHistoryTest { private final Parcel mHistoryBuffer = Parcel.obtain(); private File mSystemDir; private File mHistoryDir; private final Clock mClock = new MockClock(); private final MockClock mClock = new MockClock(); private BatteryStatsHistory mHistory; private BatteryStats.HistoryPrinter mHistoryPrinter; @Mock private BatteryStatsHistory.TraceDelegate mTracer; @Mock Loading @@ -89,6 +89,8 @@ public class BatteryStatsHistoryTest { when(mStepDetailsCalculator.getHistoryStepDetails()) .thenReturn(new BatteryStats.HistoryStepDetails()); mHistoryPrinter = new BatteryStats.HistoryPrinter(); } @Test Loading Loading @@ -366,11 +368,95 @@ public class BatteryStatsHistoryTest { assertThat(checkin).contains("XC,10321,400,500,600"); } @Test public void largeTagPool() { // Keep the preserved part of history short - we only need to capture the very tail of // history. mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 1, 6000, mStepDetailsCalculator, mClock, mTracer); mHistory.forceRecordAllHistory(); mClock.realtime = 2_000_000; mClock.uptime = 1_000_000; // More than 32k strings final int tagCount = 0x7FFF + 20; for (int tag = 0; tag < tagCount;) { mClock.realtime += 10; mClock.uptime += 10; mHistory.recordEvent(mClock.realtime, mClock.uptime, HistoryItem.EVENT_ALARM_START, "a" + (tag++), 42); mHistory.setBatteryState(true, BatteryManager.BATTERY_STATUS_CHARGING, tag % 50, 0); mClock.realtime += 10; mClock.uptime += 10; mHistory.recordWakelockStartEvent(mClock.realtime, mClock.uptime, "w" + tag, 42); mClock.realtime += 10; mClock.uptime += 10; mHistory.recordWakelockStopEvent(mClock.realtime, mClock.uptime, "w" + tag, 42); tag++; mHistory.recordWakeupEvent(mClock.realtime, mClock.uptime, "wr" + (tag++)); } int eventTagsPooled = 0; int eventTagsUnpooled = 0; int wakelockTagsPooled = 0; int wakelockTagsUnpooled = 0; int wakeReasonTagsPooled = 0; int wakeReasonTagsUnpooled = 0; for (BatteryStatsHistoryIterator iterator = mHistory.iterate(); iterator.hasNext(); ) { HistoryItem item = iterator.next(); if (item.cmd != HistoryItem.CMD_UPDATE) { continue; } String checkinDump = toString(item, true); if (item.eventCode == HistoryItem.EVENT_ALARM_START) { if (item.eventTag.poolIdx != BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { eventTagsPooled++; assertThat(checkinDump).contains("+Eal=" + item.eventTag.poolIdx); } else { eventTagsUnpooled++; assertThat(checkinDump).contains("+Eal=42:\"" + item.eventTag.string + "\""); } } if (item.wakelockTag != null) { if (item.wakelockTag.poolIdx != BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { wakelockTagsPooled++; assertThat(checkinDump).contains("w=" + item.wakelockTag.poolIdx); } else { wakelockTagsUnpooled++; assertThat(checkinDump).contains("w=42:\"" + item.wakelockTag.string + "\""); } } if (item.wakeReasonTag != null) { if (item.wakeReasonTag.poolIdx != BatteryStats.HistoryTag.HISTORY_TAG_POOL_OVERFLOW) { wakeReasonTagsPooled++; assertThat(checkinDump).contains("wr=" + item.wakeReasonTag.poolIdx); } else { wakeReasonTagsUnpooled++; assertThat(checkinDump).contains("wr=0:\"" + item.wakeReasonTag.string + "\""); } } } // Self-check - ensure that we have all cases represented in the test assertThat(eventTagsPooled).isGreaterThan(0); assertThat(eventTagsUnpooled).isGreaterThan(0); assertThat(wakelockTagsPooled).isGreaterThan(0); assertThat(wakelockTagsUnpooled).isGreaterThan(0); assertThat(wakeReasonTagsPooled).isGreaterThan(0); assertThat(wakeReasonTagsUnpooled).isGreaterThan(0); } private String toString(BatteryStats.HistoryItem item, boolean checkin) { BatteryStats.HistoryPrinter printer = new BatteryStats.HistoryPrinter(); StringWriter writer = new StringWriter(); PrintWriter pw = new PrintWriter(writer); printer.printNextItem(pw, item, 0, checkin, /* verbose */ true); mHistoryPrinter.printNextItem(pw, item, 0, checkin, /* verbose */ false); pw.flush(); return writer.toString(); } Loading