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

Commit 08455995 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Tron counters for battery saving stats."

parents 321ef3a5 04e9dc91
Loading
Loading
Loading
Loading
+82 −21
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.power.BatterySaverPolicy;
@@ -116,9 +117,16 @@ public class BatterySavingStats {
        }
    }

    @VisibleForTesting
    static final String COUNTER_POWER_MILLIAMPS_PREFIX = "battery_saver_stats_milliamps_";

    @VisibleForTesting
    static final String COUNTER_TIME_SECONDS_PREFIX = "battery_saver_stats_seconds_";

    private static BatterySavingStats sInstance;

    private BatteryManagerInternal mBatteryManagerInternal;
    private final MetricsLogger mMetricsLogger;

    private static final int STATE_NOT_INITIALIZED = -1;
    private static final int STATE_CHARGING = -2;
@@ -136,17 +144,21 @@ public class BatterySavingStats {
    @GuardedBy("mLock")
    final ArrayMap<Integer, Stat> mStats = new ArrayMap<>();

    private final MetricsLoggerHelper mMetricsLoggerHelper = new MetricsLoggerHelper();

    /**
     * Don't call it directly -- use {@link #getInstance()}. Not private for testing.
     * @param metricsLogger
     */
    @VisibleForTesting
    BatterySavingStats() {
    BatterySavingStats(MetricsLogger metricsLogger) {
        mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
        mMetricsLogger = metricsLogger;
    }

    public static synchronized BatterySavingStats getInstance() {
        if (sInstance == null) {
            sInstance = new BatterySavingStats();
            sInstance = new BatterySavingStats(new MetricsLogger());
        }
        return sInstance;
    }
@@ -208,10 +220,12 @@ public class BatterySavingStats {
        return getStat(statesToIndex(batterySaverState, interactiveState, dozeState));
    }

    @VisibleForTesting
    long injectCurrentTime() {
        return SystemClock.elapsedRealtime();
    }

    @VisibleForTesting
    int injectBatteryLevel() {
        final BatteryManagerInternal bmi = getBatteryManagerInternal();
        if (bmi == null) {
@@ -227,15 +241,9 @@ public class BatterySavingStats {
     */
    public void transitionState(int batterySaverState, int interactiveState, int dozeState) {
        synchronized (mLock) {

            final int newState = statesToIndex(
                    batterySaverState, interactiveState, dozeState);
            if (mCurrentState == newState) {
                return;
            }

            endLastStateLocked();
            startNewStateLocked(newState);
            transitionStateLocked(newState);
        }
    }

@@ -244,23 +252,30 @@ public class BatterySavingStats {
     */
    public void startCharging() {
        synchronized (mLock) {
            if (mCurrentState < 0) {
                return;
            transitionStateLocked(STATE_CHARGING);
        }
    }

            endLastStateLocked();
            startNewStateLocked(STATE_CHARGING);
    private void transitionStateLocked(int newState) {
        if (mCurrentState == newState) {
            return;
        }
        final long now = injectCurrentTime();
        final int batteryLevel = injectBatteryLevel();

        endLastStateLocked(now, batteryLevel);
        startNewStateLocked(newState, now, batteryLevel);
        mMetricsLoggerHelper.transitionState(newState, now, batteryLevel);
    }

    private void endLastStateLocked() {
    private void endLastStateLocked(long now, int batteryLevel) {
        if (mCurrentState < 0) {
            return;
        }
        final Stat stat = getStat(mCurrentState);

        stat.endBatteryLevel = injectBatteryLevel();
        stat.endTime = injectCurrentTime();
        stat.endBatteryLevel = batteryLevel;
        stat.endTime = now;

        final long deltaTime = stat.endTime - stat.startTime;
        final int deltaDrain = stat.startBatteryLevel - stat.endBatteryLevel;
@@ -283,9 +298,10 @@ public class BatterySavingStats {
                deltaDrain,
                stat.totalTimeMillis,
                stat.totalBatteryDrain);

    }

    private void startNewStateLocked(int newState) {
    private void startNewStateLocked(int newState, long now, int batteryLevel) {
        if (DEBUG) {
            Slog.d(TAG, "New state: " + stateToString(newState));
        }
@@ -296,8 +312,8 @@ public class BatterySavingStats {
        }

        final Stat stat = getStat(mCurrentState);
        stat.startBatteryLevel = injectBatteryLevel();
        stat.startTime = injectCurrentTime();
        stat.startBatteryLevel = batteryLevel;
        stat.startTime = now;
        stat.endTime = 0;
    }

@@ -349,5 +365,50 @@ public class BatterySavingStats {
                onStat.totalBatteryDrain / 1000,
                onStat.drainPerHour() / 1000.0));
    }

    @VisibleForTesting
    class MetricsLoggerHelper {
        private int mLastState = STATE_NOT_INITIALIZED;
        private long mStartTime;
        private int mStartBatteryLevel;

        private static final int STATE_CHANGE_DETECT_MASK =
                (BatterySaverState.MASK << BatterySaverState.SHIFT) |
                (InteractiveState.MASK << InteractiveState.SHIFT);

        public void transitionState(int newState, long now, int batteryLevel) {
            final boolean stateChanging =
                    ((mLastState >= 0) ^ (newState >= 0)) ||
                    (((mLastState ^ newState) & STATE_CHANGE_DETECT_MASK) != 0);
            if (stateChanging) {
                if (mLastState >= 0) {
                    final long deltaTime = now - mStartTime;
                    final int deltaBattery = mStartBatteryLevel - batteryLevel;

                    report(mLastState, deltaTime, deltaBattery);
                }
                mStartTime = now;
                mStartBatteryLevel = batteryLevel;
            }
            mLastState = newState;
        }

        String getCounterSuffix(int state) {
            final boolean batterySaver =
                    BatterySaverState.fromIndex(state) != BatterySaverState.OFF;
            final boolean interactive =
                    InteractiveState.fromIndex(state) != InteractiveState.NON_INTERACTIVE;
            if (batterySaver) {
                return interactive ? "11" : "10";
            } else {
                return interactive ? "01" : "00";
            }
        }

        void report(int state, long deltaTimeMs, int deltaBatteryUa) {
            final String suffix = getCounterSuffix(state);
            mMetricsLogger.count(COUNTER_POWER_MILLIAMPS_PREFIX + suffix, deltaBatteryUa / 1000);
            mMetricsLogger.count(COUNTER_TIME_SECONDS_PREFIX + suffix, (int) (deltaTimeMs / 1000));
        }
    }
}
+108 −3
Original line number Diff line number Diff line
@@ -16,10 +16,18 @@
package com.android.server.power.batterysaver;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import com.android.internal.logging.MetricsLogger;
import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
@@ -39,7 +47,11 @@ public class BatterySavingStatsTest {
    private class BatterySavingStatsTestable extends BatterySavingStats {
        private long mTime = 1_000_000; // Some random starting time.

        private int mBatteryLevel = 100;
        private int mBatteryLevel = 1_000_000_000;

        private BatterySavingStatsTestable() {
            super(mMetricsLogger);
        }

        @Override
        long injectCurrentTime() {
@@ -60,8 +72,8 @@ public class BatterySavingStatsTest {
            mTime += 60_000 * minutes;
        }

        void drainBattery(int percent) {
            mBatteryLevel -= percent;
        void drainBattery(int value) {
            mBatteryLevel -= value;
            if (mBatteryLevel < 0) {
                mBatteryLevel = 0;
            }
@@ -81,6 +93,8 @@ public class BatterySavingStatsTest {
        }
    }

    public MetricsLogger mMetricsLogger = mock(MetricsLogger.class);

    @Test
    public void testAll() {
        final BatterySavingStatsTestable target = new BatterySavingStatsTestable();
@@ -202,4 +216,95 @@ public class BatterySavingStatsTest {
                "BS=1,I=1,D=2:{0m,0,0.00}",
                target.toDebugString());
    }

    private void assertMetricsLog(String counter, int value) {
        verify(mMetricsLogger, times(1)).count(eq(counter), eq(value));
    }

    @Test
    public void testMetricsLogger() {
        final BatterySavingStatsTestable target = new BatterySavingStatsTestable();

        target.advanceClock(1);
        target.drainBattery(1000);

        target.transitionState(
                BatterySaverState.OFF,
                InteractiveState.INTERACTIVE,
                DozeState.NOT_DOZING);

        verify(mMetricsLogger, times(0)).count(anyString(), anyInt());

        target.advanceClock(1);
        target.drainBattery(2000);

        reset(mMetricsLogger);
        target.transitionState(
                BatterySaverState.OFF,
                InteractiveState.NON_INTERACTIVE,
                DozeState.NOT_DOZING);

        assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "01", 2);
        assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "01", 60);

        target.advanceClock(1);
        target.drainBattery(2000);

        reset(mMetricsLogger);
        target.transitionState(
                BatterySaverState.OFF,
                InteractiveState.NON_INTERACTIVE,
                DozeState.DEEP);

        target.advanceClock(1);
        target.drainBattery(2000);

        verify(mMetricsLogger, times(0)).count(anyString(), anyInt());

        target.transitionState(
                BatterySaverState.OFF,
                InteractiveState.NON_INTERACTIVE,
                DozeState.LIGHT);

        target.advanceClock(1);
        target.drainBattery(2000);

        verify(mMetricsLogger, times(0)).count(anyString(), anyInt());

        target.transitionState(
                BatterySaverState.ON,
                InteractiveState.INTERACTIVE,
                DozeState.NOT_DOZING);

        assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "00", 2 * 3);
        assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "00", 60 * 3);

        target.advanceClock(10);
        target.drainBattery(10_000);

        reset(mMetricsLogger);
        target.startCharging();

        assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "11", 10);
        assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "11", 60 * 10);

        target.advanceClock(1);
        target.drainBattery(2000);

        reset(mMetricsLogger);
        target.transitionState(
                BatterySaverState.ON,
                InteractiveState.NON_INTERACTIVE,
                DozeState.NOT_DOZING);

        verify(mMetricsLogger, times(0)).count(anyString(), anyInt());

        target.advanceClock(1);
        target.drainBattery(2000);

        target.startCharging();

        assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "10", 2);
        assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "10", 60);
    }
}