Loading services/core/java/com/android/server/power/stats/AggregatedPowerStats.java +68 −13 Original line number Diff line number Diff line Loading @@ -16,16 +16,21 @@ package com.android.server.power.stats; import android.annotation.CurrentTimeMillisLong; import android.annotation.DurationMillisLong; import android.os.UserHandle; import android.text.format.DateFormat; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.TimeUtils; import com.android.internal.os.PowerStats; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** Loading @@ -33,10 +38,16 @@ import java.util.Set; * etc) covering a specific period of power usage history. */ class AggregatedPowerStats { private static final String TAG = "AggregatedPowerStats"; private static final int MAX_CLOCK_UPDATES = 100; private final PowerComponentAggregatedPowerStats[] mPowerComponentStats; // See MonotonicClock private long mStartTime; static class ClockUpdate { public long monotonicTime; @CurrentTimeMillisLong public long currentTime; } private final List<ClockUpdate> mClockUpdates = new ArrayList<>(); @DurationMillisLong private long mDurationMs; Loading @@ -46,17 +57,39 @@ class AggregatedPowerStats { } /** * @param startTime monotonic time * Records a mapping of monotonic time to wall-clock time. Since wall-clock time can change, * there may be multiple clock updates in one set of aggregated stats. * * @param monotonicTime monotonic time in milliseconds, see * {@link com.android.internal.os.MonotonicClock} * @param currentTime current time in milliseconds, see {@link System#currentTimeMillis()} */ void setStartTime(long startTime) { mStartTime = startTime; void addClockUpdate(long monotonicTime, @CurrentTimeMillisLong long currentTime) { ClockUpdate clockUpdate = new ClockUpdate(); clockUpdate.monotonicTime = monotonicTime; clockUpdate.currentTime = currentTime; if (mClockUpdates.size() < MAX_CLOCK_UPDATES) { mClockUpdates.add(clockUpdate); } else { Slog.i(TAG, "Too many clock updates. Replacing the previous update with " + DateFormat.format("yyyy-MM-dd-HH-mm-ss", currentTime)); mClockUpdates.set(mClockUpdates.size() - 1, clockUpdate); } } /** * Start time according to {@link com.android.internal.os.MonotonicClock} */ public long getStartTime() { return mStartTime; long getStartTime() { if (mClockUpdates.isEmpty()) { return 0; } else { return mClockUpdates.get(0).monotonicTime; } } List<ClockUpdate> getClockUpdates() { return mClockUpdates; } void setDuration(long durationMs) { Loading Loading @@ -110,7 +143,7 @@ class AggregatedPowerStats { } void reset() { mStartTime = 0; mClockUpdates.clear(); mDurationMs = 0; for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) { stats.reset(); Loading @@ -119,11 +152,33 @@ class AggregatedPowerStats { void dump(PrintWriter pw) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw); ipw.print("Start time: "); ipw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartTime)); ipw.print(" duration: "); ipw.print(mDurationMs); ipw.println(); StringBuilder sb = new StringBuilder(); long baseTime = 0; for (int i = 0; i < mClockUpdates.size(); i++) { ClockUpdate clockUpdate = mClockUpdates.get(i); sb.setLength(0); if (i == 0) { baseTime = clockUpdate.monotonicTime; sb.append("Start time: ") .append(DateFormat.format("yyyy-MM-dd-HH-mm-ss", clockUpdate.currentTime)) .append(" (") .append(baseTime) .append(") duration: ") .append(mDurationMs); ipw.println(sb); } else { sb.setLength(0); sb.append("Clock update: "); TimeUtils.formatDuration( clockUpdate.monotonicTime - baseTime, sb, TimeUtils.HUNDRED_DAY_FIELD_LEN + 3); sb.append(" ").append( DateFormat.format("yyyy-MM-dd-HH-mm-ss", clockUpdate.currentTime)); ipw.increaseIndent(); ipw.println(sb); ipw.decreaseIndent(); } } ipw.println("Device"); ipw.increaseIndent(); Loading services/core/java/com/android/server/power/stats/PowerStatsAggregator.java +5 −2 Original line number Diff line number Diff line Loading @@ -96,8 +96,11 @@ class PowerStatsAggregator { BatteryStats.HistoryItem item = iterator.next(); if (baseTime < 0) { mStats.setStartTime(item.time); mStats.addClockUpdate(item.time, item.currentTime); baseTime = item.time; } else if (item.cmd == BatteryStats.HistoryItem.CMD_CURRENT_TIME || item.cmd == BatteryStats.HistoryItem.CMD_RESET) { mStats.addClockUpdate(item.time, item.currentTime); } lastTime = item.time; Loading Loading @@ -128,7 +131,7 @@ class PowerStatsAggregator { mStats.setDuration(lastTime - baseTime); consumer.accept(mStats); mStats.reset(); mStats.setStartTime(item.time); mStats.addClockUpdate(item.time, item.currentTime); baseTime = lastTime = item.time; } mStats.addPowerStats(item.powerStats, item.time); Loading services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java +32 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import static org.mockito.Mockito.mock; import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.PersistableBundle; import android.text.format.DateFormat; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; Loading @@ -37,6 +39,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.text.ParseException; import java.util.Calendar; import java.util.List; import java.util.TimeZone; @RunWith(AndroidJUnit4.class) @SmallTest Loading Loading @@ -71,6 +76,8 @@ public class PowerStatsAggregatorTest { @Test public void stateUpdates() { mClock.currentTime = 1222156800000L; // An important date in world history mHistory.forceRecordAllHistory(); mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 10, /* plugged */ true); mHistory.recordStateStartEvent(mClock.realtime, mClock.uptime, Loading @@ -97,7 +104,12 @@ public class PowerStatsAggregatorTest { mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, TEST_UID, BatteryConsumer.PROCESS_STATE_BACKGROUND); advance(3000); advance(1000); mClock.currentTime += 60 * 60 * 1000; // one hour mHistory.recordCurrentTimeChange(mClock.realtime, mClock.uptime, mClock.currentTime); advance(2000); powerStats.stats = new long[]{20000}; powerStats.uidStats.put(TEST_UID, new long[]{4444}); Loading @@ -106,6 +118,18 @@ public class PowerStatsAggregatorTest { mAggregator.aggregateBatteryStats(0, 0, stats -> { assertThat(mAggregatedStatsCount++).isEqualTo(0); assertThat(stats.getStartTime()).isEqualTo(START_TIME); List<AggregatedPowerStats.ClockUpdate> clockUpdates = stats.getClockUpdates(); assertThat(clockUpdates).hasSize(2); AggregatedPowerStats.ClockUpdate clockUpdate0 = clockUpdates.get(0); assertThat(clockUpdate0.monotonicTime).isEqualTo(1234); assertThat(formatDateTime(clockUpdate0.currentTime)).isEqualTo("2008-09-23 08:00:00"); AggregatedPowerStats.ClockUpdate clockUpdate1 = clockUpdates.get(1); assertThat(clockUpdate1.monotonicTime).isEqualTo(1234 + 3000); assertThat(formatDateTime(clockUpdate1.currentTime)).isEqualTo("2008-09-23 09:00:03"); assertThat(stats.getDuration()).isEqualTo(5000); long[] values = new long[1]; Loading Loading @@ -148,6 +172,13 @@ public class PowerStatsAggregatorTest { }); } @NonNull private static CharSequence formatDateTime(long timeInMillis) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); cal.setTimeInMillis(timeInMillis); return DateFormat.format("yyyy-MM-dd hh:mm:ss", cal); } @Test public void incompatiblePowerStats() { mHistory.forceRecordAllHistory(); Loading Loading
services/core/java/com/android/server/power/stats/AggregatedPowerStats.java +68 −13 Original line number Diff line number Diff line Loading @@ -16,16 +16,21 @@ package com.android.server.power.stats; import android.annotation.CurrentTimeMillisLong; import android.annotation.DurationMillisLong; import android.os.UserHandle; import android.text.format.DateFormat; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.TimeUtils; import com.android.internal.os.PowerStats; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** Loading @@ -33,10 +38,16 @@ import java.util.Set; * etc) covering a specific period of power usage history. */ class AggregatedPowerStats { private static final String TAG = "AggregatedPowerStats"; private static final int MAX_CLOCK_UPDATES = 100; private final PowerComponentAggregatedPowerStats[] mPowerComponentStats; // See MonotonicClock private long mStartTime; static class ClockUpdate { public long monotonicTime; @CurrentTimeMillisLong public long currentTime; } private final List<ClockUpdate> mClockUpdates = new ArrayList<>(); @DurationMillisLong private long mDurationMs; Loading @@ -46,17 +57,39 @@ class AggregatedPowerStats { } /** * @param startTime monotonic time * Records a mapping of monotonic time to wall-clock time. Since wall-clock time can change, * there may be multiple clock updates in one set of aggregated stats. * * @param monotonicTime monotonic time in milliseconds, see * {@link com.android.internal.os.MonotonicClock} * @param currentTime current time in milliseconds, see {@link System#currentTimeMillis()} */ void setStartTime(long startTime) { mStartTime = startTime; void addClockUpdate(long monotonicTime, @CurrentTimeMillisLong long currentTime) { ClockUpdate clockUpdate = new ClockUpdate(); clockUpdate.monotonicTime = monotonicTime; clockUpdate.currentTime = currentTime; if (mClockUpdates.size() < MAX_CLOCK_UPDATES) { mClockUpdates.add(clockUpdate); } else { Slog.i(TAG, "Too many clock updates. Replacing the previous update with " + DateFormat.format("yyyy-MM-dd-HH-mm-ss", currentTime)); mClockUpdates.set(mClockUpdates.size() - 1, clockUpdate); } } /** * Start time according to {@link com.android.internal.os.MonotonicClock} */ public long getStartTime() { return mStartTime; long getStartTime() { if (mClockUpdates.isEmpty()) { return 0; } else { return mClockUpdates.get(0).monotonicTime; } } List<ClockUpdate> getClockUpdates() { return mClockUpdates; } void setDuration(long durationMs) { Loading Loading @@ -110,7 +143,7 @@ class AggregatedPowerStats { } void reset() { mStartTime = 0; mClockUpdates.clear(); mDurationMs = 0; for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) { stats.reset(); Loading @@ -119,11 +152,33 @@ class AggregatedPowerStats { void dump(PrintWriter pw) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw); ipw.print("Start time: "); ipw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartTime)); ipw.print(" duration: "); ipw.print(mDurationMs); ipw.println(); StringBuilder sb = new StringBuilder(); long baseTime = 0; for (int i = 0; i < mClockUpdates.size(); i++) { ClockUpdate clockUpdate = mClockUpdates.get(i); sb.setLength(0); if (i == 0) { baseTime = clockUpdate.monotonicTime; sb.append("Start time: ") .append(DateFormat.format("yyyy-MM-dd-HH-mm-ss", clockUpdate.currentTime)) .append(" (") .append(baseTime) .append(") duration: ") .append(mDurationMs); ipw.println(sb); } else { sb.setLength(0); sb.append("Clock update: "); TimeUtils.formatDuration( clockUpdate.monotonicTime - baseTime, sb, TimeUtils.HUNDRED_DAY_FIELD_LEN + 3); sb.append(" ").append( DateFormat.format("yyyy-MM-dd-HH-mm-ss", clockUpdate.currentTime)); ipw.increaseIndent(); ipw.println(sb); ipw.decreaseIndent(); } } ipw.println("Device"); ipw.increaseIndent(); Loading
services/core/java/com/android/server/power/stats/PowerStatsAggregator.java +5 −2 Original line number Diff line number Diff line Loading @@ -96,8 +96,11 @@ class PowerStatsAggregator { BatteryStats.HistoryItem item = iterator.next(); if (baseTime < 0) { mStats.setStartTime(item.time); mStats.addClockUpdate(item.time, item.currentTime); baseTime = item.time; } else if (item.cmd == BatteryStats.HistoryItem.CMD_CURRENT_TIME || item.cmd == BatteryStats.HistoryItem.CMD_RESET) { mStats.addClockUpdate(item.time, item.currentTime); } lastTime = item.time; Loading Loading @@ -128,7 +131,7 @@ class PowerStatsAggregator { mStats.setDuration(lastTime - baseTime); consumer.accept(mStats); mStats.reset(); mStats.setStartTime(item.time); mStats.addClockUpdate(item.time, item.currentTime); baseTime = lastTime = item.time; } mStats.addPowerStats(item.powerStats, item.time); Loading
services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java +32 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import static org.mockito.Mockito.mock; import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.PersistableBundle; import android.text.format.DateFormat; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; Loading @@ -37,6 +39,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.text.ParseException; import java.util.Calendar; import java.util.List; import java.util.TimeZone; @RunWith(AndroidJUnit4.class) @SmallTest Loading Loading @@ -71,6 +76,8 @@ public class PowerStatsAggregatorTest { @Test public void stateUpdates() { mClock.currentTime = 1222156800000L; // An important date in world history mHistory.forceRecordAllHistory(); mHistory.recordBatteryState(mClock.realtime, mClock.uptime, 10, /* plugged */ true); mHistory.recordStateStartEvent(mClock.realtime, mClock.uptime, Loading @@ -97,7 +104,12 @@ public class PowerStatsAggregatorTest { mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, TEST_UID, BatteryConsumer.PROCESS_STATE_BACKGROUND); advance(3000); advance(1000); mClock.currentTime += 60 * 60 * 1000; // one hour mHistory.recordCurrentTimeChange(mClock.realtime, mClock.uptime, mClock.currentTime); advance(2000); powerStats.stats = new long[]{20000}; powerStats.uidStats.put(TEST_UID, new long[]{4444}); Loading @@ -106,6 +118,18 @@ public class PowerStatsAggregatorTest { mAggregator.aggregateBatteryStats(0, 0, stats -> { assertThat(mAggregatedStatsCount++).isEqualTo(0); assertThat(stats.getStartTime()).isEqualTo(START_TIME); List<AggregatedPowerStats.ClockUpdate> clockUpdates = stats.getClockUpdates(); assertThat(clockUpdates).hasSize(2); AggregatedPowerStats.ClockUpdate clockUpdate0 = clockUpdates.get(0); assertThat(clockUpdate0.monotonicTime).isEqualTo(1234); assertThat(formatDateTime(clockUpdate0.currentTime)).isEqualTo("2008-09-23 08:00:00"); AggregatedPowerStats.ClockUpdate clockUpdate1 = clockUpdates.get(1); assertThat(clockUpdate1.monotonicTime).isEqualTo(1234 + 3000); assertThat(formatDateTime(clockUpdate1.currentTime)).isEqualTo("2008-09-23 09:00:03"); assertThat(stats.getDuration()).isEqualTo(5000); long[] values = new long[1]; Loading Loading @@ -148,6 +172,13 @@ public class PowerStatsAggregatorTest { }); } @NonNull private static CharSequence formatDateTime(long timeInMillis) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); cal.setTimeInMillis(timeInMillis); return DateFormat.format("yyyy-MM-dd hh:mm:ss", cal); } @Test public void incompatiblePowerStats() { mHistory.forceRecordAllHistory(); Loading