Merge "Have BatteryStats track and report the running wakelocks." into nyc-mr1-dev
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f0cc390..a0c2efd 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,8 @@
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.ArrayMap;
+import android.util.Log;
+import android.util.LongSparseArray;
import android.util.MutableBoolean;
import android.util.Pair;
import android.util.Printer;
@@ -47,6 +49,7 @@
* @hide
*/
public abstract class BatteryStats implements Parcelable {
+ private static final String TAG = "BatteryStats";
private static final boolean LOCAL_LOGV = false;
@@ -175,8 +178,11 @@
/**
* 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.
@@ -352,6 +358,32 @@
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.
*/
public abstract void logState(Printer pw, String prefix);
@@ -2558,6 +2590,22 @@
sb.append('(');
sb.append(count);
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 ", ";
}
}
@@ -2565,6 +2613,7 @@
}
/**
+ * Prints details about a timer, if its total time was greater than 0.
*
* @param pw a PrintWriter object to print to.
* @param sb a StringBuilder object.
@@ -2573,24 +2622,40 @@
* @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 type the name of the timer.
+ * @return true if anything was printed.
*/
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) {
// Convert from microseconds to milliseconds with rounding
- final long totalTime = (timer.getTotalTimeLocked(
- rawRealtime, which) + 500) / 1000;
+ final long totalTimeMs = (timer.getTotalTimeLocked(
+ rawRealtimeUs, which) + 500) / 1000;
final int count = timer.getCountLocked(which);
- if (totalTime != 0) {
+ if (totalTimeMs != 0) {
sb.setLength(0);
sb.append(prefix);
sb.append(" ");
sb.append(type);
sb.append(": ");
- formatTimeMs(sb, totalTime);
+ formatTimeMs(sb, totalTimeMs);
sb.append("realtime (");
sb.append(count);
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());
return true;
}
@@ -2613,15 +2678,23 @@
long elapsedRealtimeUs, String name, int which, String linePrefix) {
long totalTimeMicros = 0;
int count = 0;
+ long max = -1;
+ long current = -1;
if (timer != null) {
totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
count = timer.getCountLocked(which);
+ current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
+ max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
}
sb.append(linePrefix);
sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
sb.append(',');
sb.append(name != null ? name + "," : "");
sb.append(count);
+ sb.append(',');
+ sb.append(current);
+ sb.append(',');
+ sb.append(max);
return ",";
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 17635ae..7fb92ae 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// 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.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -1566,6 +1566,186 @@
}
}
+
+ /**
+ * 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.
*/
@@ -6535,7 +6715,7 @@
/**
* 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.
@@ -6564,8 +6744,8 @@
* @param in the Parcel to be read from.
* return a new Timer, or null.
*/
- private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
- TimeBase timeBase, Parcel in) {
+ private StopwatchTimer readStopwatchTimerFromParcel(int type,
+ ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) {
if (in.readInt() == 0) {
return null;
}
@@ -6573,6 +6753,22 @@
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 wlactive = false;
if (mTimerFull != null) {
@@ -6609,11 +6805,14 @@
}
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
- mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
+ mTimerPartial = readDurationTimerFromParcel(WAKE_TYPE_PARTIAL,
mBsi.mPartialTimers, screenOffTimeBase, in);
- mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
- mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
- mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
+ mTimerFull = readStopwatchTimerFromParcel(WAKE_TYPE_FULL,
+ mBsi.mFullTimers, 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) {
@@ -6635,40 +6834,43 @@
}
public StopwatchTimer getStopwatchTimer(int type) {
- StopwatchTimer t;
switch (type) {
- case WAKE_TYPE_PARTIAL:
- t = mTimerPartial;
+ case WAKE_TYPE_PARTIAL: {
+ DurationTimer t = mTimerPartial;
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);
mTimerPartial = t;
}
return t;
- case WAKE_TYPE_FULL:
- t = mTimerFull;
+ }
+ case WAKE_TYPE_FULL: {
+ StopwatchTimer t = mTimerFull;
if (t == null) {
t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
mTimerFull = t;
}
return t;
- case WAKE_TYPE_WINDOW:
- t = mTimerWindow;
+ }
+ case WAKE_TYPE_WINDOW: {
+ StopwatchTimer t = mTimerWindow;
if (t == null) {
t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
mTimerWindow = t;
}
return t;
- case WAKE_TYPE_DRAW:
- t = mTimerDraw;
+ }
+ case WAKE_TYPE_DRAW: {
+ StopwatchTimer t = mTimerDraw;
if (t == null) {
t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
mTimerDraw = t;
}
return t;
+ }
default:
throw new IllegalArgumentException("type=" + type);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
new file mode 100644
index 0000000..a15e367
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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));
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 78bcbbc..9518219 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -5,6 +5,7 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({
+ BatteryStatsDurationTimerTest.class,
BatteryStatsSamplingTimerTest.class,
BatteryStatsServTest.class,
BatteryStatsTimeBaseTest.class,