Loading core/java/android/os/BatteryStats.java +79 −6 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.content.pm.ApplicationInfo; import android.telephony.SignalStrength; import android.telephony.SignalStrength; import android.text.format.DateFormat; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; import android.util.MutableBoolean; import android.util.MutableBoolean; import android.util.Pair; import android.util.Pair; import android.util.Printer; import android.util.Printer; Loading @@ -47,6 +49,7 @@ import com.android.internal.os.BatteryStatsHelper; * @hide * @hide */ */ public abstract class BatteryStats implements Parcelable { public abstract class BatteryStats implements Parcelable { private static final String TAG = "BatteryStats"; private static final boolean LOCAL_LOGV = false; private static final boolean LOCAL_LOGV = false; Loading Loading @@ -175,8 +178,11 @@ public abstract class BatteryStats implements Parcelable { /** /** * Current version of checkin data format. * Current version of checkin data format. * * New in version 19: * - Wakelock data (wl) gets current and max times. */ */ static final String CHECKIN_VERSION = "18"; static final String CHECKIN_VERSION = "19"; /** /** * Old version, we hit 9 and ran out of room, need to remove. * Old version, we hit 9 and ran out of room, need to remove. Loading Loading @@ -351,6 +357,32 @@ public abstract class BatteryStats implements Parcelable { */ */ public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs); public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs); /** * Returns the max duration if it is being tracked. * Not all Timer subclasses track the max duration and the current duration. */ public long getMaxDurationMsLocked(long elapsedRealtimeMs) { return -1; } /** * Returns the current time the timer has been active, if it is being tracked. * Not all Timer subclasses track the max duration and the current duration. */ public long getCurrentDurationMsLocked(long elapsedRealtimeMs) { return -1; } /** * Returns whether the timer is currently running. Some types of timers * (e.g. BatchTimers) don't know whether the event is currently active, * and report false. */ public boolean isRunningLocked() { return false; } /** /** * Temporary for debugging. * Temporary for debugging. */ */ Loading Loading @@ -2558,6 +2590,22 @@ public abstract class BatteryStats implements Parcelable { sb.append('('); sb.append('('); sb.append(count); sb.append(count); sb.append(" times)"); sb.append(" times)"); final long maxDurationMs = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000); if (maxDurationMs >= 0) { sb.append(" max="); sb.append(maxDurationMs); } if (timer.isRunningLocked()) { final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000); if (currentMs >= 0) { sb.append(" (running for "); sb.append(currentMs); sb.append("ms)"); } else { sb.append(" (running)"); } } return ", "; return ", "; } } } } Loading @@ -2565,6 +2613,7 @@ public abstract class BatteryStats implements Parcelable { } } /** /** * Prints details about a timer, if its total time was greater than 0. * * * @param pw a PrintWriter object to print to. * @param pw a PrintWriter object to print to. * @param sb a StringBuilder object. * @param sb a StringBuilder object. Loading @@ -2573,24 +2622,40 @@ public abstract class BatteryStats implements Parcelable { * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. * @param prefix a String to be prepended to each line of output. * @param prefix a String to be prepended to each line of output. * @param type the name of the timer. * @param type the name of the timer. * @return true if anything was printed. */ */ private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer, private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer, long rawRealtime, int which, String prefix, String type) { long rawRealtimeUs, int which, String prefix, String type) { if (timer != null) { if (timer != null) { // Convert from microseconds to milliseconds with rounding // Convert from microseconds to milliseconds with rounding final long totalTime = (timer.getTotalTimeLocked( final long totalTimeMs = (timer.getTotalTimeLocked( rawRealtime, which) + 500) / 1000; rawRealtimeUs, which) + 500) / 1000; final int count = timer.getCountLocked(which); final int count = timer.getCountLocked(which); if (totalTime != 0) { if (totalTimeMs != 0) { sb.setLength(0); sb.setLength(0); sb.append(prefix); sb.append(prefix); sb.append(" "); sb.append(" "); sb.append(type); sb.append(type); sb.append(": "); sb.append(": "); formatTimeMs(sb, totalTime); formatTimeMs(sb, totalTimeMs); sb.append("realtime ("); sb.append("realtime ("); sb.append(count); sb.append(count); sb.append(" times)"); sb.append(" times)"); final long maxDurationMs = timer.getMaxDurationMsLocked(rawRealtimeUs/1000); if (maxDurationMs >= 0) { sb.append(" max="); sb.append(maxDurationMs); } if (timer.isRunningLocked()) { final long currentMs = timer.getCurrentDurationMsLocked(rawRealtimeUs/1000); if (currentMs >= 0) { sb.append(" (running for "); sb.append(currentMs); sb.append("ms)"); } else { sb.append(" (running)"); } } pw.println(sb.toString()); pw.println(sb.toString()); return true; return true; } } Loading @@ -2613,15 +2678,23 @@ public abstract class BatteryStats implements Parcelable { long elapsedRealtimeUs, String name, int which, String linePrefix) { long elapsedRealtimeUs, String name, int which, String linePrefix) { long totalTimeMicros = 0; long totalTimeMicros = 0; int count = 0; int count = 0; long max = -1; long current = -1; if (timer != null) { if (timer != null) { totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which); totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which); count = timer.getCountLocked(which); count = timer.getCountLocked(which); current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000); max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000); } } sb.append(linePrefix); sb.append(linePrefix); sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding sb.append(','); sb.append(','); sb.append(name != null ? name + "," : ""); sb.append(name != null ? name + "," : ""); sb.append(count); sb.append(count); sb.append(','); sb.append(current); sb.append(','); sb.append(max); return ","; return ","; } } Loading core/java/com/android/internal/os/BatteryStatsImpl.java +220 −18 Original line number Original line Diff line number Diff line Loading @@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version // Current on-disk Parcel version private static final int VERSION = 148 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 149 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -1566,6 +1566,186 @@ public class BatteryStatsImpl extends BatteryStats { } } } } /** * A StopwatchTimer that also tracks the total and max individual * time spent active according to the given timebase. Whereas * StopwatchTimer apportions the time amongst all in the pool, * the total and max durations are not apportioned. */ public static class DurationTimer extends StopwatchTimer { /** * The time (in ms) that the timer was last acquired or the time base * last (re-)started. Increasing the nesting depth does not reset this time. * * -1 if the timer is currently not running or the time base is not running. * * If written to a parcel, the start time is reset, as is mNesting in the base class * StopwatchTimer. */ long mStartTimeMs = -1; /** * The longest time period (in ms) that the timer has been active. */ long mMaxDurationMs; /** * The total time (in ms) that that the timer has been active since reset(). */ long mCurrentDurationMs; public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase, Parcel in) { super(clocks, uid, type, timerPool, timeBase, in); mMaxDurationMs = in.readLong(); } public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase) { super(clocks, uid, type, timerPool, timeBase); } @Override public void writeToParcel(Parcel out, long elapsedRealtimeUs) { super.writeToParcel(out, elapsedRealtimeUs); out.writeLong(mMaxDurationMs); } /** * Write the summary to the parcel. * * Since the time base is probably meaningless after we come back, reading * from this will have the effect of stopping the timer. So here all we write * is the max duration. */ @Override public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) { super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); out.writeLong(mMaxDurationMs); } /** * Read the summary parcel. * * Has the side effect of stopping the timer. */ @Override public void readSummaryFromParcelLocked(Parcel in) { super.readSummaryFromParcelLocked(in); mMaxDurationMs = in.readLong(); mStartTimeMs = -1; mCurrentDurationMs = 0; } /** * The TimeBase time started (again). * * If the timer is also running, store the start time. */ public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) { super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime); if (mNesting > 0) { mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; } } /** * The TimeBase stopped running. * * If the timer is running, add the duration into mCurrentDurationMs. */ @Override public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtime) { super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtime); if (mNesting > 0) { mCurrentDurationMs += (elapsedRealtimeUs / 1000) - mStartTimeMs; } mStartTimeMs = -1; } @Override public void logState(Printer pw, String prefix) { super.logState(pw, prefix); } @Override public void startRunningLocked(long elapsedRealtimeMs) { super.startRunningLocked(elapsedRealtimeMs); if (mNesting == 1 && mTimeBase.isRunning()) { // Just started mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; } } /** * Decrements the mNesting ref-count on this timer. * * If it actually stopped (mNesting went to 0), then possibly update * mMaxDuration if the current duration was the longest ever. */ @Override public void stopRunningLocked(long elapsedRealtimeMs) { super.stopRunningLocked(elapsedRealtimeMs); if (mNesting == 0) { final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs); if (durationMs > mMaxDurationMs) { mMaxDurationMs = durationMs; } mStartTimeMs = -1; mCurrentDurationMs = 0; } } @Override public boolean reset(boolean detachIfReset) { boolean result = super.reset(detachIfReset); mMaxDurationMs = 0; mCurrentDurationMs = 0; if (mNesting > 0) { mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; } else { mStartTimeMs = -1; } return result; } /** * Returns the max duration that this timer has ever seen. * * Note that this time is NOT split between the timers in the timer group that * this timer is attached to. It is the TOTAL time. */ @Override public long getMaxDurationMsLocked(long elapsedRealtimeMs) { if (mNesting > 0) { final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs); if (durationMs > mMaxDurationMs) { return durationMs; } } return mMaxDurationMs; } /** * Returns the time since the timer was started. * * Note that this time is NOT split between the timers in the timer group that * this timer is attached to. It is the TOTAL time. */ @Override public long getCurrentDurationMsLocked(long elapsedRealtimeMs) { long durationMs = mCurrentDurationMs; if (mNesting > 0) { if (mTimeBase.isRunning()) { durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000) - mStartTimeMs; } } return durationMs; } } /** /** * State for keeping track of timing information. * State for keeping track of timing information. */ */ Loading Loading @@ -6535,7 +6715,7 @@ public class BatteryStatsImpl extends BatteryStats { /** /** * How long (in ms) this uid has been keeping the device partially awake. * How long (in ms) this uid has been keeping the device partially awake. */ */ StopwatchTimer mTimerPartial; DurationTimer mTimerPartial; /** /** * How long (in ms) this uid has been keeping the device fully awake. * How long (in ms) this uid has been keeping the device fully awake. Loading Loading @@ -6564,8 +6744,8 @@ public class BatteryStatsImpl extends BatteryStats { * @param in the Parcel to be read from. * @param in the Parcel to be read from. * return a new Timer, or null. * return a new Timer, or null. */ */ private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool, private StopwatchTimer readStopwatchTimerFromParcel(int type, TimeBase timeBase, Parcel in) { ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) { if (in.readInt() == 0) { if (in.readInt() == 0) { return null; return null; } } Loading @@ -6573,6 +6753,22 @@ public class BatteryStatsImpl extends BatteryStats { return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in); return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in); } } /** * Reads a possibly null Timer from a Parcel. The timer is associated with the * proper timer pool from the given BatteryStatsImpl object. * * @param in the Parcel to be read from. * return a new Timer, or null. */ private DurationTimer readDurationTimerFromParcel(int type, ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) { if (in.readInt() == 0) { return null; } return new DurationTimer(mBsi.mClocks, mUid, type, pool, timeBase, in); } boolean reset() { boolean reset() { boolean wlactive = false; boolean wlactive = false; if (mTimerFull != null) { if (mTimerFull != null) { Loading Loading @@ -6609,11 +6805,14 @@ public class BatteryStatsImpl extends BatteryStats { } } void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL, mTimerPartial = readDurationTimerFromParcel(WAKE_TYPE_PARTIAL, mBsi.mPartialTimers, screenOffTimeBase, in); mBsi.mPartialTimers, screenOffTimeBase, in); mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in); mTimerFull = readStopwatchTimerFromParcel(WAKE_TYPE_FULL, mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in); mBsi.mFullTimers, timeBase, in); mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in); mTimerWindow = readStopwatchTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in); mTimerDraw = readStopwatchTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in); } } void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { Loading @@ -6635,40 +6834,43 @@ public class BatteryStatsImpl extends BatteryStats { } } public StopwatchTimer getStopwatchTimer(int type) { public StopwatchTimer getStopwatchTimer(int type) { StopwatchTimer t; switch (type) { switch (type) { case WAKE_TYPE_PARTIAL: case WAKE_TYPE_PARTIAL: { t = mTimerPartial; DurationTimer t = mTimerPartial; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL, t = new DurationTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL, mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase); mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase); mTimerPartial = t; mTimerPartial = t; } } return t; return t; case WAKE_TYPE_FULL: } t = mTimerFull; case WAKE_TYPE_FULL: { StopwatchTimer t = mTimerFull; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL, t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL, mBsi.mFullTimers, mBsi.mOnBatteryTimeBase); mBsi.mFullTimers, mBsi.mOnBatteryTimeBase); mTimerFull = t; mTimerFull = t; } } return t; return t; case WAKE_TYPE_WINDOW: } t = mTimerWindow; case WAKE_TYPE_WINDOW: { StopwatchTimer t = mTimerWindow; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW, t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW, mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase); mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase); mTimerWindow = t; mTimerWindow = t; } } return t; return t; case WAKE_TYPE_DRAW: } t = mTimerDraw; case WAKE_TYPE_DRAW: { StopwatchTimer t = mTimerDraw; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW, t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW, mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase); mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase); mTimerDraw = t; mTimerDraw = t; } } return t; return t; } default: default: throw new IllegalArgumentException("type=" + type); throw new IllegalArgumentException("type=" + type); } } Loading core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java 0 → 100644 +151 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.internal.os; import android.os.BatteryStats; import android.os.Parcel; import android.support.test.filters.SmallTest; import android.util.Log; import junit.framework.TestCase; import org.mockito.Mockito; /** * Test BatteryStatsImpl.DurationTimer. * * In these tests, unless otherwise commented, the time increments by * 2x + 100, to make the subtraction unlikely to alias to another time. */ public class BatteryStatsDurationTimerTest extends TestCase { @SmallTest public void testStartStop() throws Exception { final MockClocks clocks = new MockClocks(); final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase(); timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime()); final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase); // TimeBase running, timer not running: current and max are 0 timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100*1000); assertFalse(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(300)); assertEquals(0, timer.getMaxDurationMsLocked(301)); // Start timer: current and max advance timer.startRunningLocked(700); assertTrue(timer.isRunningLocked()); assertEquals(800, timer.getCurrentDurationMsLocked(1500)); assertEquals(801, timer.getMaxDurationMsLocked(1501)); // Stop timer: current resets to 0, max remains timer.stopRunningLocked(3100); assertFalse(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(6300)); assertEquals(2400, timer.getMaxDurationMsLocked(6301)); // Start time again, but check with a short time, and make sure max doesn't // increment. timer.startRunningLocked(12700); assertTrue(timer.isRunningLocked()); assertEquals(100, timer.getCurrentDurationMsLocked(12800)); assertEquals(2400, timer.getMaxDurationMsLocked(12801)); // And stop it again, but with a short time, and make sure it doesn't increment. timer.stopRunningLocked(12900); assertFalse(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(13000)); assertEquals(2400, timer.getMaxDurationMsLocked(13001)); // Now start and check that the time doesn't increase if the two times are the same. timer.startRunningLocked(27000); assertTrue(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(27000)); assertEquals(2400, timer.getMaxDurationMsLocked(27000)); // Stop the TimeBase. The values should be frozen. timeBase.setRunning(false, /* uptimeUs */ 10, /* realtimeUs */ 55000*1000); assertTrue(timer.isRunningLocked()); assertEquals(28100, timer.getCurrentDurationMsLocked(110100)); // Why 28100 and not 28000? assertEquals(28100, timer.getMaxDurationMsLocked(110101)); // Start the TimeBase. The values should be the old value plus the delta // between when the timer restarted and the current time timeBase.setRunning(true, /* uptimeUs */ 10, /* realtimeUs */ 220100*1000); assertTrue(timer.isRunningLocked()); assertEquals(28300, timer.getCurrentDurationMsLocked(220300)); // extra 100 from above?? assertEquals(28301, timer.getMaxDurationMsLocked(220301)); } @SmallTest public void testReset() throws Exception { } @SmallTest public void testParceling() throws Exception { final MockClocks clocks = new MockClocks(); final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase(); timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime()); final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase); // Start running on battery. clocks.realtime = 100; clocks.uptime = 10; timeBase.setRunning(true, clocks.uptimeMillis()*1000, clocks.elapsedRealtime()*1000); timer.startRunningLocked(300); // Check that it did start running assertEquals(400, timer.getMaxDurationMsLocked(700)); assertEquals(401, timer.getCurrentDurationMsLocked(701)); // Write summary final Parcel summaryParcel = Parcel.obtain(); timer.writeSummaryFromParcelLocked(summaryParcel, 1500*1000); summaryParcel.setDataPosition(0); // Read summary final BatteryStatsImpl.DurationTimer summary = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase); summary.startRunningLocked(3100); summary.readSummaryFromParcelLocked(summaryParcel); // The new one shouldn't be running, and therefore 0 for current time assertFalse(summary.isRunningLocked()); assertEquals(0, summary.getCurrentDurationMsLocked(6300)); // The new one should have the max duration that we had when we wrote it assertEquals(1200, summary.getMaxDurationMsLocked(6301)); // Write full final Parcel fullParcel = Parcel.obtain(); timer.writeToParcel(fullParcel, 1500*1000); fullParcel.setDataPosition(0); // Read full - Should be the same as the summary as far as DurationTimer is concerned. final BatteryStatsImpl.DurationTimer full = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase, fullParcel); // The new one shouldn't be running, and therefore 0 for current time assertFalse(full.isRunningLocked()); assertEquals(0, full.getCurrentDurationMsLocked(6300)); // The new one should have the max duration that we had when we wrote it assertEquals(1200, full.getMaxDurationMsLocked(6301)); } } core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,7 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @RunWith(Suite.class) @Suite.SuiteClasses({ @Suite.SuiteClasses({ BatteryStatsDurationTimerTest.class, BatteryStatsSamplingTimerTest.class, BatteryStatsSamplingTimerTest.class, BatteryStatsServTest.class, BatteryStatsServTest.class, BatteryStatsTimeBaseTest.class, BatteryStatsTimeBaseTest.class, Loading Loading
core/java/android/os/BatteryStats.java +79 −6 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.content.pm.ApplicationInfo; import android.telephony.SignalStrength; import android.telephony.SignalStrength; import android.text.format.DateFormat; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; import android.util.MutableBoolean; import android.util.MutableBoolean; import android.util.Pair; import android.util.Pair; import android.util.Printer; import android.util.Printer; Loading @@ -47,6 +49,7 @@ import com.android.internal.os.BatteryStatsHelper; * @hide * @hide */ */ public abstract class BatteryStats implements Parcelable { public abstract class BatteryStats implements Parcelable { private static final String TAG = "BatteryStats"; private static final boolean LOCAL_LOGV = false; private static final boolean LOCAL_LOGV = false; Loading Loading @@ -175,8 +178,11 @@ public abstract class BatteryStats implements Parcelable { /** /** * Current version of checkin data format. * Current version of checkin data format. * * New in version 19: * - Wakelock data (wl) gets current and max times. */ */ static final String CHECKIN_VERSION = "18"; static final String CHECKIN_VERSION = "19"; /** /** * Old version, we hit 9 and ran out of room, need to remove. * Old version, we hit 9 and ran out of room, need to remove. Loading Loading @@ -351,6 +357,32 @@ public abstract class BatteryStats implements Parcelable { */ */ public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs); public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs); /** * Returns the max duration if it is being tracked. * Not all Timer subclasses track the max duration and the current duration. */ public long getMaxDurationMsLocked(long elapsedRealtimeMs) { return -1; } /** * Returns the current time the timer has been active, if it is being tracked. * Not all Timer subclasses track the max duration and the current duration. */ public long getCurrentDurationMsLocked(long elapsedRealtimeMs) { return -1; } /** * Returns whether the timer is currently running. Some types of timers * (e.g. BatchTimers) don't know whether the event is currently active, * and report false. */ public boolean isRunningLocked() { return false; } /** /** * Temporary for debugging. * Temporary for debugging. */ */ Loading Loading @@ -2558,6 +2590,22 @@ public abstract class BatteryStats implements Parcelable { sb.append('('); sb.append('('); sb.append(count); sb.append(count); sb.append(" times)"); sb.append(" times)"); final long maxDurationMs = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000); if (maxDurationMs >= 0) { sb.append(" max="); sb.append(maxDurationMs); } if (timer.isRunningLocked()) { final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000); if (currentMs >= 0) { sb.append(" (running for "); sb.append(currentMs); sb.append("ms)"); } else { sb.append(" (running)"); } } return ", "; return ", "; } } } } Loading @@ -2565,6 +2613,7 @@ public abstract class BatteryStats implements Parcelable { } } /** /** * Prints details about a timer, if its total time was greater than 0. * * * @param pw a PrintWriter object to print to. * @param pw a PrintWriter object to print to. * @param sb a StringBuilder object. * @param sb a StringBuilder object. Loading @@ -2573,24 +2622,40 @@ public abstract class BatteryStats implements Parcelable { * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. * @param prefix a String to be prepended to each line of output. * @param prefix a String to be prepended to each line of output. * @param type the name of the timer. * @param type the name of the timer. * @return true if anything was printed. */ */ private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer, private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer, long rawRealtime, int which, String prefix, String type) { long rawRealtimeUs, int which, String prefix, String type) { if (timer != null) { if (timer != null) { // Convert from microseconds to milliseconds with rounding // Convert from microseconds to milliseconds with rounding final long totalTime = (timer.getTotalTimeLocked( final long totalTimeMs = (timer.getTotalTimeLocked( rawRealtime, which) + 500) / 1000; rawRealtimeUs, which) + 500) / 1000; final int count = timer.getCountLocked(which); final int count = timer.getCountLocked(which); if (totalTime != 0) { if (totalTimeMs != 0) { sb.setLength(0); sb.setLength(0); sb.append(prefix); sb.append(prefix); sb.append(" "); sb.append(" "); sb.append(type); sb.append(type); sb.append(": "); sb.append(": "); formatTimeMs(sb, totalTime); formatTimeMs(sb, totalTimeMs); sb.append("realtime ("); sb.append("realtime ("); sb.append(count); sb.append(count); sb.append(" times)"); sb.append(" times)"); final long maxDurationMs = timer.getMaxDurationMsLocked(rawRealtimeUs/1000); if (maxDurationMs >= 0) { sb.append(" max="); sb.append(maxDurationMs); } if (timer.isRunningLocked()) { final long currentMs = timer.getCurrentDurationMsLocked(rawRealtimeUs/1000); if (currentMs >= 0) { sb.append(" (running for "); sb.append(currentMs); sb.append("ms)"); } else { sb.append(" (running)"); } } pw.println(sb.toString()); pw.println(sb.toString()); return true; return true; } } Loading @@ -2613,15 +2678,23 @@ public abstract class BatteryStats implements Parcelable { long elapsedRealtimeUs, String name, int which, String linePrefix) { long elapsedRealtimeUs, String name, int which, String linePrefix) { long totalTimeMicros = 0; long totalTimeMicros = 0; int count = 0; int count = 0; long max = -1; long current = -1; if (timer != null) { if (timer != null) { totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which); totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which); count = timer.getCountLocked(which); count = timer.getCountLocked(which); current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000); max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000); } } sb.append(linePrefix); sb.append(linePrefix); sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding sb.append(','); sb.append(','); sb.append(name != null ? name + "," : ""); sb.append(name != null ? name + "," : ""); sb.append(count); sb.append(count); sb.append(','); sb.append(current); sb.append(','); sb.append(max); return ","; return ","; } } Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +220 −18 Original line number Original line Diff line number Diff line Loading @@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version // Current on-disk Parcel version private static final int VERSION = 148 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 149 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -1566,6 +1566,186 @@ public class BatteryStatsImpl extends BatteryStats { } } } } /** * A StopwatchTimer that also tracks the total and max individual * time spent active according to the given timebase. Whereas * StopwatchTimer apportions the time amongst all in the pool, * the total and max durations are not apportioned. */ public static class DurationTimer extends StopwatchTimer { /** * The time (in ms) that the timer was last acquired or the time base * last (re-)started. Increasing the nesting depth does not reset this time. * * -1 if the timer is currently not running or the time base is not running. * * If written to a parcel, the start time is reset, as is mNesting in the base class * StopwatchTimer. */ long mStartTimeMs = -1; /** * The longest time period (in ms) that the timer has been active. */ long mMaxDurationMs; /** * The total time (in ms) that that the timer has been active since reset(). */ long mCurrentDurationMs; public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase, Parcel in) { super(clocks, uid, type, timerPool, timeBase, in); mMaxDurationMs = in.readLong(); } public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase) { super(clocks, uid, type, timerPool, timeBase); } @Override public void writeToParcel(Parcel out, long elapsedRealtimeUs) { super.writeToParcel(out, elapsedRealtimeUs); out.writeLong(mMaxDurationMs); } /** * Write the summary to the parcel. * * Since the time base is probably meaningless after we come back, reading * from this will have the effect of stopping the timer. So here all we write * is the max duration. */ @Override public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) { super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); out.writeLong(mMaxDurationMs); } /** * Read the summary parcel. * * Has the side effect of stopping the timer. */ @Override public void readSummaryFromParcelLocked(Parcel in) { super.readSummaryFromParcelLocked(in); mMaxDurationMs = in.readLong(); mStartTimeMs = -1; mCurrentDurationMs = 0; } /** * The TimeBase time started (again). * * If the timer is also running, store the start time. */ public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) { super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime); if (mNesting > 0) { mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; } } /** * The TimeBase stopped running. * * If the timer is running, add the duration into mCurrentDurationMs. */ @Override public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtime) { super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtime); if (mNesting > 0) { mCurrentDurationMs += (elapsedRealtimeUs / 1000) - mStartTimeMs; } mStartTimeMs = -1; } @Override public void logState(Printer pw, String prefix) { super.logState(pw, prefix); } @Override public void startRunningLocked(long elapsedRealtimeMs) { super.startRunningLocked(elapsedRealtimeMs); if (mNesting == 1 && mTimeBase.isRunning()) { // Just started mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; } } /** * Decrements the mNesting ref-count on this timer. * * If it actually stopped (mNesting went to 0), then possibly update * mMaxDuration if the current duration was the longest ever. */ @Override public void stopRunningLocked(long elapsedRealtimeMs) { super.stopRunningLocked(elapsedRealtimeMs); if (mNesting == 0) { final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs); if (durationMs > mMaxDurationMs) { mMaxDurationMs = durationMs; } mStartTimeMs = -1; mCurrentDurationMs = 0; } } @Override public boolean reset(boolean detachIfReset) { boolean result = super.reset(detachIfReset); mMaxDurationMs = 0; mCurrentDurationMs = 0; if (mNesting > 0) { mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; } else { mStartTimeMs = -1; } return result; } /** * Returns the max duration that this timer has ever seen. * * Note that this time is NOT split between the timers in the timer group that * this timer is attached to. It is the TOTAL time. */ @Override public long getMaxDurationMsLocked(long elapsedRealtimeMs) { if (mNesting > 0) { final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs); if (durationMs > mMaxDurationMs) { return durationMs; } } return mMaxDurationMs; } /** * Returns the time since the timer was started. * * Note that this time is NOT split between the timers in the timer group that * this timer is attached to. It is the TOTAL time. */ @Override public long getCurrentDurationMsLocked(long elapsedRealtimeMs) { long durationMs = mCurrentDurationMs; if (mNesting > 0) { if (mTimeBase.isRunning()) { durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000) - mStartTimeMs; } } return durationMs; } } /** /** * State for keeping track of timing information. * State for keeping track of timing information. */ */ Loading Loading @@ -6535,7 +6715,7 @@ public class BatteryStatsImpl extends BatteryStats { /** /** * How long (in ms) this uid has been keeping the device partially awake. * How long (in ms) this uid has been keeping the device partially awake. */ */ StopwatchTimer mTimerPartial; DurationTimer mTimerPartial; /** /** * How long (in ms) this uid has been keeping the device fully awake. * How long (in ms) this uid has been keeping the device fully awake. Loading Loading @@ -6564,8 +6744,8 @@ public class BatteryStatsImpl extends BatteryStats { * @param in the Parcel to be read from. * @param in the Parcel to be read from. * return a new Timer, or null. * return a new Timer, or null. */ */ private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool, private StopwatchTimer readStopwatchTimerFromParcel(int type, TimeBase timeBase, Parcel in) { ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) { if (in.readInt() == 0) { if (in.readInt() == 0) { return null; return null; } } Loading @@ -6573,6 +6753,22 @@ public class BatteryStatsImpl extends BatteryStats { return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in); return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in); } } /** * Reads a possibly null Timer from a Parcel. The timer is associated with the * proper timer pool from the given BatteryStatsImpl object. * * @param in the Parcel to be read from. * return a new Timer, or null. */ private DurationTimer readDurationTimerFromParcel(int type, ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) { if (in.readInt() == 0) { return null; } return new DurationTimer(mBsi.mClocks, mUid, type, pool, timeBase, in); } boolean reset() { boolean reset() { boolean wlactive = false; boolean wlactive = false; if (mTimerFull != null) { if (mTimerFull != null) { Loading Loading @@ -6609,11 +6805,14 @@ public class BatteryStatsImpl extends BatteryStats { } } void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL, mTimerPartial = readDurationTimerFromParcel(WAKE_TYPE_PARTIAL, mBsi.mPartialTimers, screenOffTimeBase, in); mBsi.mPartialTimers, screenOffTimeBase, in); mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in); mTimerFull = readStopwatchTimerFromParcel(WAKE_TYPE_FULL, mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in); mBsi.mFullTimers, timeBase, in); mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in); mTimerWindow = readStopwatchTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in); mTimerDraw = readStopwatchTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in); } } void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { Loading @@ -6635,40 +6834,43 @@ public class BatteryStatsImpl extends BatteryStats { } } public StopwatchTimer getStopwatchTimer(int type) { public StopwatchTimer getStopwatchTimer(int type) { StopwatchTimer t; switch (type) { switch (type) { case WAKE_TYPE_PARTIAL: case WAKE_TYPE_PARTIAL: { t = mTimerPartial; DurationTimer t = mTimerPartial; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL, t = new DurationTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL, mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase); mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase); mTimerPartial = t; mTimerPartial = t; } } return t; return t; case WAKE_TYPE_FULL: } t = mTimerFull; case WAKE_TYPE_FULL: { StopwatchTimer t = mTimerFull; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL, t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL, mBsi.mFullTimers, mBsi.mOnBatteryTimeBase); mBsi.mFullTimers, mBsi.mOnBatteryTimeBase); mTimerFull = t; mTimerFull = t; } } return t; return t; case WAKE_TYPE_WINDOW: } t = mTimerWindow; case WAKE_TYPE_WINDOW: { StopwatchTimer t = mTimerWindow; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW, t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW, mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase); mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase); mTimerWindow = t; mTimerWindow = t; } } return t; return t; case WAKE_TYPE_DRAW: } t = mTimerDraw; case WAKE_TYPE_DRAW: { StopwatchTimer t = mTimerDraw; if (t == null) { if (t == null) { t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW, t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW, mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase); mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase); mTimerDraw = t; mTimerDraw = t; } } return t; return t; } default: default: throw new IllegalArgumentException("type=" + type); throw new IllegalArgumentException("type=" + type); } } Loading
core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java 0 → 100644 +151 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.internal.os; import android.os.BatteryStats; import android.os.Parcel; import android.support.test.filters.SmallTest; import android.util.Log; import junit.framework.TestCase; import org.mockito.Mockito; /** * Test BatteryStatsImpl.DurationTimer. * * In these tests, unless otherwise commented, the time increments by * 2x + 100, to make the subtraction unlikely to alias to another time. */ public class BatteryStatsDurationTimerTest extends TestCase { @SmallTest public void testStartStop() throws Exception { final MockClocks clocks = new MockClocks(); final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase(); timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime()); final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase); // TimeBase running, timer not running: current and max are 0 timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100*1000); assertFalse(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(300)); assertEquals(0, timer.getMaxDurationMsLocked(301)); // Start timer: current and max advance timer.startRunningLocked(700); assertTrue(timer.isRunningLocked()); assertEquals(800, timer.getCurrentDurationMsLocked(1500)); assertEquals(801, timer.getMaxDurationMsLocked(1501)); // Stop timer: current resets to 0, max remains timer.stopRunningLocked(3100); assertFalse(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(6300)); assertEquals(2400, timer.getMaxDurationMsLocked(6301)); // Start time again, but check with a short time, and make sure max doesn't // increment. timer.startRunningLocked(12700); assertTrue(timer.isRunningLocked()); assertEquals(100, timer.getCurrentDurationMsLocked(12800)); assertEquals(2400, timer.getMaxDurationMsLocked(12801)); // And stop it again, but with a short time, and make sure it doesn't increment. timer.stopRunningLocked(12900); assertFalse(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(13000)); assertEquals(2400, timer.getMaxDurationMsLocked(13001)); // Now start and check that the time doesn't increase if the two times are the same. timer.startRunningLocked(27000); assertTrue(timer.isRunningLocked()); assertEquals(0, timer.getCurrentDurationMsLocked(27000)); assertEquals(2400, timer.getMaxDurationMsLocked(27000)); // Stop the TimeBase. The values should be frozen. timeBase.setRunning(false, /* uptimeUs */ 10, /* realtimeUs */ 55000*1000); assertTrue(timer.isRunningLocked()); assertEquals(28100, timer.getCurrentDurationMsLocked(110100)); // Why 28100 and not 28000? assertEquals(28100, timer.getMaxDurationMsLocked(110101)); // Start the TimeBase. The values should be the old value plus the delta // between when the timer restarted and the current time timeBase.setRunning(true, /* uptimeUs */ 10, /* realtimeUs */ 220100*1000); assertTrue(timer.isRunningLocked()); assertEquals(28300, timer.getCurrentDurationMsLocked(220300)); // extra 100 from above?? assertEquals(28301, timer.getMaxDurationMsLocked(220301)); } @SmallTest public void testReset() throws Exception { } @SmallTest public void testParceling() throws Exception { final MockClocks clocks = new MockClocks(); final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase(); timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime()); final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase); // Start running on battery. clocks.realtime = 100; clocks.uptime = 10; timeBase.setRunning(true, clocks.uptimeMillis()*1000, clocks.elapsedRealtime()*1000); timer.startRunningLocked(300); // Check that it did start running assertEquals(400, timer.getMaxDurationMsLocked(700)); assertEquals(401, timer.getCurrentDurationMsLocked(701)); // Write summary final Parcel summaryParcel = Parcel.obtain(); timer.writeSummaryFromParcelLocked(summaryParcel, 1500*1000); summaryParcel.setDataPosition(0); // Read summary final BatteryStatsImpl.DurationTimer summary = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase); summary.startRunningLocked(3100); summary.readSummaryFromParcelLocked(summaryParcel); // The new one shouldn't be running, and therefore 0 for current time assertFalse(summary.isRunningLocked()); assertEquals(0, summary.getCurrentDurationMsLocked(6300)); // The new one should have the max duration that we had when we wrote it assertEquals(1200, summary.getMaxDurationMsLocked(6301)); // Write full final Parcel fullParcel = Parcel.obtain(); timer.writeToParcel(fullParcel, 1500*1000); fullParcel.setDataPosition(0); // Read full - Should be the same as the summary as far as DurationTimer is concerned. final BatteryStatsImpl.DurationTimer full = new BatteryStatsImpl.DurationTimer(clocks, null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase, fullParcel); // The new one shouldn't be running, and therefore 0 for current time assertFalse(full.isRunningLocked()); assertEquals(0, full.getCurrentDurationMsLocked(6300)); // The new one should have the max duration that we had when we wrote it assertEquals(1200, full.getMaxDurationMsLocked(6301)); } }
core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,7 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @RunWith(Suite.class) @Suite.SuiteClasses({ @Suite.SuiteClasses({ BatteryStatsDurationTimerTest.class, BatteryStatsSamplingTimerTest.class, BatteryStatsSamplingTimerTest.class, BatteryStatsServTest.class, BatteryStatsServTest.class, BatteryStatsTimeBaseTest.class, BatteryStatsTimeBaseTest.class, Loading