Loading core/java/android/os/BatteryStats.java +27 −2 Original line number Original line Diff line number Diff line Loading @@ -182,7 +182,7 @@ public abstract class BatteryStats implements Parcelable { * New in version 19: * New in version 19: * - Wakelock data (wl) gets current and max times. * - Wakelock data (wl) gets current and max times. * New in version 20: * New in version 20: * - Sensor, BluetoothScan, WifiScan get background timers and counter. * - Background timers and counters for: Sensor, BluetoothScan, WifiScan, Jobs. */ */ static final String CHECKIN_VERSION = "20"; static final String CHECKIN_VERSION = "20"; Loading Loading @@ -391,6 +391,16 @@ public abstract class BatteryStats implements Parcelable { return -1; return -1; } } /** * Returns the secondary Timer held by the Timer, if one exists. This secondary timer may be * used, for example, for tracking background usage. Secondary timers are never pooled. * * Not all Timer subclasses have a secondary timer; those that don't return null. */ public Timer getSubTimer() { return null; } /** /** * Returns whether the timer is currently running. Some types of timers * Returns whether the timer is currently running. Some types of timers * (e.g. BatchTimers) don't know whether the event is currently active, * (e.g. BatchTimers) don't know whether the event is currently active, Loading Loading @@ -3393,9 +3403,13 @@ public abstract class BatteryStats implements Parcelable { // Convert from microseconds to milliseconds with rounding // 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 count = timer.getCountLocked(which); final Timer bgTimer = timer.getSubTimer(); final long bgTime = bgTimer != null ? (bgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : -1; final int bgCount = bgTimer != null ? bgTimer.getCountLocked(which) : -1; if (totalTime != 0) { if (totalTime != 0) { dumpLine(pw, uid, category, JOB_DATA, "\"" + jobs.keyAt(ij) + "\"", dumpLine(pw, uid, category, JOB_DATA, "\"" + jobs.keyAt(ij) + "\"", totalTime, count); totalTime, count, bgTime, bgCount); } } } } Loading Loading @@ -4616,6 +4630,10 @@ public abstract class BatteryStats implements Parcelable { // Convert from microseconds to milliseconds with rounding // 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 count = timer.getCountLocked(which); final Timer bgTimer = timer.getSubTimer(); final long bgTime = bgTimer != null ? (bgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : -1; final int bgCount = bgTimer != null ? bgTimer.getCountLocked(which) : -1; sb.setLength(0); sb.setLength(0); sb.append(prefix); sb.append(prefix); sb.append(" Job "); sb.append(" Job "); Loading @@ -4626,6 +4644,13 @@ public abstract class BatteryStats implements Parcelable { sb.append("realtime ("); sb.append("realtime ("); sb.append(count); sb.append(count); sb.append(" times)"); sb.append(" times)"); if (bgTime > 0) { sb.append(", "); formatTimeMs(sb, bgTime); sb.append("background ("); sb.append(bgCount); sb.append(" times)"); } } else { } else { sb.append("(not used)"); sb.append("(not used)"); } } Loading core/java/com/android/internal/os/BatteryStatsImpl.java +58 −79 Original line number Original line Diff line number Diff line Loading @@ -114,7 +114,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version // Current on-disk Parcel version private static final int VERSION = 152 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 153 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -2006,107 +2006,92 @@ public class BatteryStatsImpl extends BatteryStats { * State for keeping track of two DurationTimers with different TimeBases, presumably where one * State for keeping track of two DurationTimers with different TimeBases, presumably where one * TimeBase is effectively a subset of the other. * TimeBase is effectively a subset of the other. */ */ public static class DualTimer { public static class DualTimer extends DurationTimer { // mMainTimer typically tracks the total time. May be pooled (but since it's a durationTimer, // This class both is a DurationTimer and also holds a second DurationTimer. // it also has the unpooled getTotalDurationMsLocked() for STATS_SINCE_CHARGED). // The main timer (this) typically tracks the total time. It may be pooled (but since it's a private final DurationTimer mMainTimer; // durationTimer, it also has the unpooled getTotalDurationMsLocked() for // STATS_SINCE_CHARGED). // mSubTimer typically tracks only part of the total time, such as background time, as // mSubTimer typically tracks only part of the total time, such as background time, as // determined by a subTimeBase. It is NOT pooled. // determined by a subTimeBase. It is NOT pooled. private final DurationTimer mSubTimer; private final DurationTimer mSubTimer; /** /** * Creates a DualTimer to hold a mMainTimer and a mSubTimer. * Creates a DualTimer to hold a main timer (this) and a mSubTimer. * The mMainTimer is based on the given timeBase and timerPool. * The main timer (this) is based on the given timeBase and timerPool. * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * the mMainTimer is. * the main timer is. */ */ public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase, TimeBase subTimeBase, Parcel in) { TimeBase timeBase, TimeBase subTimeBase, Parcel in) { mMainTimer = new DurationTimer(clocks, uid, type, timerPool, timeBase, in); super(clocks, uid, type, timerPool, timeBase, in); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase, in); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase, in); } } /** /** * Creates a DualTimer to hold a mMainTimer and a mSubTimer. * Creates a DualTimer to hold a main timer (this) and a mSubTimer. * The mMainTimer is based on the given timeBase and timerPool. * The main timer (this) is based on the given timeBase and timerPool. * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * the mMainTimer is. * the main timer is. */ */ public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase, TimeBase subTimeBase) { TimeBase timeBase, TimeBase subTimeBase) { mMainTimer = new DurationTimer(clocks, uid, type, timerPool, timeBase); super(clocks, uid, type, timerPool, timeBase); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase); } } /** Get the main timer. */ public DurationTimer getMainTimer() { return mMainTimer; } /** Get the secondary timer. */ /** Get the secondary timer. */ @Override public DurationTimer getSubTimer() { public DurationTimer getSubTimer() { return mSubTimer; return mSubTimer; } } @Override public void startRunningLocked(long elapsedRealtimeMs) { public void startRunningLocked(long elapsedRealtimeMs) { mMainTimer.startRunningLocked(elapsedRealtimeMs); super.startRunningLocked(elapsedRealtimeMs); mSubTimer.startRunningLocked(elapsedRealtimeMs); mSubTimer.startRunningLocked(elapsedRealtimeMs); } } @Override public void stopRunningLocked(long elapsedRealtimeMs) { public void stopRunningLocked(long elapsedRealtimeMs) { mMainTimer.stopRunningLocked(elapsedRealtimeMs); super.stopRunningLocked(elapsedRealtimeMs); mSubTimer.stopRunningLocked(elapsedRealtimeMs); mSubTimer.stopRunningLocked(elapsedRealtimeMs); } } @Override public void stopAllRunningLocked(long elapsedRealtimeMs) { public void stopAllRunningLocked(long elapsedRealtimeMs) { mMainTimer.stopAllRunningLocked(elapsedRealtimeMs); super.stopAllRunningLocked(elapsedRealtimeMs); mSubTimer.stopAllRunningLocked(elapsedRealtimeMs); mSubTimer.stopAllRunningLocked(elapsedRealtimeMs); } } public void setMark(long elapsedRealtimeMs) { @Override mMainTimer.setMark(elapsedRealtimeMs); mSubTimer.setMark(elapsedRealtimeMs); } public boolean reset(boolean detachIfReset) { public boolean reset(boolean detachIfReset) { boolean active = false; boolean active = false; active |= !mMainTimer.reset(detachIfReset); active |= !super.reset(detachIfReset); active |= !mSubTimer.reset(detachIfReset); active |= !mSubTimer.reset(detachIfReset); return !active; return !active; } } @Override public void detach() { public void detach() { mMainTimer.detach(); super.detach(); mSubTimer.detach(); mSubTimer.detach(); } } /** @Override * 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) { public void writeToParcel(Parcel out, long elapsedRealtimeUs) { mMainTimer.writeToParcel(out, elapsedRealtimeUs); super.writeToParcel(out, elapsedRealtimeUs); mSubTimer.writeToParcel(out, elapsedRealtimeUs); mSubTimer.writeToParcel(out, elapsedRealtimeUs); } } @Override public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) { public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) { mMainTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); mSubTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); mSubTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); } } @Override public void readSummaryFromParcelLocked(Parcel in) { public void readSummaryFromParcelLocked(Parcel in) { mMainTimer.readSummaryFromParcelLocked(in); super.readSummaryFromParcelLocked(in); mSubTimer.readSummaryFromParcelLocked(in); mSubTimer.readSummaryFromParcelLocked(in); } } } } Loading Loading @@ -5488,7 +5473,7 @@ public class BatteryStatsImpl extends BatteryStats { /** /** * The statistics we have collected for this uid's jobs. * The statistics we have collected for this uid's jobs. */ */ final OverflowArrayMap<StopwatchTimer> mJobStats; final OverflowArrayMap<DualTimer> mJobStats; /** /** * The statistics we have collected for this uid's sensor activations. * The statistics we have collected for this uid's sensor activations. Loading Loading @@ -5533,10 +5518,10 @@ public class BatteryStatsImpl extends BatteryStats { mBsi.mOnBatteryTimeBase); mBsi.mOnBatteryTimeBase); } } }; }; mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>(uid) { mJobStats = mBsi.new OverflowArrayMap<DualTimer>(uid) { @Override public StopwatchTimer instantiateObject() { @Override public DualTimer instantiateObject() { return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null, return new DualTimer(mBsi.mClocks, Uid.this, JOB, null, mBsi.mOnBatteryTimeBase); mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase); } } }; }; Loading Loading @@ -5918,7 +5903,7 @@ public class BatteryStatsImpl extends BatteryStats { if (mWifiScanTimer == null) { if (mWifiScanTimer == null) { return 0; return 0; } } return mWifiScanTimer.getMainTimer().getTotalTimeLocked(elapsedRealtimeUs, which); return mWifiScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } } @Override @Override Loading @@ -5926,12 +5911,12 @@ public class BatteryStatsImpl extends BatteryStats { if (mWifiScanTimer == null) { if (mWifiScanTimer == null) { return 0; return 0; } } return mWifiScanTimer.getMainTimer().getCountLocked(which); return mWifiScanTimer.getCountLocked(which); } } @Override @Override public int getWifiScanBackgroundCount(int which) { public int getWifiScanBackgroundCount(int which) { if (mWifiScanTimer == null) { if (mWifiScanTimer == null || mWifiScanTimer.getSubTimer() == null) { return 0; return 0; } } return mWifiScanTimer.getSubTimer().getCountLocked(which); return mWifiScanTimer.getSubTimer().getCountLocked(which); Loading @@ -5943,12 +5928,12 @@ public class BatteryStatsImpl extends BatteryStats { return 0; return 0; } } final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; return mWifiScanTimer.getMainTimer().getTotalDurationMsLocked(elapsedRealtimeMs) * 1000; return mWifiScanTimer.getTotalDurationMsLocked(elapsedRealtimeMs) * 1000; } } @Override @Override public long getWifiScanBackgroundTime(final long elapsedRealtimeUs) { public long getWifiScanBackgroundTime(final long elapsedRealtimeUs) { if (mWifiScanTimer == null) { if (mWifiScanTimer == null || mWifiScanTimer.getSubTimer() == null) { return 0; return 0; } } final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; Loading Loading @@ -6008,10 +5993,7 @@ public class BatteryStatsImpl extends BatteryStats { @Override @Override public Timer getBluetoothScanTimer() { public Timer getBluetoothScanTimer() { if (mBluetoothScanTimer == null) { return mBluetoothScanTimer; return null; } return mBluetoothScanTimer.getMainTimer(); } } @Override @Override Loading Loading @@ -6361,9 +6343,9 @@ public class BatteryStatsImpl extends BatteryStats { } } } } mSyncStats.cleanup(); mSyncStats.cleanup(); final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap(); final ArrayMap<String, DualTimer> jobStats = mJobStats.getMap(); for (int ij=jobStats.size()-1; ij>=0; ij--) { for (int ij=jobStats.size()-1; ij>=0; ij--) { StopwatchTimer timer = jobStats.valueAt(ij); DualTimer timer = jobStats.valueAt(ij); if (timer.reset(false)) { if (timer.reset(false)) { jobStats.removeAt(ij); jobStats.removeAt(ij); timer.detach(); timer.detach(); Loading Loading @@ -6531,12 +6513,12 @@ public class BatteryStatsImpl extends BatteryStats { Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); } } final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap(); final ArrayMap<String, DualTimer> jobStats = mJobStats.getMap(); int NJ = jobStats.size(); int NJ = jobStats.size(); out.writeInt(NJ); out.writeInt(NJ); for (int ij=0; ij<NJ; ij++) { for (int ij=0; ij<NJ; ij++) { out.writeString(jobStats.keyAt(ij)); out.writeString(jobStats.keyAt(ij)); StopwatchTimer timer = jobStats.valueAt(ij); DualTimer timer = jobStats.valueAt(ij); Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); } } Loading Loading @@ -6756,8 +6738,8 @@ public class BatteryStatsImpl extends BatteryStats { for (int j = 0; j < numJobs; j++) { for (int j = 0; j < numJobs; j++) { String jobName = in.readString(); String jobName = in.readString(); if (in.readInt() != 0) { if (in.readInt() != 0) { mJobStats.add(jobName, new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null, mJobStats.add(jobName, new DualTimer(mBsi.mClocks, Uid.this, JOB, null, timeBase, in)); mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase, in)); } } } } Loading Loading @@ -7196,15 +7178,12 @@ public class BatteryStatsImpl extends BatteryStats { } } void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { DualTimer.writeDualTimerToParcel(out, mTimer, elapsedRealtimeUs); Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs); } } @Override @Override public Timer getSensorTime() { public Timer getSensorTime() { if (mTimer == null) { return mTimer; return null; } return mTimer.getMainTimer(); } } @Override @Override Loading Loading @@ -8023,7 +8002,7 @@ public class BatteryStatsImpl extends BatteryStats { } } public void readJobSummaryFromParcelLocked(String name, Parcel in) { public void readJobSummaryFromParcelLocked(String name, Parcel in) { StopwatchTimer timer = mJobStats.instantiateObject(); DualTimer timer = mJobStats.instantiateObject(); timer.readSummaryFromParcelLocked(in); timer.readSummaryFromParcelLocked(in); mJobStats.add(name, timer); mJobStats.add(name, timer); } } Loading Loading @@ -8084,14 +8063,14 @@ public class BatteryStatsImpl extends BatteryStats { } } public void noteStartJobLocked(String name, long elapsedRealtimeMs) { public void noteStartJobLocked(String name, long elapsedRealtimeMs) { StopwatchTimer t = mJobStats.startObject(name); DualTimer t = mJobStats.startObject(name); if (t != null) { if (t != null) { t.startRunningLocked(elapsedRealtimeMs); t.startRunningLocked(elapsedRealtimeMs); } } } } public void noteStopJobLocked(String name, long elapsedRealtimeMs) { public void noteStopJobLocked(String name, long elapsedRealtimeMs) { StopwatchTimer t = mJobStats.stopObject(name); DualTimer t = mJobStats.stopObject(name); if (t != null) { if (t != null) { t.stopRunningLocked(elapsedRealtimeMs); t.stopRunningLocked(elapsedRealtimeMs); } } Loading Loading @@ -9149,7 +9128,7 @@ public class BatteryStatsImpl extends BatteryStats { final Uid uid = mUidStats.valueAt(i); final Uid uid = mUidStats.valueAt(i); // Sum the total scan power for all apps. // Sum the total scan power for all apps. totalScanTimeMs += uid.mWifiScanTimer.getMainTimer().getTimeSinceMarkLocked( totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; // Sum the total time holding wifi lock for all apps. // Sum the total time holding wifi lock for all apps. Loading @@ -9170,7 +9149,7 @@ public class BatteryStatsImpl extends BatteryStats { for (int i = 0; i < uidStatsSize; i++) { for (int i = 0; i < uidStatsSize; i++) { final Uid uid = mUidStats.valueAt(i); final Uid uid = mUidStats.valueAt(i); long scanTimeSinceMarkMs = uid.mWifiScanTimer.getMainTimer().getTimeSinceMarkLocked( long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; if (scanTimeSinceMarkMs > 0) { if (scanTimeSinceMarkMs > 0) { // Set the new mark so that next time we get new data since this point. // Set the new mark so that next time we get new data since this point. Loading Loading @@ -9444,7 +9423,7 @@ public class BatteryStatsImpl extends BatteryStats { continue; continue; } } totalScanTimeMs += u.mBluetoothScanTimer.getMainTimer().getTimeSinceMarkLocked( totalScanTimeMs += u.mBluetoothScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; } } Loading @@ -9465,7 +9444,7 @@ public class BatteryStatsImpl extends BatteryStats { continue; continue; } } long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getMainTimer().getTimeSinceMarkLocked( long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; if (scanTimeSinceMarkMs > 0) { if (scanTimeSinceMarkMs > 0) { // Set the new mark so that next time we get new data since this point. // Set the new mark so that next time we get new data since this point. Loading Loading @@ -11526,7 +11505,7 @@ public class BatteryStatsImpl extends BatteryStats { syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS); syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS); } } final ArrayMap<String, StopwatchTimer> jobStats = u.mJobStats.getMap(); final ArrayMap<String, DualTimer> jobStats = u.mJobStats.getMap(); int NJ = jobStats.size(); int NJ = jobStats.size(); out.writeInt(NJ); out.writeInt(NJ); for (int ij=0; ij<NJ; ij++) { for (int ij=0; ij<NJ; ij++) { Loading core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java +62 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.ActivityManager; import android.os.BatteryStats; import android.os.BatteryStats; import android.os.WorkSource; import android.os.WorkSource; import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest; import android.util.ArrayMap; import junit.framework.TestCase; import junit.framework.TestCase; Loading Loading @@ -187,4 +188,65 @@ public class BatteryStatsBackgroundStatsTest extends TestCase { assertEquals((305 - 202) * 1000, actualTime); assertEquals((305 - 202) * 1000, actualTime); assertEquals((305 - 254) * 1000, bgTime); assertEquals((305 - 254) * 1000, bgTime); } } @SmallTest public void testJob() throws Exception { final MockClocks clocks = new MockClocks(); MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); final String jobName = "job_name"; 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 = 151); bi.noteJobStartLocked(jobName, UID); // Stop timer curr = 1000 * (clocks.realtime = clocks.uptime = 161); bi.noteJobFinishLocked(jobName, UID); // Start timer curr = 1000 * (clocks.realtime = clocks.uptime = 202); bi.noteJobStartLocked(jobName, 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.noteJobFinishLocked(jobName, UID); // Test curr = 1000 * (clocks.realtime = clocks.uptime = 657); final ArrayMap<String, ? extends BatteryStats.Timer> jobs = bi.getUidStats().get(UID).getJobStats(); assertEquals(1, jobs.size()); BatteryStats.Timer timer = jobs.valueAt(0); BatteryStats.Timer bgTimer = timer.getSubTimer(); long time = timer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); int count = timer.getCountLocked(STATS_SINCE_CHARGED); int bgCount = bgTimer.getCountLocked(STATS_SINCE_CHARGED); long bgTime = bgTimer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); assertEquals((161 - 151 + 305 - 202) * 1000, time); assertEquals(2, count); assertEquals(1, bgCount); assertEquals((305 - 254) * 1000, bgTime); // Test that a second job is separate. curr = 1000 * (clocks.realtime = clocks.uptime = 3000); final String jobName2 = "second_job"; bi.noteJobStartLocked(jobName2, UID); assertEquals(2, bi.getUidStats().get(UID).getJobStats().size()); bi.noteJobFinishLocked(jobName2, UID); } } } Loading
core/java/android/os/BatteryStats.java +27 −2 Original line number Original line Diff line number Diff line Loading @@ -182,7 +182,7 @@ public abstract class BatteryStats implements Parcelable { * New in version 19: * New in version 19: * - Wakelock data (wl) gets current and max times. * - Wakelock data (wl) gets current and max times. * New in version 20: * New in version 20: * - Sensor, BluetoothScan, WifiScan get background timers and counter. * - Background timers and counters for: Sensor, BluetoothScan, WifiScan, Jobs. */ */ static final String CHECKIN_VERSION = "20"; static final String CHECKIN_VERSION = "20"; Loading Loading @@ -391,6 +391,16 @@ public abstract class BatteryStats implements Parcelable { return -1; return -1; } } /** * Returns the secondary Timer held by the Timer, if one exists. This secondary timer may be * used, for example, for tracking background usage. Secondary timers are never pooled. * * Not all Timer subclasses have a secondary timer; those that don't return null. */ public Timer getSubTimer() { return null; } /** /** * Returns whether the timer is currently running. Some types of timers * Returns whether the timer is currently running. Some types of timers * (e.g. BatchTimers) don't know whether the event is currently active, * (e.g. BatchTimers) don't know whether the event is currently active, Loading Loading @@ -3393,9 +3403,13 @@ public abstract class BatteryStats implements Parcelable { // Convert from microseconds to milliseconds with rounding // 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 count = timer.getCountLocked(which); final Timer bgTimer = timer.getSubTimer(); final long bgTime = bgTimer != null ? (bgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : -1; final int bgCount = bgTimer != null ? bgTimer.getCountLocked(which) : -1; if (totalTime != 0) { if (totalTime != 0) { dumpLine(pw, uid, category, JOB_DATA, "\"" + jobs.keyAt(ij) + "\"", dumpLine(pw, uid, category, JOB_DATA, "\"" + jobs.keyAt(ij) + "\"", totalTime, count); totalTime, count, bgTime, bgCount); } } } } Loading Loading @@ -4616,6 +4630,10 @@ public abstract class BatteryStats implements Parcelable { // Convert from microseconds to milliseconds with rounding // 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 count = timer.getCountLocked(which); final Timer bgTimer = timer.getSubTimer(); final long bgTime = bgTimer != null ? (bgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : -1; final int bgCount = bgTimer != null ? bgTimer.getCountLocked(which) : -1; sb.setLength(0); sb.setLength(0); sb.append(prefix); sb.append(prefix); sb.append(" Job "); sb.append(" Job "); Loading @@ -4626,6 +4644,13 @@ public abstract class BatteryStats implements Parcelable { sb.append("realtime ("); sb.append("realtime ("); sb.append(count); sb.append(count); sb.append(" times)"); sb.append(" times)"); if (bgTime > 0) { sb.append(", "); formatTimeMs(sb, bgTime); sb.append("background ("); sb.append(bgCount); sb.append(" times)"); } } else { } else { sb.append("(not used)"); sb.append("(not used)"); } } Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +58 −79 Original line number Original line Diff line number Diff line Loading @@ -114,7 +114,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version // Current on-disk Parcel version private static final int VERSION = 152 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 153 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -2006,107 +2006,92 @@ public class BatteryStatsImpl extends BatteryStats { * State for keeping track of two DurationTimers with different TimeBases, presumably where one * State for keeping track of two DurationTimers with different TimeBases, presumably where one * TimeBase is effectively a subset of the other. * TimeBase is effectively a subset of the other. */ */ public static class DualTimer { public static class DualTimer extends DurationTimer { // mMainTimer typically tracks the total time. May be pooled (but since it's a durationTimer, // This class both is a DurationTimer and also holds a second DurationTimer. // it also has the unpooled getTotalDurationMsLocked() for STATS_SINCE_CHARGED). // The main timer (this) typically tracks the total time. It may be pooled (but since it's a private final DurationTimer mMainTimer; // durationTimer, it also has the unpooled getTotalDurationMsLocked() for // STATS_SINCE_CHARGED). // mSubTimer typically tracks only part of the total time, such as background time, as // mSubTimer typically tracks only part of the total time, such as background time, as // determined by a subTimeBase. It is NOT pooled. // determined by a subTimeBase. It is NOT pooled. private final DurationTimer mSubTimer; private final DurationTimer mSubTimer; /** /** * Creates a DualTimer to hold a mMainTimer and a mSubTimer. * Creates a DualTimer to hold a main timer (this) and a mSubTimer. * The mMainTimer is based on the given timeBase and timerPool. * The main timer (this) is based on the given timeBase and timerPool. * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * the mMainTimer is. * the main timer is. */ */ public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase, TimeBase subTimeBase, Parcel in) { TimeBase timeBase, TimeBase subTimeBase, Parcel in) { mMainTimer = new DurationTimer(clocks, uid, type, timerPool, timeBase, in); super(clocks, uid, type, timerPool, timeBase, in); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase, in); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase, in); } } /** /** * Creates a DualTimer to hold a mMainTimer and a mSubTimer. * Creates a DualTimer to hold a main timer (this) and a mSubTimer. * The mMainTimer is based on the given timeBase and timerPool. * The main timer (this) is based on the given timeBase and timerPool. * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * The mSubTimer is based on the given subTimeBase. The mSubTimer is not pooled, even if * the mMainTimer is. * the main timer is. */ */ public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, public DualTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool, TimeBase timeBase, TimeBase subTimeBase) { TimeBase timeBase, TimeBase subTimeBase) { mMainTimer = new DurationTimer(clocks, uid, type, timerPool, timeBase); super(clocks, uid, type, timerPool, timeBase); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase); mSubTimer = new DurationTimer(clocks, uid, type, null, subTimeBase); } } /** Get the main timer. */ public DurationTimer getMainTimer() { return mMainTimer; } /** Get the secondary timer. */ /** Get the secondary timer. */ @Override public DurationTimer getSubTimer() { public DurationTimer getSubTimer() { return mSubTimer; return mSubTimer; } } @Override public void startRunningLocked(long elapsedRealtimeMs) { public void startRunningLocked(long elapsedRealtimeMs) { mMainTimer.startRunningLocked(elapsedRealtimeMs); super.startRunningLocked(elapsedRealtimeMs); mSubTimer.startRunningLocked(elapsedRealtimeMs); mSubTimer.startRunningLocked(elapsedRealtimeMs); } } @Override public void stopRunningLocked(long elapsedRealtimeMs) { public void stopRunningLocked(long elapsedRealtimeMs) { mMainTimer.stopRunningLocked(elapsedRealtimeMs); super.stopRunningLocked(elapsedRealtimeMs); mSubTimer.stopRunningLocked(elapsedRealtimeMs); mSubTimer.stopRunningLocked(elapsedRealtimeMs); } } @Override public void stopAllRunningLocked(long elapsedRealtimeMs) { public void stopAllRunningLocked(long elapsedRealtimeMs) { mMainTimer.stopAllRunningLocked(elapsedRealtimeMs); super.stopAllRunningLocked(elapsedRealtimeMs); mSubTimer.stopAllRunningLocked(elapsedRealtimeMs); mSubTimer.stopAllRunningLocked(elapsedRealtimeMs); } } public void setMark(long elapsedRealtimeMs) { @Override mMainTimer.setMark(elapsedRealtimeMs); mSubTimer.setMark(elapsedRealtimeMs); } public boolean reset(boolean detachIfReset) { public boolean reset(boolean detachIfReset) { boolean active = false; boolean active = false; active |= !mMainTimer.reset(detachIfReset); active |= !super.reset(detachIfReset); active |= !mSubTimer.reset(detachIfReset); active |= !mSubTimer.reset(detachIfReset); return !active; return !active; } } @Override public void detach() { public void detach() { mMainTimer.detach(); super.detach(); mSubTimer.detach(); mSubTimer.detach(); } } /** @Override * 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) { public void writeToParcel(Parcel out, long elapsedRealtimeUs) { mMainTimer.writeToParcel(out, elapsedRealtimeUs); super.writeToParcel(out, elapsedRealtimeUs); mSubTimer.writeToParcel(out, elapsedRealtimeUs); mSubTimer.writeToParcel(out, elapsedRealtimeUs); } } @Override public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) { public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) { mMainTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); mSubTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); mSubTimer.writeSummaryFromParcelLocked(out, elapsedRealtimeUs); } } @Override public void readSummaryFromParcelLocked(Parcel in) { public void readSummaryFromParcelLocked(Parcel in) { mMainTimer.readSummaryFromParcelLocked(in); super.readSummaryFromParcelLocked(in); mSubTimer.readSummaryFromParcelLocked(in); mSubTimer.readSummaryFromParcelLocked(in); } } } } Loading Loading @@ -5488,7 +5473,7 @@ public class BatteryStatsImpl extends BatteryStats { /** /** * The statistics we have collected for this uid's jobs. * The statistics we have collected for this uid's jobs. */ */ final OverflowArrayMap<StopwatchTimer> mJobStats; final OverflowArrayMap<DualTimer> mJobStats; /** /** * The statistics we have collected for this uid's sensor activations. * The statistics we have collected for this uid's sensor activations. Loading Loading @@ -5533,10 +5518,10 @@ public class BatteryStatsImpl extends BatteryStats { mBsi.mOnBatteryTimeBase); mBsi.mOnBatteryTimeBase); } } }; }; mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>(uid) { mJobStats = mBsi.new OverflowArrayMap<DualTimer>(uid) { @Override public StopwatchTimer instantiateObject() { @Override public DualTimer instantiateObject() { return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null, return new DualTimer(mBsi.mClocks, Uid.this, JOB, null, mBsi.mOnBatteryTimeBase); mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase); } } }; }; Loading Loading @@ -5918,7 +5903,7 @@ public class BatteryStatsImpl extends BatteryStats { if (mWifiScanTimer == null) { if (mWifiScanTimer == null) { return 0; return 0; } } return mWifiScanTimer.getMainTimer().getTotalTimeLocked(elapsedRealtimeUs, which); return mWifiScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } } @Override @Override Loading @@ -5926,12 +5911,12 @@ public class BatteryStatsImpl extends BatteryStats { if (mWifiScanTimer == null) { if (mWifiScanTimer == null) { return 0; return 0; } } return mWifiScanTimer.getMainTimer().getCountLocked(which); return mWifiScanTimer.getCountLocked(which); } } @Override @Override public int getWifiScanBackgroundCount(int which) { public int getWifiScanBackgroundCount(int which) { if (mWifiScanTimer == null) { if (mWifiScanTimer == null || mWifiScanTimer.getSubTimer() == null) { return 0; return 0; } } return mWifiScanTimer.getSubTimer().getCountLocked(which); return mWifiScanTimer.getSubTimer().getCountLocked(which); Loading @@ -5943,12 +5928,12 @@ public class BatteryStatsImpl extends BatteryStats { return 0; return 0; } } final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; return mWifiScanTimer.getMainTimer().getTotalDurationMsLocked(elapsedRealtimeMs) * 1000; return mWifiScanTimer.getTotalDurationMsLocked(elapsedRealtimeMs) * 1000; } } @Override @Override public long getWifiScanBackgroundTime(final long elapsedRealtimeUs) { public long getWifiScanBackgroundTime(final long elapsedRealtimeUs) { if (mWifiScanTimer == null) { if (mWifiScanTimer == null || mWifiScanTimer.getSubTimer() == null) { return 0; return 0; } } final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; final long elapsedRealtimeMs = (elapsedRealtimeUs + 500) / 1000; Loading Loading @@ -6008,10 +5993,7 @@ public class BatteryStatsImpl extends BatteryStats { @Override @Override public Timer getBluetoothScanTimer() { public Timer getBluetoothScanTimer() { if (mBluetoothScanTimer == null) { return mBluetoothScanTimer; return null; } return mBluetoothScanTimer.getMainTimer(); } } @Override @Override Loading Loading @@ -6361,9 +6343,9 @@ public class BatteryStatsImpl extends BatteryStats { } } } } mSyncStats.cleanup(); mSyncStats.cleanup(); final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap(); final ArrayMap<String, DualTimer> jobStats = mJobStats.getMap(); for (int ij=jobStats.size()-1; ij>=0; ij--) { for (int ij=jobStats.size()-1; ij>=0; ij--) { StopwatchTimer timer = jobStats.valueAt(ij); DualTimer timer = jobStats.valueAt(ij); if (timer.reset(false)) { if (timer.reset(false)) { jobStats.removeAt(ij); jobStats.removeAt(ij); timer.detach(); timer.detach(); Loading Loading @@ -6531,12 +6513,12 @@ public class BatteryStatsImpl extends BatteryStats { Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); } } final ArrayMap<String, StopwatchTimer> jobStats = mJobStats.getMap(); final ArrayMap<String, DualTimer> jobStats = mJobStats.getMap(); int NJ = jobStats.size(); int NJ = jobStats.size(); out.writeInt(NJ); out.writeInt(NJ); for (int ij=0; ij<NJ; ij++) { for (int ij=0; ij<NJ; ij++) { out.writeString(jobStats.keyAt(ij)); out.writeString(jobStats.keyAt(ij)); StopwatchTimer timer = jobStats.valueAt(ij); DualTimer timer = jobStats.valueAt(ij); Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); Timer.writeTimerToParcel(out, timer, elapsedRealtimeUs); } } Loading Loading @@ -6756,8 +6738,8 @@ public class BatteryStatsImpl extends BatteryStats { for (int j = 0; j < numJobs; j++) { for (int j = 0; j < numJobs; j++) { String jobName = in.readString(); String jobName = in.readString(); if (in.readInt() != 0) { if (in.readInt() != 0) { mJobStats.add(jobName, new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null, mJobStats.add(jobName, new DualTimer(mBsi.mClocks, Uid.this, JOB, null, timeBase, in)); mBsi.mOnBatteryTimeBase, mOnBatteryBackgroundTimeBase, in)); } } } } Loading Loading @@ -7196,15 +7178,12 @@ public class BatteryStatsImpl extends BatteryStats { } } void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { DualTimer.writeDualTimerToParcel(out, mTimer, elapsedRealtimeUs); Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs); } } @Override @Override public Timer getSensorTime() { public Timer getSensorTime() { if (mTimer == null) { return mTimer; return null; } return mTimer.getMainTimer(); } } @Override @Override Loading Loading @@ -8023,7 +8002,7 @@ public class BatteryStatsImpl extends BatteryStats { } } public void readJobSummaryFromParcelLocked(String name, Parcel in) { public void readJobSummaryFromParcelLocked(String name, Parcel in) { StopwatchTimer timer = mJobStats.instantiateObject(); DualTimer timer = mJobStats.instantiateObject(); timer.readSummaryFromParcelLocked(in); timer.readSummaryFromParcelLocked(in); mJobStats.add(name, timer); mJobStats.add(name, timer); } } Loading Loading @@ -8084,14 +8063,14 @@ public class BatteryStatsImpl extends BatteryStats { } } public void noteStartJobLocked(String name, long elapsedRealtimeMs) { public void noteStartJobLocked(String name, long elapsedRealtimeMs) { StopwatchTimer t = mJobStats.startObject(name); DualTimer t = mJobStats.startObject(name); if (t != null) { if (t != null) { t.startRunningLocked(elapsedRealtimeMs); t.startRunningLocked(elapsedRealtimeMs); } } } } public void noteStopJobLocked(String name, long elapsedRealtimeMs) { public void noteStopJobLocked(String name, long elapsedRealtimeMs) { StopwatchTimer t = mJobStats.stopObject(name); DualTimer t = mJobStats.stopObject(name); if (t != null) { if (t != null) { t.stopRunningLocked(elapsedRealtimeMs); t.stopRunningLocked(elapsedRealtimeMs); } } Loading Loading @@ -9149,7 +9128,7 @@ public class BatteryStatsImpl extends BatteryStats { final Uid uid = mUidStats.valueAt(i); final Uid uid = mUidStats.valueAt(i); // Sum the total scan power for all apps. // Sum the total scan power for all apps. totalScanTimeMs += uid.mWifiScanTimer.getMainTimer().getTimeSinceMarkLocked( totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; // Sum the total time holding wifi lock for all apps. // Sum the total time holding wifi lock for all apps. Loading @@ -9170,7 +9149,7 @@ public class BatteryStatsImpl extends BatteryStats { for (int i = 0; i < uidStatsSize; i++) { for (int i = 0; i < uidStatsSize; i++) { final Uid uid = mUidStats.valueAt(i); final Uid uid = mUidStats.valueAt(i); long scanTimeSinceMarkMs = uid.mWifiScanTimer.getMainTimer().getTimeSinceMarkLocked( long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; if (scanTimeSinceMarkMs > 0) { if (scanTimeSinceMarkMs > 0) { // Set the new mark so that next time we get new data since this point. // Set the new mark so that next time we get new data since this point. Loading Loading @@ -9444,7 +9423,7 @@ public class BatteryStatsImpl extends BatteryStats { continue; continue; } } totalScanTimeMs += u.mBluetoothScanTimer.getMainTimer().getTimeSinceMarkLocked( totalScanTimeMs += u.mBluetoothScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; } } Loading @@ -9465,7 +9444,7 @@ public class BatteryStatsImpl extends BatteryStats { continue; continue; } } long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getMainTimer().getTimeSinceMarkLocked( long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000) / 1000; elapsedRealtimeMs * 1000) / 1000; if (scanTimeSinceMarkMs > 0) { if (scanTimeSinceMarkMs > 0) { // Set the new mark so that next time we get new data since this point. // Set the new mark so that next time we get new data since this point. Loading Loading @@ -11526,7 +11505,7 @@ public class BatteryStatsImpl extends BatteryStats { syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS); syncStats.valueAt(is).writeSummaryFromParcelLocked(out, NOWREAL_SYS); } } final ArrayMap<String, StopwatchTimer> jobStats = u.mJobStats.getMap(); final ArrayMap<String, DualTimer> jobStats = u.mJobStats.getMap(); int NJ = jobStats.size(); int NJ = jobStats.size(); out.writeInt(NJ); out.writeInt(NJ); for (int ij=0; ij<NJ; ij++) { for (int ij=0; ij<NJ; ij++) { Loading
core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java +62 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.ActivityManager; import android.os.BatteryStats; import android.os.BatteryStats; import android.os.WorkSource; import android.os.WorkSource; import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest; import android.util.ArrayMap; import junit.framework.TestCase; import junit.framework.TestCase; Loading Loading @@ -187,4 +188,65 @@ public class BatteryStatsBackgroundStatsTest extends TestCase { assertEquals((305 - 202) * 1000, actualTime); assertEquals((305 - 202) * 1000, actualTime); assertEquals((305 - 254) * 1000, bgTime); assertEquals((305 - 254) * 1000, bgTime); } } @SmallTest public void testJob() throws Exception { final MockClocks clocks = new MockClocks(); MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); final String jobName = "job_name"; 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 = 151); bi.noteJobStartLocked(jobName, UID); // Stop timer curr = 1000 * (clocks.realtime = clocks.uptime = 161); bi.noteJobFinishLocked(jobName, UID); // Start timer curr = 1000 * (clocks.realtime = clocks.uptime = 202); bi.noteJobStartLocked(jobName, 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.noteJobFinishLocked(jobName, UID); // Test curr = 1000 * (clocks.realtime = clocks.uptime = 657); final ArrayMap<String, ? extends BatteryStats.Timer> jobs = bi.getUidStats().get(UID).getJobStats(); assertEquals(1, jobs.size()); BatteryStats.Timer timer = jobs.valueAt(0); BatteryStats.Timer bgTimer = timer.getSubTimer(); long time = timer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); int count = timer.getCountLocked(STATS_SINCE_CHARGED); int bgCount = bgTimer.getCountLocked(STATS_SINCE_CHARGED); long bgTime = bgTimer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); assertEquals((161 - 151 + 305 - 202) * 1000, time); assertEquals(2, count); assertEquals(1, bgCount); assertEquals((305 - 254) * 1000, bgTime); // Test that a second job is separate. curr = 1000 * (clocks.realtime = clocks.uptime = 3000); final String jobName2 = "second_job"; bi.noteJobStartLocked(jobName2, UID); assertEquals(2, bi.getUidStats().get(UID).getJobStats().size()); bi.noteJobFinishLocked(jobName2, UID); } } }