Loading core/java/com/android/internal/os/BatteryStatsHistory.java +78 −3 Original line number Diff line number Diff line Loading @@ -16,17 +16,23 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.BatteryStats.BitDescription; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.HistoryStepDetails; import android.os.BatteryStats.HistoryTag; import android.os.BatteryStats.MeasuredEnergyDetails; import android.os.Build; import android.os.Parcel; import android.os.ParcelFormatException; import android.os.Process; import android.os.StatFs; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; Loading Loading @@ -209,6 +215,42 @@ public class BatteryStatsHistory { void clear(); } /** * A delegate for android.os.Trace to allow testing static calls. Due to * limitations in Android Tracing (b/153319140), the delegate also records * counter values in system properties which allows reading the value at the * start of a tracing session. This overhead is limited to userdebug builds. * On user builds, tracing still occurs but the counter value will be missing * until the first change occurs. */ @VisibleForTesting public static class TraceDelegate { // Note: certain tests currently run as platform_app which is not allowed // to set debug system properties. To ensure that system properties are set // only when allowed, we check the current UID. private final boolean mShouldSetProperty = Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID); /** * Returns true if trace counters should be recorded. */ public boolean tracingEnabled() { return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty; } /** * Records the counter value with the given name. */ public void traceCounter(@NonNull String name, int value) { Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value); if (mShouldSetProperty) { SystemProperties.set("debug.tracing." + name, Integer.toString(value)); } } } private TraceDelegate mTracer; /** * Constructor * Loading @@ -219,19 +261,20 @@ public class BatteryStatsHistory { public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock); stepDetailsCalculator, clock, new TraceDelegate()); initHistoryBuffer(); } @VisibleForTesting public BatteryStatsHistory(Parcel historyBuffer, File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) { mHistoryBuffer = historyBuffer; mSystemDir = systemDir; mMaxHistoryFiles = maxHistoryFiles; mMaxHistoryBufferSize = maxHistoryBufferSize; mStepDetailsCalculator = stepDetailsCalculator; mTracer = tracer; mClock = clock; mHistoryDir = new File(systemDir, HISTORY_DIR); Loading Loading @@ -272,6 +315,7 @@ public class BatteryStatsHistory { public BatteryStatsHistory(HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mStepDetailsCalculator = stepDetailsCalculator; mTracer = new TraceDelegate(); mClock = clock; mHistoryBuffer = Parcel.obtain(); Loading @@ -287,6 +331,7 @@ public class BatteryStatsHistory { private BatteryStatsHistory(Parcel historyBuffer, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mHistoryBuffer = historyBuffer; mTracer = new TraceDelegate(); mClock = clock; mSystemDir = null; mHistoryDir = null; Loading Loading @@ -338,7 +383,7 @@ public class BatteryStatsHistory { // Make a copy of battery history to avoid concurrent modification. Parcel historyBuffer = Parcel.obtain(); historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null); return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null, mTracer); } /** Loading Loading @@ -1119,6 +1164,30 @@ public class BatteryStatsHistory { writeHistoryItem(elapsedRealtimeMs, uptimeMs); } /** * Writes changes to a HistoryItem state bitmap to Atrace. */ private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) { if (!mTracer.tracingEnabled()) return; int diff = oldval ^ newval; if (diff == 0) return; for (int i = 0; i < descriptions.length; i++) { BitDescription bd = descriptions[i]; if ((diff & bd.mask) == 0) continue; int value; if (bd.shift < 0) { value = (newval & bd.mask) != 0 ? 1 : 0; } else { value = (newval & bd.mask) >> bd.shift; } mTracer.traceCounter("battery_stats." + bd.name, value); } } /** * Writes the current history item to history. */ Loading Loading @@ -1159,6 +1228,12 @@ public class BatteryStatsHistory { + Integer.toHexString(diffStates2) + " lastDiff2=" + Integer.toHexString(lastDiffStates2)); } recordTraceCounters(mHistoryLastWritten.states, cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS); recordTraceCounters(mHistoryLastWritten.states2, cur.states2 & mActiveHistoryStates2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS); if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0 && (diffStates2 & lastDiffStates2) == 0 Loading services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +64 −2 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.MeasuredEnergyDetails; import android.os.Parcel; import android.util.Log; Loading @@ -40,7 +41,9 @@ import com.android.internal.os.Clock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.File; Loading @@ -63,6 +66,8 @@ public class BatteryStatsHistoryTest { private final Clock mClock = new MockClock(); private BatteryStatsHistory mHistory; @Mock private BatteryStatsHistory.TraceDelegate mTracer; @Mock private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator; @Before Loading @@ -79,12 +84,69 @@ public class BatteryStatsHistoryTest { } mHistoryDir.delete(); mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, mStepDetailsCalculator, mClock); mStepDetailsCalculator, mClock, mTracer); when(mStepDetailsCalculator.getHistoryStepDetails()) .thenReturn(new BatteryStats.HistoryStepDetails()); } @Test public void testAtraceBinaryState1() { mHistory.forceRecordAllHistory(); InOrder inOrder = Mockito.inOrder(mTracer); Mockito.when(mTracer.tracingEnabled()).thenReturn(true); mHistory.recordStateStartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); mHistory.recordStateStopEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); mHistory.recordStateStartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1); inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 0); inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1); } @Test public void testAtraceBinaryState2() { mHistory.forceRecordAllHistory(); InOrder inOrder = Mockito.inOrder(mTracer); Mockito.when(mTracer.tracingEnabled()).thenReturn(true); mHistory.recordState2StartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG); mHistory.recordState2StopEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG); mHistory.recordState2StartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG); inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1); inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 0); inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1); } @Test public void testAtraceNumericalState() { mHistory.forceRecordAllHistory(); InOrder inOrder = Mockito.inOrder(mTracer); Mockito.when(mTracer.tracingEnabled()).thenReturn(true); mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), 1); mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), 2); mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), 3); inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 1); inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 2); inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 3); } @Test public void testConstruct() { createActiveFile(mHistory); Loading Loading @@ -131,7 +193,7 @@ public class BatteryStatsHistoryTest { // create a new BatteryStatsHistory object, it will pick up existing history files. BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, null, mClock); null, mClock, mTracer); // verify constructor can pick up all files from file system. verifyFileNumbers(history2, fileList); verifyActiveFile(history2, "33.bin"); Loading Loading
core/java/com/android/internal/os/BatteryStatsHistory.java +78 −3 Original line number Diff line number Diff line Loading @@ -16,17 +16,23 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.BatteryStats.BitDescription; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.HistoryStepDetails; import android.os.BatteryStats.HistoryTag; import android.os.BatteryStats.MeasuredEnergyDetails; import android.os.Build; import android.os.Parcel; import android.os.ParcelFormatException; import android.os.Process; import android.os.StatFs; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; Loading Loading @@ -209,6 +215,42 @@ public class BatteryStatsHistory { void clear(); } /** * A delegate for android.os.Trace to allow testing static calls. Due to * limitations in Android Tracing (b/153319140), the delegate also records * counter values in system properties which allows reading the value at the * start of a tracing session. This overhead is limited to userdebug builds. * On user builds, tracing still occurs but the counter value will be missing * until the first change occurs. */ @VisibleForTesting public static class TraceDelegate { // Note: certain tests currently run as platform_app which is not allowed // to set debug system properties. To ensure that system properties are set // only when allowed, we check the current UID. private final boolean mShouldSetProperty = Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID); /** * Returns true if trace counters should be recorded. */ public boolean tracingEnabled() { return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty; } /** * Records the counter value with the given name. */ public void traceCounter(@NonNull String name, int value) { Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value); if (mShouldSetProperty) { SystemProperties.set("debug.tracing." + name, Integer.toString(value)); } } } private TraceDelegate mTracer; /** * Constructor * Loading @@ -219,19 +261,20 @@ public class BatteryStatsHistory { public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock); stepDetailsCalculator, clock, new TraceDelegate()); initHistoryBuffer(); } @VisibleForTesting public BatteryStatsHistory(Parcel historyBuffer, File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) { mHistoryBuffer = historyBuffer; mSystemDir = systemDir; mMaxHistoryFiles = maxHistoryFiles; mMaxHistoryBufferSize = maxHistoryBufferSize; mStepDetailsCalculator = stepDetailsCalculator; mTracer = tracer; mClock = clock; mHistoryDir = new File(systemDir, HISTORY_DIR); Loading Loading @@ -272,6 +315,7 @@ public class BatteryStatsHistory { public BatteryStatsHistory(HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mStepDetailsCalculator = stepDetailsCalculator; mTracer = new TraceDelegate(); mClock = clock; mHistoryBuffer = Parcel.obtain(); Loading @@ -287,6 +331,7 @@ public class BatteryStatsHistory { private BatteryStatsHistory(Parcel historyBuffer, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) { mHistoryBuffer = historyBuffer; mTracer = new TraceDelegate(); mClock = clock; mSystemDir = null; mHistoryDir = null; Loading Loading @@ -338,7 +383,7 @@ public class BatteryStatsHistory { // Make a copy of battery history to avoid concurrent modification. Parcel historyBuffer = Parcel.obtain(); historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null); return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null, mTracer); } /** Loading Loading @@ -1119,6 +1164,30 @@ public class BatteryStatsHistory { writeHistoryItem(elapsedRealtimeMs, uptimeMs); } /** * Writes changes to a HistoryItem state bitmap to Atrace. */ private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) { if (!mTracer.tracingEnabled()) return; int diff = oldval ^ newval; if (diff == 0) return; for (int i = 0; i < descriptions.length; i++) { BitDescription bd = descriptions[i]; if ((diff & bd.mask) == 0) continue; int value; if (bd.shift < 0) { value = (newval & bd.mask) != 0 ? 1 : 0; } else { value = (newval & bd.mask) >> bd.shift; } mTracer.traceCounter("battery_stats." + bd.name, value); } } /** * Writes the current history item to history. */ Loading Loading @@ -1159,6 +1228,12 @@ public class BatteryStatsHistory { + Integer.toHexString(diffStates2) + " lastDiff2=" + Integer.toHexString(lastDiffStates2)); } recordTraceCounters(mHistoryLastWritten.states, cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS); recordTraceCounters(mHistoryLastWritten.states2, cur.states2 & mActiveHistoryStates2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS); if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0 && (diffStates2 & lastDiffStates2) == 0 Loading
services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +64 −2 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.MeasuredEnergyDetails; import android.os.Parcel; import android.util.Log; Loading @@ -40,7 +41,9 @@ import com.android.internal.os.Clock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.File; Loading @@ -63,6 +66,8 @@ public class BatteryStatsHistoryTest { private final Clock mClock = new MockClock(); private BatteryStatsHistory mHistory; @Mock private BatteryStatsHistory.TraceDelegate mTracer; @Mock private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator; @Before Loading @@ -79,12 +84,69 @@ public class BatteryStatsHistoryTest { } mHistoryDir.delete(); mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, mStepDetailsCalculator, mClock); mStepDetailsCalculator, mClock, mTracer); when(mStepDetailsCalculator.getHistoryStepDetails()) .thenReturn(new BatteryStats.HistoryStepDetails()); } @Test public void testAtraceBinaryState1() { mHistory.forceRecordAllHistory(); InOrder inOrder = Mockito.inOrder(mTracer); Mockito.when(mTracer.tracingEnabled()).thenReturn(true); mHistory.recordStateStartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); mHistory.recordStateStopEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); mHistory.recordStateStartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG); inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1); inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 0); inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1); } @Test public void testAtraceBinaryState2() { mHistory.forceRecordAllHistory(); InOrder inOrder = Mockito.inOrder(mTracer); Mockito.when(mTracer.tracingEnabled()).thenReturn(true); mHistory.recordState2StartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG); mHistory.recordState2StopEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG); mHistory.recordState2StartEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG); inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1); inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 0); inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1); } @Test public void testAtraceNumericalState() { mHistory.forceRecordAllHistory(); InOrder inOrder = Mockito.inOrder(mTracer); Mockito.when(mTracer.tracingEnabled()).thenReturn(true); mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), 1); mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), 2); mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(), 3); inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 1); inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 2); inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 3); } @Test public void testConstruct() { createActiveFile(mHistory); Loading Loading @@ -131,7 +193,7 @@ public class BatteryStatsHistoryTest { // create a new BatteryStatsHistory object, it will pick up existing history files. BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024, null, mClock); null, mClock, mTracer); // verify constructor can pick up all files from file system. verifyFileNumbers(history2, fileList); verifyActiveFile(history2, "33.bin"); Loading