Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 993a0be6 authored by Bookatz's avatar Bookatz
Browse files

Batterystats: fix inappropriate bg timebase reset

Previously, the background timebases (of a Uid) were reset when the Uid
resets in the wrong place. This caused StopwatchTimer.reset() to have the timesbase's old value to keep
track of its mUpdateTime. The solution is to call TimeBase.init at the
start of Uid.reset(), instead of calling TimeBase.reset() at the end of
Uid.reset().

Bug: 62352334
Test: runtest -x frameworks/base/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
Change-Id: I23c886544e18f154fc226cc81c22c3ea70fb4c7e
parent 484115b7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ public abstract class BatteryStats implements Parcelable {
     * New in version 22:
     *   - BLE scan result background count, BLE unoptimized scan time
     */
    static final String CHECKIN_VERSION = "23";
    static final String CHECKIN_VERSION = "24";

    /**
     * Old version, we hit 9 and ran out of room, need to remove.
+5 −7
Original line number Diff line number Diff line
@@ -6553,9 +6553,12 @@ public class BatteryStatsImpl extends BatteryStats {
         * inactive so can be dropped.
         */
        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
        public boolean reset() {
        public boolean reset(long uptime, long realtime) {
            boolean active = false;

            mOnBatteryBackgroundTimeBase.init(uptime, realtime);
            mOnBatteryScreenOffBackgroundTimeBase.init(uptime, realtime);

            if (mWifiRunningTimer != null) {
                active |= !mWifiRunningTimer.reset(false);
                active |= mWifiRunning;
@@ -6741,11 +6744,6 @@ public class BatteryStatsImpl extends BatteryStats {
            mLastStepUserTime = mLastStepSystemTime = 0;
            mCurStepUserTime = mCurStepSystemTime = 0;

            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) {
                    mWifiRunningTimer.detach();
@@ -9337,7 +9335,7 @@ public class BatteryStatsImpl extends BatteryStats {
        mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;

        for (int i=0; i<mUidStats.size(); i++) {
            if (mUidStats.valueAt(i).reset()) {
            if (mUidStats.valueAt(i).reset(uptimeMillis * 1000, elapsedRealtimeMillis * 1000)) {
                mUidStats.remove(mUidStats.keyAt(i));
                i--;
            }
+104 −2
Original line number Diff line number Diff line
@@ -400,7 +400,7 @@ public class BatteryStatsSensorTest extends TestCase {
        assertNotNull(sensor.getSensorBackgroundTime());

        // Reset the stats. Since the sensor is still running, we should still see the timer
        bi.getUidStatsLocked(UID).reset();
        bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000);

        sensor = uid.getSensorStats().get(SENSOR_ID);
        assertNotNull(sensor);
@@ -410,9 +410,111 @@ public class BatteryStatsSensorTest extends TestCase {
        bi.noteStopSensorLocked(UID, SENSOR_ID);

        // Now the sensor timer has stopped so this reset should also take out the sensor.
        bi.getUidStatsLocked(UID).reset();
        bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000);

        sensor = uid.getSensorStats().get(SENSOR_ID);
        assertNull(sensor);
    }

    @SmallTest
    public void testSensorResetTimes() throws Exception {
        final MockClocks clocks = new MockClocks();
        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
        final int which = BatteryStats.STATS_SINCE_CHARGED;
        bi.mForceOnBattery = true;
        clocks.realtime = 100; // in ms
        clocks.uptime = 100; // in ms

        // TimeBases are on for some time.
        BatteryStatsImpl.TimeBase timeBase = bi.getOnBatteryTimeBase();
        BatteryStatsImpl.TimeBase bgTimeBase = bi.getOnBatteryBackgroundTimeBase(UID);
        timeBase.setRunning(true, clocks.uptime * 1000, clocks.realtime * 1000);
        bgTimeBase.setRunning(true, clocks.uptime * 1000, clocks.realtime * 1000);
        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);

        clocks.realtime += 100;
        clocks.uptime += 100;

        // TimeBases are turned off
        timeBase.setRunning(false, clocks.uptime * 1000, clocks.realtime * 1000);
        bgTimeBase.setRunning(false, clocks.uptime * 1000, clocks.realtime * 1000);

        clocks.realtime += 100;
        clocks.uptime += 100;

        // Timer is turned on
        bi.noteStartSensorLocked(UID, SENSOR_ID);

        clocks.realtime += 100;
        clocks.uptime += 100;

        // Timebase was off so times are all 0.
        BatteryStats.Uid.Sensor sensor = bi.getUidStats().get(UID).getSensorStats().get(SENSOR_ID);
        BatteryStats.Timer timer = sensor.getSensorTime();
        BatteryStats.Timer bgTimer = sensor.getSensorBackgroundTime();
        assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime));
        assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, bgTimer.getTotalDurationMsLocked(clocks.realtime));

        clocks.realtime += 100;
        clocks.uptime += 100;

        // Reset the stats. Since the sensor is still running, we should still see the timer
        // but still with 0 times.
        bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000);
        assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime));
        assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, bgTimer.getTotalDurationMsLocked(clocks.realtime));

        clocks.realtime += 100;
        clocks.uptime += 100;

        // Now stop the timer. The times should still be 0.
        bi.noteStopSensorLocked(UID, SENSOR_ID);
        assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime));
        assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, bgTimer.getTotalDurationMsLocked(clocks.realtime));

        // Now repeat with the TimeBases turned on the entire time.
        timeBase.setRunning(true, clocks.uptime * 1000, clocks.realtime * 1000);
        bgTimeBase.setRunning(true, clocks.uptime * 1000, clocks.realtime * 1000);
        clocks.realtime += 100;
        clocks.uptime += 100;

        // Timer is turned on
        bi.noteStartSensorLocked(UID, SENSOR_ID);

        clocks.realtime += 111;
        clocks.uptime += 1111;

        // Timebase and timer was on so times have increased.
        assertEquals(111_000, timer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(111, timer.getTotalDurationMsLocked(clocks.realtime));
        assertEquals(111_000, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(111, bgTimer.getTotalDurationMsLocked(clocks.realtime));

        clocks.realtime += 100;
        clocks.uptime += 100;

        // Reset the stats. Since the sensor is still running, we should still see the timer
        // but with 0 times.
        bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000);
        assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime));
        assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(0, bgTimer.getTotalDurationMsLocked(clocks.realtime));

        clocks.realtime += 112;
        clocks.uptime += 112;

        // Now stop the timer. The times should have increased since the timebase was on.
        bi.noteStopSensorLocked(UID, SENSOR_ID);
        assertEquals(112_000, timer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(112, timer.getTotalDurationMsLocked(clocks.realtime));
        assertEquals(112_000, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which));
        assertEquals(112, bgTimer.getTotalDurationMsLocked(clocks.realtime));
    }
}