summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/BatteryStats.java175
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java395
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java190
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java22
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java358
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java5
8 files changed, 974 insertions, 174 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 29884b132e5a..dd11f68ffe50 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -24,14 +24,12 @@ import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.function.Predicate;
import android.content.Context;
import android.content.pm.ApplicationInfo;
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;
@@ -184,7 +182,7 @@ public abstract class BatteryStats implements Parcelable {
* New in version 19:
* - Wakelock data (wl) gets current and max times.
* New in version 20:
- * - Sensor gets a background counter.
+ * - Sensor, BluetoothScan, WifiScan get background timers and counter.
*/
static final String CHECKIN_VERSION = "20";
@@ -363,7 +361,7 @@ public abstract class BatteryStats implements Parcelable {
/**
* Returns the max duration if it is being tracked.
- * Not all Timer subclasses track the max duration and the current duration.
+ * Not all Timer subclasses track the max, total, current durations.
*/
public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
@@ -372,13 +370,28 @@ public abstract class BatteryStats implements Parcelable {
/**
* 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.
+ * Not all Timer subclasses track the max, total, current durations.
*/
public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
return -1;
}
/**
+ * Returns the current time the timer has been active, if it is being tracked.
+ *
+ * Returns the total cumulative duration (i.e. sum of past durations) that this timer has
+ * been on since reset.
+ * This may differ from getTotalTimeLocked(elapsedRealtimeUs, STATS_SINCE_CHARGED)/1000 since,
+ * depending on the Timer, getTotalTimeLocked may represent the total 'blamed' or 'pooled'
+ * time, rather than the actual time. By contrast, getTotalDurationMsLocked always gives
+ * the actual total time.
+ * Not all Timer subclasses track the max, total, current durations.
+ */
+ public long getTotalDurationMsLocked(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.
@@ -477,6 +490,9 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which);
public abstract long getWifiScanTime(long elapsedRealtimeUs, int which);
public abstract int getWifiScanCount(int which);
+ public abstract int getWifiScanBackgroundCount(int which);
+ public abstract long getWifiScanActualTime(long elapsedRealtimeUs);
+ public abstract long getWifiScanBackgroundTime(long elapsedRealtimeUs);
public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which);
public abstract int getWifiBatchedScanCount(int csphBin, int which);
public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which);
@@ -486,6 +502,7 @@ public abstract class BatteryStats implements Parcelable {
public abstract Timer getCameraTurnedOnTimer();
public abstract Timer getForegroundActivityTimer();
public abstract Timer getBluetoothScanTimer();
+ public abstract Timer getBluetoothScanBackgroundTimer();
// Note: the following times are disjoint. They can be added together to find the
// total time a uid has had any processes running at all.
@@ -609,8 +626,8 @@ public abstract class BatteryStats implements Parcelable {
public abstract Timer getSensorTime();
- /** Returns a counter for usage count when in the background. */
- public abstract Counter getSensorBgCount();
+ /** Returns a Timer for sensor usage when app is in the background. */
+ public abstract Timer getSensorBackgroundTime();
}
public class Pid {
@@ -2652,7 +2669,7 @@ public abstract class BatteryStats implements Parcelable {
* @param pw a PrintWriter object to print to.
* @param sb a StringBuilder object.
* @param timer a Timer object contining the wakelock times.
- * @param rawRealtime the current on-battery time in microseconds.
+ * @param rawRealtimeUs the current on-battery time in microseconds.
* @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.
@@ -3284,19 +3301,41 @@ public abstract class BatteryStats implements Parcelable {
final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
final int wifiScanCount = u.getWifiScanCount(which);
+ final int wifiScanCountBg = u.getWifiScanBackgroundCount(which);
+ // Note that 'ActualTime' are unpooled and always since reset (regardless of 'which')
+ final long wifiScanActualTime = u.getWifiScanActualTime(rawRealtime);
+ final long wifiScanActualTimeBg = u.getWifiScanBackgroundTime(rawRealtime);
final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
+ || wifiScanCountBg != 0 || wifiScanActualTime != 0 || wifiScanActualTimeBg != 0
|| uidWifiRunningTime != 0) {
dumpLine(pw, uid, category, WIFI_DATA, fullWifiLockOnTime, wifiScanTime,
uidWifiRunningTime, wifiScanCount,
- /* legacy fields follow, keep at 0 */ 0, 0, 0);
+ /* legacy fields follow, keep at 0 */ 0, 0, 0,
+ wifiScanCountBg, wifiScanActualTime, wifiScanActualTimeBg);
}
dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
u.getWifiControllerActivity(), which);
- dumpTimer(pw, uid, category, BLUETOOTH_MISC_DATA, u.getBluetoothScanTimer(),
- rawRealtime, which);
+ final Timer bleTimer = u.getBluetoothScanTimer();
+ if (bleTimer != null) {
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (bleTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ if (totalTime != 0) {
+ final int count = bleTimer.getCountLocked(which);
+ final Timer bleTimerBg = u.getBluetoothScanBackgroundTimer();
+ final int countBg = bleTimerBg != null ? bleTimerBg.getCountLocked(which) : 0;
+ final long rawRealtimeMs = (rawRealtime + 500) / 1000;
+ // 'actualTime' are unpooled and always since reset (regardless of 'which')
+ final long actualTime = bleTimer.getTotalDurationMsLocked(rawRealtimeMs);
+ final long actualTimeBg = bleTimerBg != null ?
+ bleTimerBg.getTotalDurationMsLocked(rawRealtimeMs) : 0;
+ dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA, totalTime, count,
+ countBg, actualTime, actualTimeBg);
+ }
+ }
dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA,
u.getBluetoothControllerActivity(), which);
@@ -3375,16 +3414,21 @@ public abstract class BatteryStats implements Parcelable {
final Uid.Sensor se = sensors.valueAt(ise);
final int sensorNumber = sensors.keyAt(ise);
final Timer timer = se.getSensorTime();
- final Counter bgCounter = se.getSensorBgCount();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500)
/ 1000;
- final int count = timer.getCountLocked(which);
- final int bgCount = bgCounter != null ? bgCounter.getCountLocked(which) : 0;
if (totalTime != 0) {
- dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count,
- bgCount);
+ final int count = timer.getCountLocked(which);
+ final Timer bgTimer = se.getSensorBackgroundTime();
+ final int bgCount = bgTimer != null ? bgTimer.getCountLocked(which) : 0;
+ final long rawRealtimeMs = (rawRealtime + 500) / 1000;
+ // 'actualTime' are unpooled and always since reset (regardless of 'which')
+ final long actualTime = timer.getTotalDurationMsLocked(rawRealtimeMs);
+ final long bgActualTime = bgTimer != null ?
+ bgTimer.getTotalDurationMsLocked(rawRealtimeMs) : 0;
+ dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime,
+ count, bgCount, actualTime, bgActualTime);
}
}
}
@@ -4294,6 +4338,10 @@ public abstract class BatteryStats implements Parcelable {
final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
final int wifiScanCount = u.getWifiScanCount(which);
+ final int wifiScanCountBg = u.getWifiScanBackgroundCount(which);
+ // 'actualTime' are unpooled and always since reset (regardless of 'which')
+ final long wifiScanActualTime = u.getWifiScanActualTime(rawRealtime);
+ final long wifiScanActualTimeBg = u.getWifiScanBackgroundTime(rawRealtime);
final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
final long mobileWakeup = u.getMobileRadioApWakeupCount(which);
@@ -4344,6 +4392,7 @@ public abstract class BatteryStats implements Parcelable {
}
if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
+ || wifiScanCountBg != 0 || wifiScanActualTime != 0 || wifiScanActualTimeBg != 0
|| uidWifiRunningTime != 0) {
sb.setLength(0);
sb.append(prefix); sb.append(" Wifi Running: ");
@@ -4354,11 +4403,26 @@ public abstract class BatteryStats implements Parcelable {
formatTimeMs(sb, fullWifiLockOnTime / 1000);
sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime,
whichBatteryRealtime)); sb.append(")\n");
- sb.append(prefix); sb.append(" Wifi Scan: ");
+ sb.append(prefix); sb.append(" Wifi Scan (blamed): ");
formatTimeMs(sb, wifiScanTime / 1000);
sb.append("("); sb.append(formatRatioLocked(wifiScanTime,
whichBatteryRealtime)); sb.append(") ");
sb.append(wifiScanCount);
+ sb.append("x\n");
+ // actual and background times are unpooled and since reset (regardless of 'which')
+ sb.append(prefix); sb.append(" Wifi Scan (actual): ");
+ formatTimeMs(sb, wifiScanActualTime / 1000);
+ sb.append("("); sb.append(formatRatioLocked(wifiScanActualTime,
+ computeBatteryRealtime(rawRealtime, STATS_SINCE_CHARGED)));
+ sb.append(") ");
+ sb.append(wifiScanCount);
+ sb.append("x\n");
+ sb.append(prefix); sb.append(" Background Wifi Scan: ");
+ formatTimeMs(sb, wifiScanActualTimeBg / 1000);
+ sb.append("("); sb.append(formatRatioLocked(wifiScanActualTimeBg,
+ computeBatteryRealtime(rawRealtime, STATS_SINCE_CHARGED)));
+ sb.append(") ");
+ sb.append(wifiScanCountBg);
sb.append("x");
pw.println(sb.toString());
}
@@ -4381,8 +4445,50 @@ public abstract class BatteryStats implements Parcelable {
pw.println(" sent");
}
- uidActivity |= printTimer(pw, sb, u.getBluetoothScanTimer(), rawRealtime, which, prefix,
- "Bluetooth Scan");
+ final Timer bleTimer = u.getBluetoothScanTimer();
+ if (bleTimer != null) {
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTimeMs = (bleTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ if (totalTimeMs != 0) {
+ final int count = bleTimer.getCountLocked(which);
+ final Timer bleTimerBg = u.getBluetoothScanBackgroundTimer();
+ final int countBg = bleTimerBg != null ? bleTimerBg.getCountLocked(which) : 0;
+ final long rawRealtimeMs = (rawRealtime + 500) / 1000;
+ // 'actualTime' are unpooled and always since reset (regardless of 'which')
+ final long actualTimeMs = bleTimer.getTotalDurationMsLocked(rawRealtimeMs);
+ final long actualTimeMsBg = bleTimerBg != null ?
+ bleTimerBg.getTotalDurationMsLocked(rawRealtimeMs) : 0;
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append("Bluetooth Scan");
+ sb.append(": ");
+ if (actualTimeMs != totalTimeMs) {
+ formatTimeMs(sb, totalTimeMs);
+ sb.append("blamed realtime, ");
+ }
+ formatTimeMs(sb, actualTimeMs); // since reset, regardless of 'which'
+ sb.append("realtime (");
+ sb.append(count);
+ sb.append(" times)");
+ if (bleTimer.isRunningLocked()) {
+ sb.append(" (running)");
+ }
+ if (actualTimeMsBg != 0 || countBg > 0) {
+ sb.append(", ");
+ formatTimeMs(sb, actualTimeMsBg); // since reset, regardless of 'which'
+ sb.append("background (");
+ sb.append(countBg);
+ sb.append(" times)");
+ }
+ pw.println(sb.toString());
+ uidActivity = true;
+ }
+ }
+
+
if (u.hasUserActivity()) {
boolean hasData = false;
@@ -4553,25 +4659,38 @@ public abstract class BatteryStats implements Parcelable {
sb.append(": ");
final Timer timer = se.getSensorTime();
- final Counter bgCounter = se.getSensorBgCount();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- final long totalTime = (timer.getTotalTimeLocked(
- rawRealtime, which) + 500) / 1000;
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
final int count = timer.getCountLocked(which);
- final int bgCount = bgCounter != null ? bgCounter.getCountLocked(which) : 0;
+ final Timer bgTimer = se.getSensorBackgroundTime();
+ final int bgCount = bgTimer != null ? bgTimer.getCountLocked(which) : 0;
+ final long rawRealtimeMs = (rawRealtime + 500) / 1000;
+ // 'actualTime' are unpooled and always since reset (regardless of 'which')
+ final long actualTime = timer.getTotalDurationMsLocked(rawRealtimeMs);
+ final long bgActualTime = bgTimer != null ?
+ bgTimer.getTotalDurationMsLocked(rawRealtimeMs) : 0;
+
//timer.logState();
if (totalTime != 0) {
- formatTimeMs(sb, totalTime);
+ if (actualTime != totalTime) {
+ formatTimeMs(sb, totalTime);
+ sb.append("blamed realtime, ");
+ }
+
+ formatTimeMs(sb, actualTime); // since reset, regardless of 'which'
sb.append("realtime (");
sb.append(count);
- sb.append(" times");
- if (bgCount > 0) {
+ sb.append(" times)");
+
+ if (bgActualTime != 0 || bgCount > 0) {
sb.append(", ");
+ formatTimeMs(sb, bgActualTime); // since reset, regardless of 'which'
+ sb.append("background (");
sb.append(bgCount);
- sb.append(" bg");
+ sb.append(" times)");
}
- sb.append(")");
} else {
sb.append("(not used)");
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 6aa77665db51..a682f956cc0a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -479,7 +479,8 @@ public class BatteryStatsImpl extends BatteryStats {
new StopwatchTimer[NUM_WIFI_SIGNAL_STRENGTH_BINS];
int mBluetoothScanNesting;
- StopwatchTimer mBluetoothScanTimer;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected StopwatchTimer mBluetoothScanTimer;
int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
long mMobileRadioActiveStartTime;
@@ -1586,19 +1587,28 @@ public class BatteryStatsImpl extends BatteryStats {
long mStartTimeMs = -1;
/**
- * The longest time period (in ms) that the timer has been active.
+ * The longest time period (in ms) that the timer has been active. Not pooled.
*/
long mMaxDurationMs;
/**
- * The total time (in ms) that that the timer has been active since reset().
+ * The time (in ms) that that the timer has been active since most recent
+ * stopRunningLocked() or reset(). Not pooled.
*/
long mCurrentDurationMs;
+ /**
+ * The total time (in ms) that that the timer has been active since most recent reset()
+ * prior to the current startRunningLocked. This is the sum of all past currentDurations
+ * (but not including the present currentDuration) since reset. Not pooled.
+ */
+ long mTotalDurationMs;
+
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();
+ mTotalDurationMs = in.readLong();
}
public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
@@ -1610,6 +1620,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
super.writeToParcel(out, elapsedRealtimeUs);
out.writeLong(getMaxDurationMsLocked(elapsedRealtimeUs / 1000));
+ out.writeLong(getTotalDurationMsLocked(elapsedRealtimeUs / 1000));
}
/**
@@ -1617,12 +1628,13 @@ public class BatteryStatsImpl extends BatteryStats {
*
* 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.
+ * is the max and total durations.
*/
@Override
public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
out.writeLong(getMaxDurationMsLocked(elapsedRealtimeUs / 1000));
+ out.writeLong(getTotalDurationMsLocked(elapsedRealtimeUs / 1000));
}
/**
@@ -1634,6 +1646,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void readSummaryFromParcelLocked(Parcel in) {
super.readSummaryFromParcelLocked(in);
mMaxDurationMs = in.readLong();
+ mTotalDurationMs = in.readLong();
mStartTimeMs = -1;
mCurrentDurationMs = 0;
}
@@ -1689,6 +1702,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void stopRunningLocked(long elapsedRealtimeMs) {
if (mNesting == 1) {
final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
+ mTotalDurationMs += durationMs;
if (durationMs > mMaxDurationMs) {
mMaxDurationMs = durationMs;
}
@@ -1704,6 +1718,7 @@ public class BatteryStatsImpl extends BatteryStats {
public boolean reset(boolean detachIfReset) {
boolean result = super.reset(detachIfReset);
mMaxDurationMs = 0;
+ mTotalDurationMs = 0;
mCurrentDurationMs = 0;
if (mNesting > 0) {
mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
@@ -1732,6 +1747,7 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Returns the time since the timer was started.
+ * Returns 0 if the timer is not currently running.
*
* 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.
@@ -1745,6 +1761,20 @@ public class BatteryStatsImpl extends BatteryStats {
}
return durationMs;
}
+
+ /**
+ * Returns the total cumulative duration that this timer has been on since reset().
+ * If mTimerPool == null, this should be the same
+ * as getTotalTimeLocked(elapsedRealtimeMs*1000, STATS_SINCE_CHARGED)/1000.
+ *
+ * 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. For this reason, if mTimerPool != null,
+ * the result will not be equivalent to getTotalTimeLocked.
+ */
+ @Override
+ public long getTotalDurationMsLocked(long elapsedRealtimeMs) {
+ return mTotalDurationMs + getCurrentDurationMsLocked(elapsedRealtimeMs);
+ }
}
/**
@@ -1969,6 +1999,116 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ /**
+ * State for keeping track of two DurationTimers with different TimeBases, presumably where one
+ * TimeBase is effectively a subset of the other.
+ */
+ public static class DualTimer {
+ // mMainTimer typically tracks the total time. May be pooled (but since it's a durationTimer,
+ // it also has the unpooled getTotalDurationMsLocked() for STATS_SINCE_CHARGED).
+ private final DurationTimer mMainTimer;
+ // mSubTimer typically tracks only part of the total time, such as background time, as
+ // determined by a subTimeBase. It is NOT pooled.
+ private final DurationTimer mSubTimer;
+
+ /**
+ * Creates a DualTimer to hold a mMainTimer and a mSubTimer.
+ * The mMainTimer is based on the given timeBase and timerPool.
+ * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if
+ * the mMainTimer is.
+ */
+ public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ TimeBase timeBase, TimeBase subTimeBase, Parcel in) {
+ mMainTimer = new DurationTimer(clocks, uid, type, timerPool, timeBase, in);
+ mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase, in);
+ }
+
+ /**
+ * Creates a DualTimer to hold a mMainTimer and a mSubTimer.
+ * The mMainTimer is based on the given timeBase and timerPool.
+ * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if
+ * the mMainTimer is.
+ */
+ public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+ TimeBase timeBase, TimeBase subTimeBase) {
+ mMainTimer = new DurationTimer(clocks, uid, type, timerPool, timeBase);
+ mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase);
+ }
+
+ /** Get the main timer. */
+ public DurationTimer getMainTimer() {
+ return mMainTimer;
+ }
+
+ /** Get the secondary timer. */
+ public DurationTimer getSubTimer() {
+ return mSubTimer;
+ }
+
+ public void startRunningLocked(long elapsedRealtimeMs) {
+ mMainTimer.startRunningLocked(elapsedRealtimeMs);
+ mSubTimer.startRunningLocked(elapsedRealtimeMs);
+ }
+
+ public void stopRunningLocked(long elapsedRealtimeMs) {
+ mMainTimer.stopRunningLocked(elapsedRealtimeMs);
+ mSubTimer.stopRunningLocked(elapsedRealtimeMs);
+ }
+
+ public void stopAllRunningLocked(long elapsedRealtimeMs) {
+ mMainTimer.stopAllRunningLocked(elapsedRealtimeMs);
+ mSubTimer.stopAllRunningLocked(elapsedRealtimeMs);
+ }
+
+ public void setMark(long elapsedRealtimeMs) {
+ mMainTimer.setMark(elapsedRealtimeMs);
+ mSubTimer.setMark(elapsedRealtimeMs);
+ }
+
+ public boolean reset(boolean detachIfReset) {
+ boolean active = false;
+ active |= !mMainTimer.reset(detachIfReset);
+ active |= !mSubTimer.reset(detachIfReset);
+ return !active;
+ }
+
+ public void detach() {
+ mMainTimer.detach();
+ mSubTimer.detach();
+ }
+
+ /**
+ * Writes a possibly null DualTimer to a Parcel.
+ *
+ * @param out the Parcel to which to write.
+ * @param t a DualTimer, or null.
+ */
+ public static void writeDualTimerToParcel(Parcel out, DualTimer t, long elapsedRealtimeUs) {
+ if (t != null) {
+ out.writeInt(1);
+ t.writeToParcel(out, elapsedRealtimeUs);
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+ mMainTimer.writeToParcel(out, elapsedRealtimeUs);
+ mSubTimer.writeToParcel(out, elapsedRealtimeUs);
+ }
+
+ public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+ mMainTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
+ mSubTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
+ }
+
+ public void readSummaryFromParcelLocked(Parcel in) {
+ mMainTimer.readSummaryFromParcelLocked(in);
+ mSubTimer.readSummaryFromParcelLocked(in);
+ }
+ }
+
+
public abstract class OverflowArrayMap<T> {
private static final String OVERFLOW_NAME = "*overflow*";
@@ -3146,7 +3286,13 @@ public class BatteryStatsImpl extends BatteryStats {
public void updateTimeBasesLocked(boolean unplugged, boolean screenOff, long uptime,
long realtime) {
- mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
+ boolean batteryStatusChanged = mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
+
+ if (batteryStatusChanged) {
+ for (int i=0; i<mUidStats.size(); i++) {
+ mUidStats.valueAt(i).updateBgTimeBase(uptime, realtime);
+ }
+ }
boolean unpluggedScreenOff = unplugged && screenOff;
if (unpluggedScreenOff != mOnBatteryScreenOffTimeBase.isRunning()) {
@@ -4485,8 +4631,8 @@ public class BatteryStatsImpl extends BatteryStats {
private void noteBluetoothScanStartedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
@@ -4507,8 +4653,8 @@ public class BatteryStatsImpl extends BatteryStats {
private void noteBluetoothScanStoppedLocked(int uid) {
uid = mapUid(uid);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mBluetoothScanNesting--;
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
@@ -4529,8 +4675,8 @@ public class BatteryStatsImpl extends BatteryStats {
public void noteResetBluetoothScanLocked() {
if (mBluetoothScanNesting > 0) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
mBluetoothScanNesting = 0;
mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: "
@@ -5204,6 +5350,13 @@ public class BatteryStatsImpl extends BatteryStats {
return true;
}
+ private static boolean resetTimerIfNotNull(DualTimer timer, boolean detachIfReset) {
+ if (timer != null) {
+ return timer.reset(detachIfReset);
+ }
+ return true;
+ }
+
private static void detachLongCounterIfNotNull(LongSamplingCounter counter) {
if (counter != null) {
counter.detach();
@@ -5228,6 +5381,10 @@ public class BatteryStatsImpl extends BatteryStats {
final int mUid;
+ /** TimeBase for when uid is in background and device is on battery. */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public final TimeBase mOnBatteryBackgroundTimeBase;
+
boolean mWifiRunning;
StopwatchTimer mWifiRunningTimer;
@@ -5235,7 +5392,7 @@ public class BatteryStatsImpl extends BatteryStats {
StopwatchTimer mFullWifiLockTimer;
boolean mWifiScanStarted;
- StopwatchTimer mWifiScanTimer;
+ DualTimer mWifiScanTimer;
static final int NO_BATCHED_SCAN_STARTED = -1;
int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
@@ -5249,7 +5406,7 @@ public class BatteryStatsImpl extends BatteryStats {
StopwatchTimer mFlashlightTurnedOnTimer;
StopwatchTimer mCameraTurnedOnTimer;
StopwatchTimer mForegroundActivityTimer;
- StopwatchTimer mBluetoothScanTimer;
+ DualTimer mBluetoothScanTimer;
int mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
StopwatchTimer[] mProcessStateTimer;
@@ -5343,6 +5500,10 @@ public class BatteryStatsImpl extends BatteryStats {
mBsi = bsi;
mUid = uid;
+ mOnBatteryBackgroundTimeBase = new TimeBase();
+ mOnBatteryBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000,
+ mBsi.mClocks.elapsedRealtime() * 1000);
+
mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
@@ -5369,8 +5530,8 @@ public class BatteryStatsImpl extends BatteryStats {
mBsi.mWifiRunningTimers, mBsi.mOnBatteryTimeBase);
mFullWifiLockTimer = new StopwatchTimer(mBsi.mClocks, this, FULL_WIFI_LOCK,
mBsi.mFullWifiLockTimers, mBsi.mOnBatteryTimeBase);
- mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_SCAN,
- mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
+ mWifiScanTimer = new DualTimer(mBsi.mClocks, this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
mWifiMulticastTimer = new StopwatchTimer(mBsi.mClocks, this, WIFI_MULTICAST_ENABLED,
mBsi.mWifiMulticastTimers, mBsi.mOnBatteryTimeBase);
@@ -5457,8 +5618,9 @@ public class BatteryStatsImpl extends BatteryStats {
if (!mWifiScanStarted) {
mWifiScanStarted = true;
if (mWifiScanTimer == null) {
- mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
- mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase);
+ mWifiScanTimer = new DualTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase,
+ mOnBatteryBackgroundTimeBase);
}
mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
}
@@ -5665,10 +5827,11 @@ public class BatteryStatsImpl extends BatteryStats {
return mForegroundActivityTimer;
}
- public StopwatchTimer createBluetoothScanTimerLocked() {
+ public DualTimer createBluetoothScanTimerLocked() {
if (mBluetoothScanTimer == null) {
- mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
- mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase);
+ mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase,
+ mOnBatteryBackgroundTimeBase);
}
return mBluetoothScanTimer;
}
@@ -5741,7 +5904,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (mWifiScanTimer == null) {
return 0;
}
- return mWifiScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ return mWifiScanTimer.getMainTimer().getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override
@@ -5749,7 +5912,33 @@ public class BatteryStatsImpl extends BatteryStats {
if (mWifiScanTimer == null) {
return 0;
}
- return mWifiScanTimer.getCountLocked(which);
+ return mWifiScanTimer.getMainTimer().getCountLocked(which);
+ }
+
+ @Override
+ public int getWifiScanBackgroundCount(int which) {
+ if (mWifiScanTimer == null) {
+ return 0;
+ }
+ return mWifiScanTimer.getSubTimer().getCountLocked(which);
+ }
+
+ @Override
+ public long getWifiScanActualTime(final long elapsedRealtimeUs) {
+ if (mWifiScanTimer == null) {
+ return 0;
+ }
+ final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000;
+ return mWifiScanTimer.getMainTimer().getTotalDurationMsLocked(elapsedRealtimeMs) * 1000;
+ }
+
+ @Override
+ public long getWifiScanBackgroundTime(final long elapsedRealtimeUs) {
+ if (mWifiScanTimer == null) {
+ return 0;
+ }
+ final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000;
+ return mWifiScanTimer.getSubTimer().getTotalDurationMsLocked(elapsedRealtimeMs) * 1000;
}
@Override
@@ -5805,7 +5994,18 @@ public class BatteryStatsImpl extends BatteryStats {
@Override
public Timer getBluetoothScanTimer() {
- return mBluetoothScanTimer;
+ if (mBluetoothScanTimer == null) {
+ return null;
+ }
+ return mBluetoothScanTimer.getMainTimer();
+ }
+
+ @Override
+ public Timer getBluetoothScanBackgroundTimer() {
+ if (mBluetoothScanTimer == null) {
+ return null;
+ }
+ return mBluetoothScanTimer.getSubTimer();
}
void makeProcessState(int i, Parcel in) {
@@ -6202,6 +6402,9 @@ public class BatteryStatsImpl extends BatteryStats {
mLastStepUserTime = mLastStepSystemTime = 0;
mCurStepUserTime = mCurStepSystemTime = 0;
+ mOnBatteryBackgroundTimeBase.reset(mBsi.mClocks.elapsedRealtime() * 1000,
+ mBsi.mClocks.uptimeMillis() * 1000);
+
if (!active) {
if (mWifiRunningTimer != null) {
mWifiRunningTimer.detach();
@@ -6293,7 +6496,9 @@ public class BatteryStatsImpl extends BatteryStats {
return !active;
}
- void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
+ void writeToParcelLocked(Parcel out, long uptimeUs, long elapsedRealtimeUs) {
+ mOnBatteryBackgroundTimeBase.writeToParcel(out, uptimeUs, elapsedRealtimeUs);
+
final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
@@ -6511,6 +6716,8 @@ public class BatteryStatsImpl extends BatteryStats {
}
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
+ mOnBatteryBackgroundTimeBase.readFromParcel(in);
+
int numWakelocks = in.readInt();
mWakelockStats.clear();
for (int j = 0; j < numWakelocks; j++) {
@@ -6545,7 +6752,8 @@ public class BatteryStatsImpl extends BatteryStats {
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
Uid.Sensor sensor = new Sensor(mBsi, this, sensorNumber);
- sensor.readFromParcelLocked(mBsi.mOnBatteryTimeBase, in);
+ sensor.readFromParcelLocked(mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase,
+ in);
mSensorStats.put(sensorNumber, sensor);
}
@@ -6583,8 +6791,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
mWifiScanStarted = false;
if (in.readInt() != 0) {
- mWifiScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
- mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, in);
+ mWifiScanTimer = new DualTimer(mBsi.mClocks, Uid.this, WIFI_SCAN,
+ mBsi.mWifiScanTimers, mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase,
+ in);
} else {
mWifiScanTimer = null;
}
@@ -6634,8 +6843,9 @@ public class BatteryStatsImpl extends BatteryStats {
mForegroundActivityTimer = null;
}
if (in.readInt() != 0) {
- mBluetoothScanTimer = new StopwatchTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
- mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, in);
+ mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON,
+ mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase,
+ mOnBatteryBackgroundTimeBase, in);
} else {
mBluetoothScanTimer = null;
}
@@ -6932,14 +7142,12 @@ public class BatteryStatsImpl extends BatteryStats {
protected BatteryStatsImpl mBsi;
/**
- * BatteryStatsImpl that we are associated with.
+ * Uid that we are associated with.
*/
protected Uid mUid;
final int mHandle;
- StopwatchTimer mTimer;
-
- Counter mBgCounter;
+ DualTimer mTimer;
public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) {
mBsi = bsi;
@@ -6947,7 +7155,8 @@ public class BatteryStatsImpl extends BatteryStats {
mHandle = handle;
}
- private StopwatchTimer readTimerFromParcel(TimeBase timeBase, Parcel in) {
+ private DualTimer readTimersFromParcel(
+ TimeBase timeBase, TimeBase bgTimeBase, Parcel in) {
if (in.readInt() == 0) {
return null;
}
@@ -6957,23 +7166,10 @@ public class BatteryStatsImpl extends BatteryStats {
pool = new ArrayList<StopwatchTimer>();
mBsi.mSensorTimers.put(mHandle, pool);
}
- return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in);
- }
-
- private Counter readCounterFromParcel(TimeBase timeBase, Parcel in) {
- if (in.readInt() == 0) {
- return null;
- }
- return new Counter(timeBase, in);
+ return new DualTimer(mBsi.mClocks, mUid, 0, pool, timeBase, bgTimeBase, in);
}
boolean reset() {
- if (mBgCounter != null) {
- mBgCounter.reset(true /*detachIfReset*/);
- // If we detach, we must null the mBgCounter reference so that it
- // can be recreated and attached.
- mBgCounter = null;
- }
if (mTimer.reset(true)) {
mTimer = null;
return true;
@@ -6981,24 +7177,28 @@ public class BatteryStatsImpl extends BatteryStats {
return false;
}
- void readFromParcelLocked(TimeBase timeBase, Parcel in) {
- mTimer = readTimerFromParcel(timeBase, in);
- mBgCounter = readCounterFromParcel(timeBase, in);
+ void readFromParcelLocked(TimeBase timeBase, TimeBase bgTimeBase, Parcel in) {
+ mTimer = readTimersFromParcel(timeBase, bgTimeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
- Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs);
- Counter.writeCounterToParcel(out, mBgCounter);
+ DualTimer.writeDualTimerToParcel(out, mTimer, elapsedRealtimeUs);
}
@Override
public Timer getSensorTime() {
- return mTimer;
+ if (mTimer == null) {
+ return null;
+ }
+ return mTimer.getMainTimer();
}
@Override
- public Counter getSensorBgCount() {
- return mBgCounter;
+ public Timer getSensorBackgroundTime() {
+ if (mTimer == null) {
+ return null;
+ }
+ return mTimer.getSubTimer();
}
@Override
@@ -7735,18 +7935,29 @@ public class BatteryStatsImpl extends BatteryStats {
if (mProcessState == uidRunningState) return;
- final long elapsedRealtime = mBsi.mClocks.elapsedRealtime();
+ final long elapsedRealtimeMs = mBsi.mClocks.elapsedRealtime();
+ final long uptimeMs = mBsi.mClocks.uptimeMillis();
if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
- mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtime);
+ mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
}
mProcessState = uidRunningState;
if (uidRunningState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
if (mProcessStateTimer[uidRunningState] == null) {
makeProcessState(uidRunningState, null);
}
- mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtime);
+ mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtimeMs);
}
+
+ updateBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000);
+ }
+
+ public boolean updateBgTimeBase(long uptimeUs, long realtimeUs) {
+ // Note that PROCESS_STATE_CACHED and ActivityManager.PROCESS_STATE_NONEXISTENT is
+ // also considered to be 'background' for our purposes, because it's not foreground.
+ boolean isBgAndUnplugged = mBsi.mOnBatteryTimeBase.isRunning()
+ && mProcessState >= PROCESS_STATE_BACKGROUND;
+ return mOnBatteryBackgroundTimeBase.setRunning(isBgAndUnplugged, uptimeUs, realtimeUs);
}
public SparseArray<? extends Pid> getPidStats() {
@@ -7820,7 +8031,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- public StopwatchTimer getSensorTimerLocked(int sensor, boolean create) {
+ public DualTimer getSensorTimerLocked(int sensor, boolean create) {
Sensor se = mSensorStats.get(sensor);
if (se == null) {
if (!create) {
@@ -7829,7 +8040,7 @@ public class BatteryStatsImpl extends BatteryStats {
se = new Sensor(mBsi, this, sensor);
mSensorStats.put(sensor, se);
}
- StopwatchTimer t = se.mTimer;
+ DualTimer t = se.mTimer;
if (t != null) {
return t;
}
@@ -7838,28 +8049,12 @@ public class BatteryStatsImpl extends BatteryStats {
timers = new ArrayList<StopwatchTimer>();
mBsi.mSensorTimers.put(sensor, timers);
}
- t = new StopwatchTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
- mBsi.mOnBatteryTimeBase);
+ t = new DualTimer(mBsi.mClocks, this, BatteryStats.SENSOR, timers,
+ mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase);
se.mTimer = t;
return t;
}
- public Counter getSensorBgCounterLocked(int sensor, boolean create) {
- Sensor se = mSensorStats.get(sensor);
- if (se == null) {
- if (!create) {
- return null;
- }
- se = new Sensor(mBsi, this, sensor);
- mSensorStats.put(sensor, se);
- }
- Counter c = se.mBgCounter;
- if (c != null) return c;
- c = new Counter(mBsi.mOnBatteryTimeBase);
- se.mBgCounter = c;
- return c;
- }
-
public void noteStartSyncLocked(String name, long elapsedRealtimeMs) {
StopwatchTimer t = mSyncStats.startObject(name);
if (t != null) {
@@ -7932,39 +8127,24 @@ public class BatteryStatsImpl extends BatteryStats {
}
public void noteStartSensor(int sensor, long elapsedRealtimeMs) {
- StopwatchTimer t = getSensorTimerLocked(sensor, /* create= */ true);
+ DualTimer t = getSensorTimerLocked(sensor, /* create= */ true);
t.startRunningLocked(elapsedRealtimeMs);
-
- Counter c = getSensorBgCounterLocked(sensor, /* create= */ true);
- if (mProcessState >= PROCESS_STATE_BACKGROUND && t.mNesting == 1) {
- c.stepAtomic();
- }
}
public void noteStopSensor(int sensor, long elapsedRealtimeMs) {
// Don't create a timer if one doesn't already exist
- StopwatchTimer t = getSensorTimerLocked(sensor, false);
+ DualTimer t = getSensorTimerLocked(sensor, false);
if (t != null) {
t.stopRunningLocked(elapsedRealtimeMs);
}
}
public void noteStartGps(long elapsedRealtimeMs) {
- StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, /* create= */ true);
- t.startRunningLocked(elapsedRealtimeMs);
-
- Counter c = getSensorBgCounterLocked(Sensor.GPS, /* create= */ true);
- if (mProcessState >= PROCESS_STATE_BACKGROUND && t.mNesting == 1) {
- c.stepAtomic();
- }
+ noteStartSensor(Sensor.GPS, elapsedRealtimeMs);
}
public void noteStopGps(long elapsedRealtimeMs) {
- // Don't create a timer if one doesn't already exist
- StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
- if (t != null) {
- t.stopRunningLocked(elapsedRealtimeMs);
- }
+ noteStopSensor(Sensor.GPS, elapsedRealtimeMs);
}
public BatteryStatsImpl getBatteryStats() {
@@ -8955,7 +9135,7 @@ public class BatteryStatsImpl extends BatteryStats {
final Uid uid = mUidStats.valueAt(i);
// Sum the total scan power for all apps.
- totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked(
+ totalScanTimeMs += uid.mWifiScanTimer.getMainTimer().getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
// Sum the total time holding wifi lock for all apps.
@@ -8976,7 +9156,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i = 0; i < uidStatsSize; i++) {
final Uid uid = mUidStats.valueAt(i);
- long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
+ long scanTimeSinceMarkMs = uid.mWifiScanTimer.getMainTimer().getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
if (scanTimeSinceMarkMs > 0) {
// Set the new mark so that next time we get new data since this point.
@@ -9230,7 +9410,7 @@ public class BatteryStatsImpl extends BatteryStats {
mHasBluetoothReporting = true;
- final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+ final long elapsedRealtimeMs = mClocks.elapsedRealtime();
final long rxTimeMs = info.getControllerRxTimeMillis();
final long txTimeMs = info.getControllerTxTimeMillis();
@@ -9250,7 +9430,7 @@ public class BatteryStatsImpl extends BatteryStats {
continue;
}
- totalScanTimeMs += u.mBluetoothScanTimer.getTimeSinceMarkLocked(
+ totalScanTimeMs += u.mBluetoothScanTimer.getMainTimer().getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
}
@@ -9271,7 +9451,7 @@ public class BatteryStatsImpl extends BatteryStats {
continue;
}
- long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getTimeSinceMarkLocked(
+ long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getMainTimer().getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
if (scanTimeSinceMarkMs > 0) {
// Set the new mark so that next time we get new data since this point.
@@ -10777,6 +10957,8 @@ public class BatteryStatsImpl extends BatteryStats {
Uid u = new Uid(this, uid);
mUidStats.put(uid, u);
+ u.mOnBatteryBackgroundTimeBase.readSummaryFromParcel(in);
+
u.mWifiRunning = false;
if (in.readInt() != 0) {
u.mWifiRunningTimer.readSummaryFromParcelLocked(in);
@@ -10934,8 +11116,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int is = 0; is < NP; is++) {
int seNumber = in.readInt();
if (in.readInt() != 0) {
- u.getSensorTimerLocked(seNumber, true)
- .readSummaryFromParcelLocked(in);
+ u.getSensorTimerLocked(seNumber, true).readSummaryFromParcelLocked(in);
}
}
@@ -11141,6 +11322,8 @@ public class BatteryStatsImpl extends BatteryStats {
out.writeInt(mUidStats.keyAt(iu));
Uid u = mUidStats.valueAt(iu);
+ u.mOnBatteryBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
+
if (u.mWifiRunningTimer != null) {
out.writeInt(1);
u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -11724,7 +11907,7 @@ public class BatteryStatsImpl extends BatteryStats {
out.writeInt(mUidStats.keyAt(i));
Uid uid = mUidStats.valueAt(i);
- uid.writeToParcelLocked(out, uSecRealtime);
+ uid.writeToParcelLocked(out, uSecUptime, uSecRealtime);
}
} else {
out.writeInt(0);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
new file mode 100644
index 000000000000..6b52b98e4758
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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 static android.os.BatteryStats.STATS_SINCE_CHARGED;
+
+import android.app.ActivityManager;
+import android.os.BatteryStats;
+import android.os.WorkSource;
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Test BatteryStatsImpl onBatteryBackgroundTimeBase TimeBase.
+ */
+public class BatteryStatsBackgroundStatsTest extends TestCase {
+
+ private static final int UID = 10500;
+
+ /** Test that BatteryStatsImpl.Uid.mOnBatteryBackgroundTimeBase works correctly. */
+ @SmallTest
+ public void testBgTimeBase() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ long cur = 0; // realtime in us
+
+ BatteryStatsImpl.TimeBase bgtb = bi.getOnBatteryBackgroundTimeBase(UID);
+
+ // Off-battery, non-existent
+ clocks.realtime = clocks.uptime = 10;
+ cur = clocks.realtime * 1000;
+ bi.updateTimeBasesLocked(false, false, cur, cur); // off battery
+ assertFalse(bgtb.isRunning());
+ assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // Off-battery, foreground
+ clocks.realtime = clocks.uptime = 100;
+ cur = clocks.realtime * 1000;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ assertFalse(bgtb.isRunning());
+ assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // Off-battery, background
+ clocks.realtime = clocks.uptime = 201;
+ cur = clocks.realtime * 1000;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+ assertFalse(bgtb.isRunning());
+ assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // On-battery, background
+ clocks.realtime = clocks.uptime = 303;
+ cur = clocks.realtime * 1000;
+ bi.updateTimeBasesLocked(true, false, cur, cur); // on battery
+ // still in ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ assertTrue(bgtb.isRunning());
+ assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // On-battery, background - but change screen state
+ clocks.realtime = clocks.uptime = 409;
+ cur = clocks.realtime * 1000;
+ bi.updateTimeBasesLocked(true, true, cur, cur); // on battery (again)
+ assertTrue(bgtb.isRunning());
+ assertEquals(106_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // On-battery, background - but a different background state
+ clocks.realtime = clocks.uptime = 417;
+ cur = clocks.realtime * 1000;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER); // background too
+ assertTrue(bgtb.isRunning());
+ assertEquals(114_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // Off-battery, foreground
+ clocks.realtime = clocks.uptime = 530;
+ cur = clocks.realtime * 1000;
+ bi.updateTimeBasesLocked(false, false, cur, cur); // off battery
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ assertFalse(bgtb.isRunning());
+ assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+
+ // Off-battery, non-existent
+ clocks.realtime = clocks.uptime = 690;
+ cur = clocks.realtime * 1000;
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_NONEXISTENT);
+ assertFalse(bgtb.isRunning());
+ assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
+ }
+
+ @SmallTest
+ public void testWifiScan() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ long curr = 0; // realtime in us
+
+ // On battery
+ curr = 1000 * (clocks.realtime = clocks.uptime = 100);
+ bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+ // App in foreground
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+
+ // Start timer
+ curr = 1000 * (clocks.realtime = clocks.uptime = 202);
+ bi.noteWifiScanStartedLocked(UID);
+
+ // Move to background
+ curr = 1000 * (clocks.realtime = clocks.uptime = 254);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+ // Off battery
+ curr = 1000 * (clocks.realtime = clocks.uptime = 305);
+ bi.updateTimeBasesLocked(false, false, curr, curr); // off battery
+
+ // Stop timer
+ curr = 1000 * (clocks.realtime = clocks.uptime = 409);
+ bi.noteWifiScanStoppedLocked(UID);
+
+ // Test
+ curr = 1000 * (clocks.realtime = clocks.uptime = 657);
+ long time = bi.getUidStats().get(UID).getWifiScanTime(curr, STATS_SINCE_CHARGED);
+ int count = bi.getUidStats().get(UID).getWifiScanCount(STATS_SINCE_CHARGED);
+ int bgCount = bi.getUidStats().get(UID).getWifiScanBackgroundCount(STATS_SINCE_CHARGED);
+ long actualTime = bi.getUidStats().get(UID).getWifiScanActualTime(curr);
+ long bgTime = bi.getUidStats().get(UID).getWifiScanBackgroundTime(curr);
+ assertEquals((305 - 202) * 1000, time);
+ assertEquals(1, count);
+ assertEquals(1, bgCount);
+ assertEquals((305 - 202) * 1000, actualTime);
+ assertEquals((305 - 254) * 1000, bgTime);
+ }
+
+ @SmallTest
+ public void testAppBluetoothScan() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ WorkSource ws = new WorkSource(UID); // needed for bluetooth
+ long curr = 0; // realtime in us
+
+ // On battery
+ curr = 1000 * (clocks.realtime = clocks.uptime = 100);
+ bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+
+ // App in foreground
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+
+ // Start timer
+ curr = 1000 * (clocks.realtime = clocks.uptime = 202);
+ bi.noteBluetoothScanStartedFromSourceLocked(ws);
+
+ // Move to background
+ curr = 1000 * (clocks.realtime = clocks.uptime = 254);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+ // Off battery
+ curr = 1000 * (clocks.realtime = clocks.uptime = 305);
+ bi.updateTimeBasesLocked(false, false, curr, curr); // off battery
+
+ // Stop timer
+ curr = 1000 * (clocks.realtime = clocks.uptime = 409);
+ bi.noteBluetoothScanStoppedFromSourceLocked(ws);
+
+ // Test
+ curr = 1000 * (clocks.realtime = clocks.uptime = 657);
+ BatteryStats.Timer timer = bi.getUidStats().get(UID).getBluetoothScanTimer();
+ BatteryStats.Timer bgTimer = bi.getUidStats().get(UID).getBluetoothScanBackgroundTimer();
+
+ long time = timer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED);
+ int count = timer.getCountLocked(STATS_SINCE_CHARGED);
+ int bgCount = bgTimer.getCountLocked(STATS_SINCE_CHARGED);
+ long actualTime = timer.getTotalDurationMsLocked(clocks.realtime) * 1000;
+ long bgTime = bgTimer.getTotalDurationMsLocked(clocks.realtime) * 1000;
+ assertEquals((305 - 202) * 1000, time);
+ assertEquals(1, count);
+ assertEquals(1, bgCount);
+ assertEquals((305 - 202) * 1000, actualTime);
+ assertEquals((305 - 254) * 1000, bgTime);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index f1aeecc46265..a1b05cdbd9d8 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -44,18 +44,21 @@ public class BatteryStatsDurationTimerTest extends TestCase {
assertFalse(timer.isRunningLocked());
assertEquals(0, timer.getCurrentDurationMsLocked(300));
assertEquals(0, timer.getMaxDurationMsLocked(301));
+ assertEquals(0, timer.getTotalDurationMsLocked(301));
- // Start timer: current and max advance
+ // Start timer: current, total, and max advance
timer.startRunningLocked(700);
assertTrue(timer.isRunningLocked());
assertEquals(800, timer.getCurrentDurationMsLocked(1500));
assertEquals(801, timer.getMaxDurationMsLocked(1501));
+ assertEquals(802, timer.getTotalDurationMsLocked(1502));
- // Stop timer: current resets to 0, max remains
+ // Stop timer: current resets to 0; total and max remain
timer.stopRunningLocked(3100);
assertFalse(timer.isRunningLocked());
assertEquals(0, timer.getCurrentDurationMsLocked(6300));
assertEquals(2400, timer.getMaxDurationMsLocked(6301));
+ assertEquals(2400, timer.getTotalDurationMsLocked(6302));
// Start time again, but check with a short time, and make sure max doesn't
// increment.
@@ -63,31 +66,36 @@ public class BatteryStatsDurationTimerTest extends TestCase {
assertTrue(timer.isRunningLocked());
assertEquals(100, timer.getCurrentDurationMsLocked(12800));
assertEquals(2400, timer.getMaxDurationMsLocked(12801));
+ assertEquals(2502, timer.getTotalDurationMsLocked(12802));
// 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));
+ assertEquals(2600, timer.getTotalDurationMsLocked(13002));
// 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));
+ assertEquals(2600, timer.getTotalDurationMsLocked(27000));
// Stop the TimeBase. The values should be frozen.
timeBase.setRunning(false, /* uptimeUs */ 10, /* realtimeUs */ 55000*1000);
assertTrue(timer.isRunningLocked());
assertEquals(28000, timer.getCurrentDurationMsLocked(110100));
assertEquals(28000, timer.getMaxDurationMsLocked(110101));
+ assertEquals(30600, timer.getTotalDurationMsLocked(110102));
// Start the TimeBase. The values should be the old value plus the delta
- // between when the timer restarted and the current time
+ // between when the timer restarted and the current time.
timeBase.setRunning(true, /* uptimeUs */ 10, /* realtimeUs */ 220100*1000);
assertTrue(timer.isRunningLocked());
assertEquals(28200, timer.getCurrentDurationMsLocked(220300));
assertEquals(28201, timer.getMaxDurationMsLocked(220301));
+ assertEquals(30802, timer.getTotalDurationMsLocked(220302));
}
@SmallTest
@@ -114,6 +122,7 @@ public class BatteryStatsDurationTimerTest extends TestCase {
// Check that it did start running
assertEquals(400, timer.getMaxDurationMsLocked(700));
assertEquals(401, timer.getCurrentDurationMsLocked(701));
+ assertEquals(402, timer.getTotalDurationMsLocked(702));
// Write summary
final Parcel summaryParcel = Parcel.obtain();
@@ -128,8 +137,9 @@ public class BatteryStatsDurationTimerTest extends TestCase {
// 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
+ // The new one should have the max and total durations that we had when we wrote it
assertEquals(1200, summary.getMaxDurationMsLocked(6301));
+ assertEquals(1200, summary.getTotalDurationMsLocked(6302));
// Write full
final Parcel fullParcel = Parcel.obtain();
@@ -142,7 +152,9 @@ public class BatteryStatsDurationTimerTest extends TestCase {
// 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
+ // The new one should have the max and total durations that we had when we wrote it
assertEquals(1200, full.getMaxDurationMsLocked(6301));
+ assertEquals(1200, full.getTotalDurationMsLocked(6302));
+
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index b4afddab97c9..251ceb04b973 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -146,6 +146,8 @@ public class BatteryStatsSamplingTimerTest extends TestCase {
BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
// Start running on battery.
+ // (Note that the wrong units are used in this class. setRunning is actually supposed to
+ // take us, not the ms that clocks uses.)
timeBase.setRunning(true, clocks.uptimeMillis(), clocks.elapsedRealtime());
// The first update on battery consumes the values as a way of starting cleanly.
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index 4ec78ff5be7f..a41a0235bef4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -17,9 +17,7 @@ package com.android.internal.os;
import android.app.ActivityManager;
import android.os.BatteryStats;
-import android.os.Debug;
import android.support.test.filters.SmallTest;
-import android.util.Log;
import junit.framework.TestCase;
@@ -31,6 +29,9 @@ public class BatteryStatsSensorTest extends TestCase {
private static final int UID = 10500;
private static final int SENSOR_ID = -10000;
+ // TODO: fix the bug in StopwatchTimer to prevent this bug from manifesting here.
+ boolean revealCntBug = false;
+
@SmallTest
public void testSensorStartStop() throws Exception {
final MockClocks clocks = new MockClocks();
@@ -38,7 +39,7 @@ public class BatteryStatsSensorTest extends TestCase {
bi.mForceOnBattery = true;
clocks.realtime = 100;
clocks.uptime = 100;
- bi.getOnBatteryTimeBase().setRunning(true, 100, 100);
+ bi.getOnBatteryTimeBase().setRunning(true, 100_000, 100_000);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
bi.noteStartSensorLocked(UID, SENSOR_ID);
@@ -56,58 +57,345 @@ public class BatteryStatsSensorTest extends TestCase {
BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats()
.get(SENSOR_ID).getSensorTime();
- BatteryStats.Counter sensorBgCounter = bi.getUidStats().get(UID).getSensorStats()
- .get(SENSOR_ID).getSensorBgCount();
+ BatteryStats.Timer sensorBgTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorBackgroundTime();
assertEquals(2, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(300000,
- sensorTimer.getTotalTimeLocked(clocks.realtime, BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(300_000, sensorTimer.getTotalTimeLocked(
+ clocks.realtime * 1000, BatteryStats.STATS_SINCE_CHARGED));
+
+ assertEquals(1, sensorBgTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(200_000, sensorBgTimer.getTotalTimeLocked(
+ clocks.realtime * 1000, BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ @SmallTest
+ public void testCountingWhileOffBattery() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ long curr = 0; // realtime in us
+
+ // Plugged-in (battery=off, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 100);
+ bi.updateTimeBasesLocked(false, false, curr, curr);
+
+
+ // Start sensor (battery=off, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 200);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ // Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 215);
+ BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ assertEquals(0,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ if(revealCntBug) {
+ assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ } else {
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ // Stop sensor (battery=off, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 550);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ // Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 678);
+ sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ assertEquals(0,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ @SmallTest
+ public void testCountingWhileOnBattery() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ long curr = 0; // realtime in us
+
+ // Unplugged (battery=on, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 100);
+ bi.updateTimeBasesLocked(true, false, curr, curr);
+
+ // Start sensor (battery=on, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 200);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ // Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 215);
+ BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ assertEquals((215-200)*1000,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+ // Stop sensor (battery=on, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 550);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ // Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 678);
+ sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ assertEquals((550-200)*1000,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ @SmallTest
+ public void testBatteryStatusOnToOff() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ long curr = 0; // realtime in us
+
+ // On battery (battery=on, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 100);
+ bi.updateTimeBasesLocked(true, false, curr, curr);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+
+ // Start sensor (battery=on, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 202);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ // Off battery (battery=off, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 305);
+ bi.updateTimeBasesLocked(false, false, curr, curr);
+
+ // Stop sensor while off battery (battery=off, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 409);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ // Start sensor while off battery (battery=off, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 519);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ // Test while still running (but off battery)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 657);
+ BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ if(revealCntBug) {
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ } else {
+ assertEquals(2, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+ assertEquals((305-202)*1000,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+
+ // Now stop running (still off battery) (battery=off, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 693);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals((305-202)*1000,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ @SmallTest
+ public void testBatteryStatusOffToOn() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ long curr = 0; // realtime in us
+
+ // Plugged-in (battery=off, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 100);
+ bi.updateTimeBasesLocked(false, false, curr, curr);
+
+ // Start sensor (battery=off, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 200);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ // Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 215);
+ BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ // Time was entirely off battery, so time=0.
+ assertEquals(0,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ // Acquired off battery, so count=0.
+ if(revealCntBug) {
+ assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ } else {
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ // Unplug (battery=on, sensor=on)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 305);
+ bi.updateTimeBasesLocked(true, false, curr, curr);
+
+ //Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 410);
+ sensorTimer = bi.getUidStats().get(UID).getSensorStats().get(SENSOR_ID).getSensorTime();
+ // Part of the time it was on battery.
+ assertEquals((410-305)*1000,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ // Only ever acquired off battery, so count=0.
+ if(revealCntBug) {
+ assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ } else {
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
+
+ // Stop sensor (battery=on, sensor=off)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 550);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
- assertEquals(1, sensorBgCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ // Test situation
+ curr = 1000 * (clocks.realtime = clocks.uptime = 678);
+ sensorTimer = bi.getUidStats().get(UID).getSensorStats().get(SENSOR_ID).getSensorTime();
+ // Part of the time it was on battery.
+ assertEquals((550-305)*1000,
+ sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ // Only ever acquired off battery, so count=0.
+ if(revealCntBug) {
+ assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ } else {
+ assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
}
@SmallTest
- public void testNestedSensorReset() throws Exception {
+ public void testPooledBackgroundUsage() throws Exception {
+ final int UID_2 = 20000; // second uid for testing pool usage
final MockClocks clocks = new MockClocks();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.mForceOnBattery = true;
- clocks.realtime = 100;
- clocks.uptime = 100;
- bi.getOnBatteryTimeBase().setRunning(true, 100, 100);
- bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER);
+ long curr = 0; // realtime in us
+ // Entire test is on-battery
+ curr = 1000 * (clocks.realtime = clocks.uptime = 1000);
+ bi.updateTimeBasesLocked(true, false, curr, curr);
- clocks.realtime += 100;
- clocks.uptime += 100;
+ // See below for a diagram of events.
+ // UID in foreground
+ curr = 1000 * (clocks.realtime = clocks.uptime = 2002);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+
+ // UID starts the sensor (foreground)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 3004);
bi.noteStartSensorLocked(UID, SENSOR_ID);
- clocks.realtime += 100;
- clocks.uptime += 100;
+ // UID_2 in background
+ curr = 1000 * (clocks.realtime = clocks.uptime = 4008);
+ bi.noteUidProcessStateLocked(UID_2, ActivityManager.PROCESS_STATE_RECEIVER); // background
+
+ // UID_2 starts the sensor (background)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 5016);
+ bi.noteStartSensorLocked(UID_2, SENSOR_ID);
- // The sensor is started and the background counter has been created.
- final BatteryStats.Uid uid = bi.getUidStats().get(UID);
- assertNotNull(uid);
+ // UID enters background
+ curr = 1000 * (clocks.realtime = clocks.uptime = 6032);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
- BatteryStats.Uid.Sensor sensor = uid.getSensorStats().get(SENSOR_ID);
- assertNotNull(sensor);
- assertNotNull(sensor.getSensorTime());
- assertNotNull(sensor.getSensorBgCount());
+ // UID enters background again (from a different background state)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 7004);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
- // Reset the stats. Since the sensor is still running, we should still see the sensor
- // timer. Background counter should be gone though.
- bi.getUidStatsLocked(UID).reset();
+ // UID_2 stops the sensor (background), then starts it again, then stops again
+ curr = 1000 * (clocks.realtime = clocks.uptime = 8064);
+ bi.noteStopSensorLocked(UID_2, SENSOR_ID);
+ curr = 1000 * (clocks.realtime = clocks.uptime = 9128);
+ bi.noteStartSensorLocked(UID_2, SENSOR_ID);
+ curr = 1000 * (clocks.realtime = clocks.uptime = 10256);
+ bi.noteStopSensorLocked(UID_2, SENSOR_ID);
- sensor = uid.getSensorStats().get(SENSOR_ID);
- assertNotNull(sensor);
- assertNotNull(sensor.getSensorTime());
- assertNull(sensor.getSensorBgCount());
+ // UID re-enters foreground
+ curr = 1000 * (clocks.realtime = clocks.uptime = 11512);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+
+ // UID starts the sensor a second time (foreground)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 12000);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+ // UID re-enters background
+ curr = 1000 * (clocks.realtime = clocks.uptime = 13002);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+ // UID stops the sensor completely (background)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 14004);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+ curr = 1000 * (clocks.realtime = clocks.uptime = 14024);
bi.noteStopSensorLocked(UID, SENSOR_ID);
- // Now the sensor timer has stopped so this reset should also take out the sensor.
- bi.getUidStatsLocked(UID).reset();
+ // UID starts the sensor anew (background)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 15010);
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ // UID stops the sensor (background)
+ curr = 1000 * (clocks.realtime = clocks.uptime = 16020);
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+// Summary
+// UID
+// foreground: 2002---6032, 11512---13002
+// background: 6032---------------11512, 13002--------------------------
+// sensor running: 3004-----------------------------14024, 15010-16020
+//
+// UID2
+// foreground:
+// background: 4008-------------------------------------------------------
+// sensor running: 5016--8064, 9128-10256
+
+ BatteryStats.Timer timer1 = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ BatteryStats.Timer bgTimer1 = bi.getUidStats().get(UID).getSensorStats()
+ .get(SENSOR_ID).getSensorBackgroundTime();
+
+ BatteryStats.Timer timer2 = bi.getUidStats().get(UID_2).getSensorStats()
+ .get(SENSOR_ID).getSensorTime();
+ BatteryStats.Timer bgTimer2 = bi.getUidStats().get(UID_2).getSensorStats()
+ .get(SENSOR_ID).getSensorBackgroundTime();
+
+ // Expected values
+ long expActualTime1 = (14024 - 3004) + (16020 - 15010);
+ long expBgTime1 = (11512 - 6032) + (14024 - 13002) + (16020 - 15010);
+
+ long expActualTime2 = (8064 - 5016) + (10256 - 9128);
+ long expBgTime2 = (8064 - 5016) + (10256 - 9128);
+
+ long expBlamedTime1 = (5016 - 3004) + (8064 - 5016)/2 + (9128 - 8064) + (10256 - 9128)/2
+ + (14024 - 10256) + (16020 - 15010);
+ long expBlamedTime2 = (8064 - 5016)/2 + (10256 - 9128)/2;
+
+ // Test: UID - blamed time
+ assertEquals(expBlamedTime1 * 1000,
+ timer1.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ // Test: UID - actual time
+ assertEquals(expActualTime1 * 1000,
+ timer1.getTotalDurationMsLocked(clocks.realtime) * 1000 );
+ // Test: UID - background time
+ // bg timer ignores pools, so both totalTime and totalDuration should give the same result
+ assertEquals(expBgTime1 * 1000,
+ bgTimer1.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(expBgTime1 * 1000,
+ bgTimer1.getTotalDurationMsLocked(clocks.realtime) * 1000 );
+ // Test: UID - count
+ assertEquals(2, timer1.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ // Test: UID - background count
+ if(revealCntBug) {
+ assertEquals(1, bgTimer1.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ } else {
+ assertEquals(2, bgTimer1.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ }
- sensor = uid.getSensorStats().get(SENSOR_ID);
- assertNull(sensor);
+ // Test: UID_2 - blamed time
+ assertEquals(expBlamedTime2 * 1000,
+ timer2.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ // Test: UID_2 - actual time
+ assertEquals(expActualTime2 * 1000,
+ timer2.getTotalDurationMsLocked(clocks.realtime) * 1000);
+ // Test: UID_2 - background time
+ // bg timer ignores pools, so both totalTime and totalDuration should give the same result
+ assertEquals(expBgTime2 * 1000,
+ bgTimer2.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED));
+ assertEquals(expBgTime2 * 1000,
+ bgTimer2.getTotalDurationMsLocked(clocks.realtime) * 1000 );
+ // Test: UID_2 - count
+ assertEquals(2, timer2.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+ // Test: UID_2 - background count
+ assertEquals(2, bgTimer2.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
}
}
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 c7cd0ee710e1..11132683d4d1 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -12,6 +12,7 @@ import org.junit.runners.Suite;
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
BatteryStatsSensorTest.class,
+ BatteryStatsBackgroundStatsTest.class,
})
public class BatteryStatsTests {
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 10541060398a..65f898c62815 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -26,6 +26,7 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
MockBatteryStatsImpl(Clocks clocks) {
super(clocks);
this.clocks = mClocks;
+ mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
}
MockBatteryStatsImpl() {
@@ -39,5 +40,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
public boolean isOnBattery() {
return mForceOnBattery ? true : super.isOnBattery();
}
+
+ public TimeBase getOnBatteryBackgroundTimeBase(int uid) {
+ return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase;
+ }
}