Loading core/java/android/os/BatteryStats.java +114 −56 Original line number Diff line number Diff line Loading @@ -156,6 +156,11 @@ public abstract class BatteryStats implements Parcelable { */ public static final int BLUETOOTH_SCAN_ON = 19; /** * A constant indicating an aggregated partial wake lock timer. */ public static final int AGGREGATED_WAKE_TYPE_PARTIAL = 20; /** * Include all of the data in the stats, including previously saved data. */ Loading Loading @@ -185,6 +190,7 @@ public abstract class BatteryStats implements Parcelable { * - Background timers and counters for: Sensor, BluetoothScan, WifiScan, Jobs, Syncs. * New in version 21: * - Actual (not just apportioned) Wakelock time is also recorded. * - Aggregated partial wakelock time (per uid, instead of per wakelock) is recorded. */ static final String CHECKIN_VERSION = "21"; Loading Loading @@ -216,6 +222,10 @@ public abstract class BatteryStats implements Parcelable { // window totalTime, 'w', count, current duration, max duration, total duration // [Currently, full and window wakelocks have durations current = max = total = -1] private static final String WAKELOCK_DATA = "wl"; // awl line is: // BATTERY_STATS_CHECKIN_VERSION, uid, which, "awl", // cumulative partial wakelock duration, cumulative background partial wakelock duration private static final String AGGREGATED_WAKELOCK_DATA = "awl"; private static final String SYNC_DATA = "sy"; private static final String JOB_DATA = "jb"; private static final String KERNEL_WAKELOCK_DATA = "kwl"; Loading Loading @@ -484,6 +494,13 @@ public abstract class BatteryStats implements Parcelable { public abstract Timer getWakeTime(int type); } /** * The cumulative time the uid spent holding any partial wakelocks. This will generally * differ from summing over the Wakelocks in getWakelockStats since the latter may have * wakelocks that overlap in time (and therefore over-counts). */ public abstract Timer getAggregatedPartialWakelockTimer(); /** * Returns a mapping containing sensor statistics. * Loading Loading @@ -3435,6 +3452,16 @@ public abstract class BatteryStats implements Parcelable { } } if (u.getAggregatedPartialWakelockTimer() != null) { final Timer timer = u.getAggregatedPartialWakelockTimer(); // Convert from microseconds to milliseconds with rounding final long totTimeMs = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; final Timer bgTimer = timer.getSubTimer(); final long bgTimeMs = bgTimer != null ? (bgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : 0; dumpLine(pw, uid, category, AGGREGATED_WAKELOCK_DATA, totTimeMs, bgTimeMs); } final ArrayMap<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats(); for (int iw=wakelocks.size()-1; iw>=0; iw--) { final Uid.Wakelock wl = wakelocks.valueAt(iw); Loading Loading @@ -4690,8 +4717,23 @@ public abstract class BatteryStats implements Parcelable { rawRealtime, which); } if (countWakelock > 1) { if (totalFullWakelock != 0 || totalPartialWakelock != 0 || totalWindowWakelock != 0) { // get unpooled partial wakelock quantities (unlike totalPartialWakelock, which is // pooled and therefore just a lower bound) long actualTotalPartialWakelock = 0; long actualBgPartialWakelock = 0; if (u.getAggregatedPartialWakelockTimer() != null) { final Timer aggTimer = u.getAggregatedPartialWakelockTimer(); // Convert from microseconds to milliseconds with rounding actualTotalPartialWakelock = (aggTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; final Timer bgAggTimer = aggTimer.getSubTimer(); actualBgPartialWakelock = bgAggTimer != null ? (bgAggTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : 0; } if (actualTotalPartialWakelock != 0 || actualBgPartialWakelock != 0 || totalFullWakelock != 0 || totalPartialWakelock != 0 || totalWindowWakelock != 0) { sb.setLength(0); sb.append(prefix); sb.append(" TOTAL wake: "); Loading @@ -4707,7 +4749,23 @@ public abstract class BatteryStats implements Parcelable { } needComma = true; formatTimeMs(sb, totalPartialWakelock); sb.append("partial"); sb.append("blamed partial"); } if (actualTotalPartialWakelock != 0) { if (needComma) { sb.append(", "); } needComma = true; formatTimeMs(sb, actualTotalPartialWakelock); sb.append("actual partial"); } if (actualBgPartialWakelock != 0) { if (needComma) { sb.append(", "); } needComma = true; formatTimeMs(sb, actualBgPartialWakelock); sb.append("actual background partial"); } if (totalWindowWakelock != 0) { if (needComma) { Loading core/java/com/android/internal/os/BatteryStatsImpl.java +95 −18 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 157 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 158 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -3468,7 +3468,7 @@ public class BatteryStatsImpl extends BatteryStats { if (batteryStatusChanged) { for (int i = 0; i < mUidStats.size(); i++) { mUidStats.valueAt(i).updateBgTimeBase(uptime, realtime); mUidStats.valueAt(i).updateOnBatteryBgTimeBase(uptime, realtime); } } Loading @@ -3482,6 +3482,9 @@ public class BatteryStatsImpl extends BatteryStats { } updateCpuTimeLocked(); mOnBatteryScreenOffTimeBase.setRunning(unpluggedScreenOff, uptime, realtime); for (int i = 0; i < mUidStats.size(); i++) { mUidStats.valueAt(i).updateOnBatteryScreenOffBgTimeBase(uptime, realtime); } } } Loading Loading @@ -5581,6 +5584,8 @@ public class BatteryStatsImpl extends BatteryStats { /** TimeBase for when uid is in background and device is on battery. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final TimeBase mOnBatteryBackgroundTimeBase; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final TimeBase mOnBatteryScreenOffBackgroundTimeBase; boolean mWifiRunning; StopwatchTimer mWifiRunningTimer; Loading @@ -5603,6 +5608,8 @@ public class BatteryStatsImpl extends BatteryStats { StopwatchTimer mFlashlightTurnedOnTimer; StopwatchTimer mCameraTurnedOnTimer; StopwatchTimer mForegroundActivityTimer; /** Total time spent by the uid holding any partial wakelocks. */ DualTimer mAggregatedPartialWakelockTimer; DualTimer mBluetoothScanTimer; Counter mBluetoothScanResultCounter; Loading Loading @@ -5704,6 +5711,10 @@ public class BatteryStatsImpl extends BatteryStats { mOnBatteryBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000, mBsi.mClocks.elapsedRealtime() * 1000); mOnBatteryScreenOffBackgroundTimeBase = new TimeBase(); mOnBatteryScreenOffBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000, mBsi.mClocks.elapsedRealtime() * 1000); mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase); mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase); Loading Loading @@ -5773,6 +5784,11 @@ public class BatteryStatsImpl extends BatteryStats { return null; } @Override public Timer getAggregatedPartialWakelockTimer() { return mAggregatedPartialWakelockTimer; } @Override public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() { return mWakelockStats.getMap(); Loading Loading @@ -6062,6 +6078,15 @@ public class BatteryStatsImpl extends BatteryStats { return mForegroundActivityTimer; } public DualTimer createAggregatedPartialWakelockTimerLocked() { if (mAggregatedPartialWakelockTimer == null) { mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this, AGGREGATED_WAKE_TYPE_PARTIAL, null, mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase); } return mAggregatedPartialWakelockTimer; } public DualTimer createBluetoothScanTimerLocked() { if (mBluetoothScanTimer == null) { mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON, Loading Loading @@ -6504,6 +6529,7 @@ public class BatteryStatsImpl extends BatteryStats { active |= !resetTimerIfNotNull(mFlashlightTurnedOnTimer, false); active |= !resetTimerIfNotNull(mCameraTurnedOnTimer, false); active |= !resetTimerIfNotNull(mForegroundActivityTimer, false); active |= !resetTimerIfNotNull(mAggregatedPartialWakelockTimer, false); active |= !resetTimerIfNotNull(mBluetoothScanTimer, false); if (mBluetoothScanResultCounter != null) { mBluetoothScanResultCounter.reset(false); Loading Loading @@ -6656,6 +6682,8 @@ public class BatteryStatsImpl extends BatteryStats { mOnBatteryBackgroundTimeBase.reset(mBsi.mClocks.elapsedRealtime() * 1000, mBsi.mClocks.uptimeMillis() * 1000); mOnBatteryScreenOffBackgroundTimeBase.reset(mBsi.mClocks.elapsedRealtime() * 1000, mBsi.mClocks.uptimeMillis() * 1000); if (!active) { if (mWifiRunningTimer != null) { Loading Loading @@ -6695,6 +6723,10 @@ public class BatteryStatsImpl extends BatteryStats { mForegroundActivityTimer.detach(); mForegroundActivityTimer = null; } if (mAggregatedPartialWakelockTimer != null) { mAggregatedPartialWakelockTimer.detach(); mAggregatedPartialWakelockTimer = null; } if (mBluetoothScanTimer != null) { mBluetoothScanTimer.detach(); mBluetoothScanTimer = null; Loading Loading @@ -6760,6 +6792,7 @@ public class BatteryStatsImpl extends BatteryStats { void writeToParcelLocked(Parcel out, long uptimeUs, long elapsedRealtimeUs) { mOnBatteryBackgroundTimeBase.writeToParcel(out, uptimeUs, elapsedRealtimeUs); mOnBatteryScreenOffBackgroundTimeBase.writeToParcel(out, uptimeUs, elapsedRealtimeUs); final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap(); int NW = wakeStats.size(); Loading Loading @@ -6874,6 +6907,12 @@ public class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } if (mAggregatedPartialWakelockTimer != null) { out.writeInt(1); mAggregatedPartialWakelockTimer.writeToParcel(out, elapsedRealtimeUs); } else { out.writeInt(0); } if (mBluetoothScanTimer != null) { out.writeInt(1); mBluetoothScanTimer.writeToParcel(out, elapsedRealtimeUs); Loading Loading @@ -6987,6 +7026,7 @@ public class BatteryStatsImpl extends BatteryStats { void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { mOnBatteryBackgroundTimeBase.readFromParcel(in); mOnBatteryScreenOffBackgroundTimeBase.readFromParcel(in); int numWakelocks = in.readInt(); mWakelockStats.clear(); Loading Loading @@ -7112,6 +7152,14 @@ public class BatteryStatsImpl extends BatteryStats { } else { mForegroundActivityTimer = null; } if (in.readInt() != 0) { mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this, AGGREGATED_WAKE_TYPE_PARTIAL, null, mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase, in); } else { mAggregatedPartialWakelockTimer = null; } if (in.readInt() != 0) { mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON, mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, Loading Loading @@ -8224,15 +8272,25 @@ public class BatteryStatsImpl extends BatteryStats { mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtimeMs); } updateBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000); updateOnBatteryBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000); updateOnBatteryScreenOffBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000); } public boolean updateBgTimeBase(long uptimeUs, long realtimeUs) { /** Whether to consider Uid to be in the background for background timebase purposes. */ public boolean isInBackground() { // 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); return mProcessState >= PROCESS_STATE_BACKGROUND; } public boolean updateOnBatteryBgTimeBase(long uptimeUs, long realtimeUs) { boolean on = mBsi.mOnBatteryTimeBase.isRunning() && isInBackground(); return mOnBatteryBackgroundTimeBase.setRunning(on, uptimeUs, realtimeUs); } public boolean updateOnBatteryScreenOffBgTimeBase(long uptimeUs, long realtimeUs) { boolean on = mBsi.mOnBatteryScreenOffTimeBase.isRunning() && isInBackground(); return mOnBatteryScreenOffBackgroundTimeBase.setRunning(on, uptimeUs, realtimeUs); } public SparseArray<? extends Pid> getPidStats() { Loading Loading @@ -8363,20 +8421,27 @@ public class BatteryStatsImpl extends BatteryStats { if (wl != null) { wl.getStopwatchTimer(type).startRunningLocked(elapsedRealtimeMs); } if (pid >= 0 && type == WAKE_TYPE_PARTIAL) { if (type == WAKE_TYPE_PARTIAL) { createAggregatedPartialWakelockTimerLocked().startRunningLocked(elapsedRealtimeMs); if (pid >= 0) { Pid p = getPidStatsLocked(pid); if (p.mWakeNesting++ == 0) { p.mWakeStartMs = elapsedRealtimeMs; } } } } public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) { Wakelock wl = mWakelockStats.stopObject(name); if (wl != null) { wl.getStopwatchTimer(type).stopRunningLocked(elapsedRealtimeMs); } if (pid >= 0 && type == WAKE_TYPE_PARTIAL) { if (type == WAKE_TYPE_PARTIAL) { if (mAggregatedPartialWakelockTimer != null) { mAggregatedPartialWakelockTimer.stopRunningLocked(elapsedRealtimeMs); } if (pid >= 0) { Pid p = mPids.get(pid); if (p != null && p.mWakeNesting > 0) { if (p.mWakeNesting-- == 1) { Loading @@ -8386,6 +8451,7 @@ public class BatteryStatsImpl extends BatteryStats { } } } } public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) { Proc p = getProcessStatsLocked(proc); Loading Loading @@ -11265,6 +11331,7 @@ public class BatteryStatsImpl extends BatteryStats { mUidStats.put(uid, u); u.mOnBatteryBackgroundTimeBase.readSummaryFromParcel(in); u.mOnBatteryScreenOffBackgroundTimeBase.readSummaryFromParcel(in); u.mWifiRunning = false; if (in.readInt() != 0) { Loading Loading @@ -11304,6 +11371,9 @@ public class BatteryStatsImpl extends BatteryStats { if (in.readInt() != 0) { u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in); } if (in.readInt() != 0) { u.createAggregatedPartialWakelockTimerLocked().readSummaryFromParcelLocked(in); } if (in.readInt() != 0) { u.createBluetoothScanTimerLocked().readSummaryFromParcelLocked(in); } Loading Loading @@ -11641,6 +11711,7 @@ public class BatteryStatsImpl extends BatteryStats { Uid u = mUidStats.valueAt(iu); u.mOnBatteryBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS); u.mOnBatteryScreenOffBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS); if (u.mWifiRunningTimer != null) { out.writeInt(1); Loading Loading @@ -11704,6 +11775,12 @@ public class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } if (u.mAggregatedPartialWakelockTimer != null) { out.writeInt(1); u.mAggregatedPartialWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); } else { out.writeInt(0); } if (u.mBluetoothScanTimer != null) { out.writeInt(1); u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); Loading core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java +49 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,55 @@ public class BatteryStatsBackgroundStatsTest extends TestCase { assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); } /** Test that BatteryStatsImpl.Uid.mOnBatteryScreenOffBackgroundTimeBase works correctly. */ @SmallTest public void testScreenOffBgTimeBase() 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.getOnBatteryScreenOffBackgroundTimeBase(UID); // battery=off, screen=off, background=off cur = (clocks.realtime = clocks.uptime = 100) * 1000; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); bi.updateTimeBasesLocked(false, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=on, screen=off, background=off cur = (clocks.realtime = clocks.uptime = 200) * 1000; bi.updateTimeBasesLocked(true, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=on, screen=on, background=off cur = (clocks.realtime = clocks.uptime = 300) * 1000; bi.updateTimeBasesLocked(true, true, cur, cur); assertFalse(bgtb.isRunning()); // battery=on, screen=on, background=on // Only during this period should the timebase progress cur = (clocks.realtime = clocks.uptime = 400) * 1000; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); assertTrue(bgtb.isRunning()); // battery=on, screen=off, background=on cur = (clocks.realtime = clocks.uptime = 550) * 1000; bi.updateTimeBasesLocked(true, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=off, screen=off, background=on cur = (clocks.realtime = clocks.uptime = 660) * 1000; bi.updateTimeBasesLocked(false, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=off, screen=off, background=off cur = (clocks.realtime = clocks.uptime = 770) * 1000; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); assertFalse(bgtb.isRunning()); assertEquals(150_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); } @SmallTest public void testWifiScan() throws Exception { final MockClocks clocks = new MockClocks(); Loading core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +30 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package com.android.internal.os; import static android.os.BatteryStats.STATS_SINCE_CHARGED; import static android.os.BatteryStats.WAKE_TYPE_PARTIAL; import android.app.ActivityManager; import android.os.BatteryStats; import android.os.WorkSource; import android.support.test.filters.SmallTest; Loading @@ -29,7 +32,7 @@ public class BatteryStatsNoteTest extends TestCase{ private static final int UID = 10500; private static final WorkSource WS = new WorkSource(UID); /** Test that BatteryStatsImpl.Uid.noteBluetoothScanResultsLocked. */ /** Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked. */ @SmallTest public void testNoteBluetoothScanResultLocked() throws Exception { MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks()); Loading @@ -41,4 +44,30 @@ public class BatteryStatsNoteTest extends TestCase{ bi.getUidStats().get(UID).getBluetoothScanResultCounter() .getCountLocked(STATS_SINCE_CHARGED)); } /** Test BatteryStatsImpl.Uid.noteStartWakeLocked. */ @SmallTest public void testNoteStartWakeLocked() throws Exception { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); int pid = 10; String name = "name"; bi.updateTimeBasesLocked(true, true, 0, 0); bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); bi.getUidStatsLocked(UID).noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime); clocks.realtime = clocks.uptime = 100; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); clocks.realtime = clocks.uptime = 220; bi.getUidStatsLocked(UID).noteStopWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime); BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID).getAggregatedPartialWakelockTimer(); long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); assertEquals(220_000, actualTime); assertEquals(120_000, bgTime); } } core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +4 −0 Original line number Diff line number Diff line Loading @@ -44,5 +44,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { public TimeBase getOnBatteryBackgroundTimeBase(int uid) { return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase; } public TimeBase getOnBatteryScreenOffBackgroundTimeBase(int uid) { return getUidStatsLocked(uid).mOnBatteryScreenOffBackgroundTimeBase; } } Loading
core/java/android/os/BatteryStats.java +114 −56 Original line number Diff line number Diff line Loading @@ -156,6 +156,11 @@ public abstract class BatteryStats implements Parcelable { */ public static final int BLUETOOTH_SCAN_ON = 19; /** * A constant indicating an aggregated partial wake lock timer. */ public static final int AGGREGATED_WAKE_TYPE_PARTIAL = 20; /** * Include all of the data in the stats, including previously saved data. */ Loading Loading @@ -185,6 +190,7 @@ public abstract class BatteryStats implements Parcelable { * - Background timers and counters for: Sensor, BluetoothScan, WifiScan, Jobs, Syncs. * New in version 21: * - Actual (not just apportioned) Wakelock time is also recorded. * - Aggregated partial wakelock time (per uid, instead of per wakelock) is recorded. */ static final String CHECKIN_VERSION = "21"; Loading Loading @@ -216,6 +222,10 @@ public abstract class BatteryStats implements Parcelable { // window totalTime, 'w', count, current duration, max duration, total duration // [Currently, full and window wakelocks have durations current = max = total = -1] private static final String WAKELOCK_DATA = "wl"; // awl line is: // BATTERY_STATS_CHECKIN_VERSION, uid, which, "awl", // cumulative partial wakelock duration, cumulative background partial wakelock duration private static final String AGGREGATED_WAKELOCK_DATA = "awl"; private static final String SYNC_DATA = "sy"; private static final String JOB_DATA = "jb"; private static final String KERNEL_WAKELOCK_DATA = "kwl"; Loading Loading @@ -484,6 +494,13 @@ public abstract class BatteryStats implements Parcelable { public abstract Timer getWakeTime(int type); } /** * The cumulative time the uid spent holding any partial wakelocks. This will generally * differ from summing over the Wakelocks in getWakelockStats since the latter may have * wakelocks that overlap in time (and therefore over-counts). */ public abstract Timer getAggregatedPartialWakelockTimer(); /** * Returns a mapping containing sensor statistics. * Loading Loading @@ -3435,6 +3452,16 @@ public abstract class BatteryStats implements Parcelable { } } if (u.getAggregatedPartialWakelockTimer() != null) { final Timer timer = u.getAggregatedPartialWakelockTimer(); // Convert from microseconds to milliseconds with rounding final long totTimeMs = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; final Timer bgTimer = timer.getSubTimer(); final long bgTimeMs = bgTimer != null ? (bgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : 0; dumpLine(pw, uid, category, AGGREGATED_WAKELOCK_DATA, totTimeMs, bgTimeMs); } final ArrayMap<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats(); for (int iw=wakelocks.size()-1; iw>=0; iw--) { final Uid.Wakelock wl = wakelocks.valueAt(iw); Loading Loading @@ -4690,8 +4717,23 @@ public abstract class BatteryStats implements Parcelable { rawRealtime, which); } if (countWakelock > 1) { if (totalFullWakelock != 0 || totalPartialWakelock != 0 || totalWindowWakelock != 0) { // get unpooled partial wakelock quantities (unlike totalPartialWakelock, which is // pooled and therefore just a lower bound) long actualTotalPartialWakelock = 0; long actualBgPartialWakelock = 0; if (u.getAggregatedPartialWakelockTimer() != null) { final Timer aggTimer = u.getAggregatedPartialWakelockTimer(); // Convert from microseconds to milliseconds with rounding actualTotalPartialWakelock = (aggTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; final Timer bgAggTimer = aggTimer.getSubTimer(); actualBgPartialWakelock = bgAggTimer != null ? (bgAggTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000 : 0; } if (actualTotalPartialWakelock != 0 || actualBgPartialWakelock != 0 || totalFullWakelock != 0 || totalPartialWakelock != 0 || totalWindowWakelock != 0) { sb.setLength(0); sb.append(prefix); sb.append(" TOTAL wake: "); Loading @@ -4707,7 +4749,23 @@ public abstract class BatteryStats implements Parcelable { } needComma = true; formatTimeMs(sb, totalPartialWakelock); sb.append("partial"); sb.append("blamed partial"); } if (actualTotalPartialWakelock != 0) { if (needComma) { sb.append(", "); } needComma = true; formatTimeMs(sb, actualTotalPartialWakelock); sb.append("actual partial"); } if (actualBgPartialWakelock != 0) { if (needComma) { sb.append(", "); } needComma = true; formatTimeMs(sb, actualBgPartialWakelock); sb.append("actual background partial"); } if (totalWindowWakelock != 0) { if (needComma) { Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +95 −18 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version private static final int VERSION = 157 + (USE_OLD_HISTORY ? 1000 : 0); private static final int VERSION = 158 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; Loading Loading @@ -3468,7 +3468,7 @@ public class BatteryStatsImpl extends BatteryStats { if (batteryStatusChanged) { for (int i = 0; i < mUidStats.size(); i++) { mUidStats.valueAt(i).updateBgTimeBase(uptime, realtime); mUidStats.valueAt(i).updateOnBatteryBgTimeBase(uptime, realtime); } } Loading @@ -3482,6 +3482,9 @@ public class BatteryStatsImpl extends BatteryStats { } updateCpuTimeLocked(); mOnBatteryScreenOffTimeBase.setRunning(unpluggedScreenOff, uptime, realtime); for (int i = 0; i < mUidStats.size(); i++) { mUidStats.valueAt(i).updateOnBatteryScreenOffBgTimeBase(uptime, realtime); } } } Loading Loading @@ -5581,6 +5584,8 @@ public class BatteryStatsImpl extends BatteryStats { /** TimeBase for when uid is in background and device is on battery. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final TimeBase mOnBatteryBackgroundTimeBase; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public final TimeBase mOnBatteryScreenOffBackgroundTimeBase; boolean mWifiRunning; StopwatchTimer mWifiRunningTimer; Loading @@ -5603,6 +5608,8 @@ public class BatteryStatsImpl extends BatteryStats { StopwatchTimer mFlashlightTurnedOnTimer; StopwatchTimer mCameraTurnedOnTimer; StopwatchTimer mForegroundActivityTimer; /** Total time spent by the uid holding any partial wakelocks. */ DualTimer mAggregatedPartialWakelockTimer; DualTimer mBluetoothScanTimer; Counter mBluetoothScanResultCounter; Loading Loading @@ -5704,6 +5711,10 @@ public class BatteryStatsImpl extends BatteryStats { mOnBatteryBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000, mBsi.mClocks.elapsedRealtime() * 1000); mOnBatteryScreenOffBackgroundTimeBase = new TimeBase(); mOnBatteryScreenOffBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000, mBsi.mClocks.elapsedRealtime() * 1000); mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase); mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase); Loading Loading @@ -5773,6 +5784,11 @@ public class BatteryStatsImpl extends BatteryStats { return null; } @Override public Timer getAggregatedPartialWakelockTimer() { return mAggregatedPartialWakelockTimer; } @Override public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() { return mWakelockStats.getMap(); Loading Loading @@ -6062,6 +6078,15 @@ public class BatteryStatsImpl extends BatteryStats { return mForegroundActivityTimer; } public DualTimer createAggregatedPartialWakelockTimerLocked() { if (mAggregatedPartialWakelockTimer == null) { mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this, AGGREGATED_WAKE_TYPE_PARTIAL, null, mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase); } return mAggregatedPartialWakelockTimer; } public DualTimer createBluetoothScanTimerLocked() { if (mBluetoothScanTimer == null) { mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON, Loading Loading @@ -6504,6 +6529,7 @@ public class BatteryStatsImpl extends BatteryStats { active |= !resetTimerIfNotNull(mFlashlightTurnedOnTimer, false); active |= !resetTimerIfNotNull(mCameraTurnedOnTimer, false); active |= !resetTimerIfNotNull(mForegroundActivityTimer, false); active |= !resetTimerIfNotNull(mAggregatedPartialWakelockTimer, false); active |= !resetTimerIfNotNull(mBluetoothScanTimer, false); if (mBluetoothScanResultCounter != null) { mBluetoothScanResultCounter.reset(false); Loading Loading @@ -6656,6 +6682,8 @@ public class BatteryStatsImpl extends BatteryStats { mOnBatteryBackgroundTimeBase.reset(mBsi.mClocks.elapsedRealtime() * 1000, mBsi.mClocks.uptimeMillis() * 1000); mOnBatteryScreenOffBackgroundTimeBase.reset(mBsi.mClocks.elapsedRealtime() * 1000, mBsi.mClocks.uptimeMillis() * 1000); if (!active) { if (mWifiRunningTimer != null) { Loading Loading @@ -6695,6 +6723,10 @@ public class BatteryStatsImpl extends BatteryStats { mForegroundActivityTimer.detach(); mForegroundActivityTimer = null; } if (mAggregatedPartialWakelockTimer != null) { mAggregatedPartialWakelockTimer.detach(); mAggregatedPartialWakelockTimer = null; } if (mBluetoothScanTimer != null) { mBluetoothScanTimer.detach(); mBluetoothScanTimer = null; Loading Loading @@ -6760,6 +6792,7 @@ public class BatteryStatsImpl extends BatteryStats { void writeToParcelLocked(Parcel out, long uptimeUs, long elapsedRealtimeUs) { mOnBatteryBackgroundTimeBase.writeToParcel(out, uptimeUs, elapsedRealtimeUs); mOnBatteryScreenOffBackgroundTimeBase.writeToParcel(out, uptimeUs, elapsedRealtimeUs); final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap(); int NW = wakeStats.size(); Loading Loading @@ -6874,6 +6907,12 @@ public class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } if (mAggregatedPartialWakelockTimer != null) { out.writeInt(1); mAggregatedPartialWakelockTimer.writeToParcel(out, elapsedRealtimeUs); } else { out.writeInt(0); } if (mBluetoothScanTimer != null) { out.writeInt(1); mBluetoothScanTimer.writeToParcel(out, elapsedRealtimeUs); Loading Loading @@ -6987,6 +7026,7 @@ public class BatteryStatsImpl extends BatteryStats { void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) { mOnBatteryBackgroundTimeBase.readFromParcel(in); mOnBatteryScreenOffBackgroundTimeBase.readFromParcel(in); int numWakelocks = in.readInt(); mWakelockStats.clear(); Loading Loading @@ -7112,6 +7152,14 @@ public class BatteryStatsImpl extends BatteryStats { } else { mForegroundActivityTimer = null; } if (in.readInt() != 0) { mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this, AGGREGATED_WAKE_TYPE_PARTIAL, null, mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase, in); } else { mAggregatedPartialWakelockTimer = null; } if (in.readInt() != 0) { mBluetoothScanTimer = new DualTimer(mBsi.mClocks, Uid.this, BLUETOOTH_SCAN_ON, mBsi.mBluetoothScanOnTimers, mBsi.mOnBatteryTimeBase, Loading Loading @@ -8224,15 +8272,25 @@ public class BatteryStatsImpl extends BatteryStats { mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtimeMs); } updateBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000); updateOnBatteryBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000); updateOnBatteryScreenOffBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000); } public boolean updateBgTimeBase(long uptimeUs, long realtimeUs) { /** Whether to consider Uid to be in the background for background timebase purposes. */ public boolean isInBackground() { // 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); return mProcessState >= PROCESS_STATE_BACKGROUND; } public boolean updateOnBatteryBgTimeBase(long uptimeUs, long realtimeUs) { boolean on = mBsi.mOnBatteryTimeBase.isRunning() && isInBackground(); return mOnBatteryBackgroundTimeBase.setRunning(on, uptimeUs, realtimeUs); } public boolean updateOnBatteryScreenOffBgTimeBase(long uptimeUs, long realtimeUs) { boolean on = mBsi.mOnBatteryScreenOffTimeBase.isRunning() && isInBackground(); return mOnBatteryScreenOffBackgroundTimeBase.setRunning(on, uptimeUs, realtimeUs); } public SparseArray<? extends Pid> getPidStats() { Loading Loading @@ -8363,20 +8421,27 @@ public class BatteryStatsImpl extends BatteryStats { if (wl != null) { wl.getStopwatchTimer(type).startRunningLocked(elapsedRealtimeMs); } if (pid >= 0 && type == WAKE_TYPE_PARTIAL) { if (type == WAKE_TYPE_PARTIAL) { createAggregatedPartialWakelockTimerLocked().startRunningLocked(elapsedRealtimeMs); if (pid >= 0) { Pid p = getPidStatsLocked(pid); if (p.mWakeNesting++ == 0) { p.mWakeStartMs = elapsedRealtimeMs; } } } } public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) { Wakelock wl = mWakelockStats.stopObject(name); if (wl != null) { wl.getStopwatchTimer(type).stopRunningLocked(elapsedRealtimeMs); } if (pid >= 0 && type == WAKE_TYPE_PARTIAL) { if (type == WAKE_TYPE_PARTIAL) { if (mAggregatedPartialWakelockTimer != null) { mAggregatedPartialWakelockTimer.stopRunningLocked(elapsedRealtimeMs); } if (pid >= 0) { Pid p = mPids.get(pid); if (p != null && p.mWakeNesting > 0) { if (p.mWakeNesting-- == 1) { Loading @@ -8386,6 +8451,7 @@ public class BatteryStatsImpl extends BatteryStats { } } } } public void reportExcessiveWakeLocked(String proc, long overTime, long usedTime) { Proc p = getProcessStatsLocked(proc); Loading Loading @@ -11265,6 +11331,7 @@ public class BatteryStatsImpl extends BatteryStats { mUidStats.put(uid, u); u.mOnBatteryBackgroundTimeBase.readSummaryFromParcel(in); u.mOnBatteryScreenOffBackgroundTimeBase.readSummaryFromParcel(in); u.mWifiRunning = false; if (in.readInt() != 0) { Loading Loading @@ -11304,6 +11371,9 @@ public class BatteryStatsImpl extends BatteryStats { if (in.readInt() != 0) { u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in); } if (in.readInt() != 0) { u.createAggregatedPartialWakelockTimerLocked().readSummaryFromParcelLocked(in); } if (in.readInt() != 0) { u.createBluetoothScanTimerLocked().readSummaryFromParcelLocked(in); } Loading Loading @@ -11641,6 +11711,7 @@ public class BatteryStatsImpl extends BatteryStats { Uid u = mUidStats.valueAt(iu); u.mOnBatteryBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS); u.mOnBatteryScreenOffBackgroundTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS); if (u.mWifiRunningTimer != null) { out.writeInt(1); Loading Loading @@ -11704,6 +11775,12 @@ public class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } if (u.mAggregatedPartialWakelockTimer != null) { out.writeInt(1); u.mAggregatedPartialWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); } else { out.writeInt(0); } if (u.mBluetoothScanTimer != null) { out.writeInt(1); u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); Loading
core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java +49 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,55 @@ public class BatteryStatsBackgroundStatsTest extends TestCase { assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); } /** Test that BatteryStatsImpl.Uid.mOnBatteryScreenOffBackgroundTimeBase works correctly. */ @SmallTest public void testScreenOffBgTimeBase() 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.getOnBatteryScreenOffBackgroundTimeBase(UID); // battery=off, screen=off, background=off cur = (clocks.realtime = clocks.uptime = 100) * 1000; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); bi.updateTimeBasesLocked(false, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=on, screen=off, background=off cur = (clocks.realtime = clocks.uptime = 200) * 1000; bi.updateTimeBasesLocked(true, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=on, screen=on, background=off cur = (clocks.realtime = clocks.uptime = 300) * 1000; bi.updateTimeBasesLocked(true, true, cur, cur); assertFalse(bgtb.isRunning()); // battery=on, screen=on, background=on // Only during this period should the timebase progress cur = (clocks.realtime = clocks.uptime = 400) * 1000; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); assertTrue(bgtb.isRunning()); // battery=on, screen=off, background=on cur = (clocks.realtime = clocks.uptime = 550) * 1000; bi.updateTimeBasesLocked(true, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=off, screen=off, background=on cur = (clocks.realtime = clocks.uptime = 660) * 1000; bi.updateTimeBasesLocked(false, false, cur, cur); assertFalse(bgtb.isRunning()); // battery=off, screen=off, background=off cur = (clocks.realtime = clocks.uptime = 770) * 1000; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); assertFalse(bgtb.isRunning()); assertEquals(150_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); } @SmallTest public void testWifiScan() throws Exception { final MockClocks clocks = new MockClocks(); Loading
core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +30 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,10 @@ package com.android.internal.os; import static android.os.BatteryStats.STATS_SINCE_CHARGED; import static android.os.BatteryStats.WAKE_TYPE_PARTIAL; import android.app.ActivityManager; import android.os.BatteryStats; import android.os.WorkSource; import android.support.test.filters.SmallTest; Loading @@ -29,7 +32,7 @@ public class BatteryStatsNoteTest extends TestCase{ private static final int UID = 10500; private static final WorkSource WS = new WorkSource(UID); /** Test that BatteryStatsImpl.Uid.noteBluetoothScanResultsLocked. */ /** Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked. */ @SmallTest public void testNoteBluetoothScanResultLocked() throws Exception { MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks()); Loading @@ -41,4 +44,30 @@ public class BatteryStatsNoteTest extends TestCase{ bi.getUidStats().get(UID).getBluetoothScanResultCounter() .getCountLocked(STATS_SINCE_CHARGED)); } /** Test BatteryStatsImpl.Uid.noteStartWakeLocked. */ @SmallTest public void testNoteStartWakeLocked() throws Exception { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); int pid = 10; String name = "name"; bi.updateTimeBasesLocked(true, true, 0, 0); bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); bi.getUidStatsLocked(UID).noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime); clocks.realtime = clocks.uptime = 100; bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); clocks.realtime = clocks.uptime = 220; bi.getUidStatsLocked(UID).noteStopWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime); BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID).getAggregatedPartialWakelockTimer(); long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED); assertEquals(220_000, actualTime); assertEquals(120_000, bgTime); } }
core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +4 −0 Original line number Diff line number Diff line Loading @@ -44,5 +44,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { public TimeBase getOnBatteryBackgroundTimeBase(int uid) { return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase; } public TimeBase getOnBatteryScreenOffBackgroundTimeBase(int uid) { return getUidStatsLocked(uid).mOnBatteryScreenOffBackgroundTimeBase; } }