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

Commit 8b1b61c5 authored by Michael Wachenschwanz's avatar Michael Wachenschwanz Committed by Android (Google) Code Review
Browse files

Merge changes from topic...

Merge changes from topic "cherrypick-config_batteryStatsResetOnUnplugHighBatteryLevel-zmiab0332q" into tm-qpr-dev

* changes:
  Reset BatteryStats when device has been plugged in for a long time.
  Add config to control BatteryStats reset logic
parents 99db8bd9 88fbe863
Loading
Loading
Loading
Loading
+231 −18
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import android.telephony.ServiceState.RegState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -201,6 +202,7 @@ public class BatteryStatsImpl extends BatteryStats {
    public static final int RESET_REASON_ADB_COMMAND = 2;
    public static final int RESET_REASON_FULL_CHARGE = 3;
    public static final int RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE = 4;
    public static final int RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION = 5;
    protected Clock mClock;
@@ -387,6 +389,89 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    /** Provide BatteryStatsImpl configuration choices */
    public static class BatteryStatsConfig {
        static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0;
        static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1;
        private final int mFlags;
        private BatteryStatsConfig(Builder builder) {
            int flags = 0;
            if (builder.mResetOnUnplugHighBatteryLevel) {
                flags |= RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
            }
            if (builder.mResetOnUnplugAfterSignificantCharge) {
                flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
            }
            mFlags = flags;
        }
        /**
         * Returns whether a BatteryStats reset should occur on unplug when the battery level is
         * high.
         */
        boolean shouldResetOnUnplugHighBatteryLevel() {
            return (mFlags & RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG)
                    == RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG;
        }
        /**
         * Returns whether a BatteryStats reset should occur on unplug if the battery charge a
         * significant amount since it has been plugged in.
         */
        boolean shouldResetOnUnplugAfterSignificantCharge() {
            return (mFlags & RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG)
                    == RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;
        }
        /**
         * Builder for BatteryStatsConfig
         */
        public static class Builder {
            private boolean mResetOnUnplugHighBatteryLevel;
            private boolean mResetOnUnplugAfterSignificantCharge;
            public Builder() {
                mResetOnUnplugHighBatteryLevel = true;
                mResetOnUnplugAfterSignificantCharge = true;
            }
            /**
             * Build the BatteryStatsConfig.
             */
            public BatteryStatsConfig build() {
                return new BatteryStatsConfig(this);
            }
            /**
             * Set whether a BatteryStats reset should occur on unplug when the battery level is
             * high.
             */
            public Builder setResetOnUnplugHighBatteryLevel(boolean reset) {
                mResetOnUnplugHighBatteryLevel = reset;
                return this;
            }
            /**
             * Set whether a BatteryStats reset should occur on unplug if the battery charge a
             * significant amount since it has been plugged in.
             */
            public Builder setResetOnUnplugAfterSignificantCharge(boolean reset) {
                mResetOnUnplugAfterSignificantCharge = reset;
                return this;
            }
        }
    }
    /** Handles calls to AlarmManager */
    public interface AlarmInterface {
        /** Schedule an RTC alarm */
        void schedule(long rtcTimeMs, long windowLengthMs);
        /** Cancel the previously scheduled alarm */
        void cancel();
    }
    private final PlatformIdleStateCallback mPlatformIdleStateCallback;
    private final Runnable mDeferSetCharging = new Runnable() {
@@ -717,6 +802,7 @@ public class BatteryStatsImpl extends BatteryStats {
    protected boolean mHaveBatteryLevel = false;
    protected boolean mRecordingHistory = false;
    int mNumHistoryItems;
    private long mBatteryPluggedInRealTimeMs = 0;
    private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe;
    private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024;
@@ -1459,6 +1545,13 @@ public class BatteryStatsImpl extends BatteryStats {
    @GuardedBy("this")
    protected final Constants mConstants;
    @VisibleForTesting
    @GuardedBy("this")
    protected BatteryStatsConfig mBatteryStatsConfig = new BatteryStatsConfig.Builder().build();
    @VisibleForTesting
    protected AlarmInterface mLongPlugInAlarmInterface = null;
    /*
     * Holds a SamplingTimer associated with each Resource Power Manager state and voter,
     * recording their times when on-battery (regardless of screen state).
@@ -1625,12 +1718,13 @@ public class BatteryStatsImpl extends BatteryStats {
    public BatteryStatsImpl(Clock clock, File historyDirectory) {
        init(clock);
        mStartClockTimeMs = clock.currentTimeMillis();
        mCheckinFile = null;
        mDailyFile = null;
        if (historyDirectory == null) {
            mCheckinFile = null;
            mStatsFile = null;
            mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
        } else {
            mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin"));
            mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin"));
            mBatteryStatsHistory = new BatteryStatsHistory(this, historyDirectory, mHistoryBuffer);
        }
@@ -12547,6 +12641,27 @@ public class BatteryStatsImpl extends BatteryStats {
        return mPowerProfile;
    }
    /**
     * Injects BatteryStatsConfig
     */
    public void setBatteryStatsConfig(BatteryStatsConfig config) {
        synchronized (this) {
            mBatteryStatsConfig = config;
        }
    }
    /**
     * Injects a LongPlugInAlarmHandler
     */
    public void setLongPlugInAlarmInterface(AlarmInterface longPlugInAlarmInterface) {
        synchronized (this) {
            mLongPlugInAlarmInterface = longPlugInAlarmInterface;
            if (!mOnBattery) {
                scheduleNextResetWhilePluggedInCheck();
            }
        }
    }
    /**
     * Starts tracking CPU time-in-state for threads of the system server process,
     * keeping a separate account of threads receiving incoming binder calls.
@@ -13019,12 +13134,12 @@ public class BatteryStatsImpl extends BatteryStats {
    }
    @GuardedBy("this")
    public void resetAllStatsCmdLocked() {
    public void resetAllStatsAndHistoryLocked(int reason) {
        final long mSecUptime = mClock.uptimeMillis();
        long uptimeUs = mSecUptime * 1000;
        long mSecRealtime = mClock.elapsedRealtime();
        long realtimeUs = mSecRealtime * 1000;
        resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND);
        resetAllStatsLocked(mSecUptime, mSecRealtime, reason);
        mDischargeStartLevel = mHistoryCur.batteryLevel;
        pullPendingStateUpdatesLocked();
        addHistoryRecordLocked(mSecRealtime, mSecUptime);
@@ -15497,6 +15612,73 @@ public class BatteryStatsImpl extends BatteryStats {
        return false;
    }
    /**
     * Might reset battery stats if conditions are met. Assumed the device is currently plugged in.
     */
    @GuardedBy("this")
    public void maybeResetWhilePluggedInLocked() {
        final long elapsedRealtimeMs = mClock.elapsedRealtime();
        if (shouldResetWhilePluggedInLocked(elapsedRealtimeMs)) {
            Slog.i(TAG,
                    "Resetting due to long plug in duration. elapsed time = " + elapsedRealtimeMs
                            + " ms, last plug in time = " + mBatteryPluggedInRealTimeMs
                            + " ms, last reset time = " + mRealtimeStartUs / 1000);
            resetAllStatsAndHistoryLocked(RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION);
        }
        scheduleNextResetWhilePluggedInCheck();
    }
    @GuardedBy("this")
    private void scheduleNextResetWhilePluggedInCheck() {
        if (mLongPlugInAlarmInterface != null) {
            final long timeoutMs = mClock.currentTimeMillis()
                    + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
                    * DateUtils.HOUR_IN_MILLIS;
            Calendar nextAlarm = Calendar.getInstance();
            nextAlarm.setTimeInMillis(timeoutMs);
            // Find the 2 AM the same day as the end of the minimum duration.
            // This logic does not handle a Daylight Savings transition, or a timezone change
            // while the alarm has been set. The need to reset after a long period while plugged
            // in is not strict enough to warrant a well architected out solution.
            nextAlarm.set(Calendar.MILLISECOND, 0);
            nextAlarm.set(Calendar.SECOND, 0);
            nextAlarm.set(Calendar.MINUTE, 0);
            nextAlarm.set(Calendar.HOUR_OF_DAY, 2);
            long nextTimeMs = nextAlarm.getTimeInMillis();
            if (nextTimeMs < timeoutMs) {
                // The 2AM on the day of the timeout, move on the next day.
                nextTimeMs += DateUtils.DAY_IN_MILLIS;
            }
            mLongPlugInAlarmInterface.schedule(nextTimeMs, DateUtils.HOUR_IN_MILLIS);
        }
    }
    @GuardedBy("this")
    private boolean shouldResetWhilePluggedInLocked(long elapsedRealtimeMs) {
        if (mNoAutoReset) return false;
        if (!mSystemReady) return false;
        final long pluggedInThresholdMs = mBatteryPluggedInRealTimeMs
                + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
                * DateUtils.HOUR_IN_MILLIS;
        if (elapsedRealtimeMs >= pluggedInThresholdMs) {
            // The device has been plugged in for a long time.
            final long resetThresholdMs = mRealtimeStartUs / 1000
                    + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS
                    * DateUtils.HOUR_IN_MILLIS;
            if (elapsedRealtimeMs >= resetThresholdMs) {
                // And it has been a long time since the last reset.
                return true;
            }
        }
        return false;
    }
    /**
     * Notifies BatteryStatsImpl that the system server is ready.
     */
@@ -15504,6 +15686,32 @@ public class BatteryStatsImpl extends BatteryStats {
        mSystemReady = true;
    }
    @GuardedBy("this")
    private boolean shouldResetOnUnplugLocked(int batteryStatus, int batteryLevel) {
        if (mNoAutoReset) return false;
        if (!mSystemReady) return false;
        if (mBatteryStatsConfig.shouldResetOnUnplugHighBatteryLevel()) {
            // Allow resetting due to currently being at high battery level
            if (batteryStatus == BatteryManager.BATTERY_STATUS_FULL) return true;
            if (batteryLevel >= 90) return true;
        }
        if (mBatteryStatsConfig.shouldResetOnUnplugAfterSignificantCharge()) {
            // Allow resetting after a significant charge (from a very low level to a now very
            // high level).
            if (mDischargePlugLevel < 20 && batteryLevel >= 80) return true;
        }
        if (getHighDischargeAmountSinceCharge() >= 200) {
            // Reset the stats if battery got partially charged and discharged repeatedly without
            // ever reaching the full charge.
            // This reset is done in order to prevent stats sessions from going on forever.
            // Exceedingly long battery sessions would lead to an overflow of
            // data structures such as mWakeupReasonStats.
            return true;
        }
        return false;
    }
    @GuardedBy("this")
    protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
            final boolean onBattery, final int oldStatus, final int level, final int chargeUah) {
@@ -15516,23 +15724,10 @@ public class BatteryStatsImpl extends BatteryStats {
        final long realtimeUs = mSecRealtime * 1000;
        final int screenState = mScreenState;
        if (onBattery) {
            // We will reset our status if we are unplugging after the
            // battery was last full, or the level is at 100, or
            // we have gone through a significant charge (from a very low
            // level to a now very high level).
            // Also, we will reset the stats if battery got partially charged
            // and discharged repeatedly without ever reaching the full charge.
            // This reset is done in order to prevent stats sessions from going on forever.
            // Exceedingly long battery sessions would lead to an overflow of
            // data structures such as mWakeupReasonStats.
            boolean reset = false;
            if (!mNoAutoReset && mSystemReady
                    && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                    || level >= 90
                    || (mDischargeCurrentLevel < 20 && level >= 80)
                    || getHighDischargeAmountSinceCharge() >= 200)) {
            if (shouldResetOnUnplugLocked(oldStatus, level)) {
                Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
                        + " dischargeLevel=" + mDischargeCurrentLevel
                        + " dischargeLevel=" + mDischargePlugLevel
                        + " lowAmount=" + getLowDischargeAmountSinceCharge()
                        + " highAmount=" + getHighDischargeAmountSinceCharge());
                // Before we write, collect a snapshot of the final aggregated
@@ -15589,6 +15784,9 @@ public class BatteryStatsImpl extends BatteryStats {
            mInitStepMode = mCurStepMode;
            mModStepMode = 0;
            pullPendingStateUpdatesLocked();
            if (mLongPlugInAlarmInterface != null) {
                mLongPlugInAlarmInterface.cancel();
            }
            mHistoryCur.batteryLevel = (byte)level;
            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
@@ -15620,6 +15818,7 @@ public class BatteryStatsImpl extends BatteryStats {
            mLastChargingStateLevel = level;
            mOnBattery = mOnBatteryInternal = false;
            pullPendingStateUpdatesLocked();
            mBatteryPluggedInRealTimeMs = mSecRealtime;
            mHistoryCur.batteryLevel = (byte)level;
            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
@@ -15637,6 +15836,7 @@ public class BatteryStatsImpl extends BatteryStats {
            mMaxChargeStepLevel = level;
            mInitStepMode = mCurStepMode;
            mModStepMode = 0;
            scheduleNextResetWhilePluggedInCheck();
        }
        if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) {
            if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) {
@@ -16651,6 +16851,8 @@ public class BatteryStatsImpl extends BatteryStats {
        public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
        public static final String KEY_BATTERY_CHARGED_DELAY_MS =
                "battery_charged_delay_ms";
        public static final String KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS =
                "reset_while_plugged_in_minimum_duration_hours";
        private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
        private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -16663,6 +16865,8 @@ public class BatteryStatsImpl extends BatteryStats {
        private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
        private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
        private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
        // Little less than 2 days
        private static final int DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = 47;
        public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
        /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -16678,6 +16882,8 @@ public class BatteryStatsImpl extends BatteryStats {
        public int MAX_HISTORY_FILES;
        public int MAX_HISTORY_BUFFER; /*Bytes*/
        public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
        public int RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS =
                DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS;
        private ContentResolver mResolver;
        private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -16754,6 +16960,11 @@ public class BatteryStatsImpl extends BatteryStats {
                                DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
                                : DEFAULT_MAX_HISTORY_BUFFER_KB)
                        * 1024;
                RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = mParser.getInt(
                        KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS,
                        DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
                updateBatteryChargedDelayMsLocked();
            }
        }
@@ -16808,6 +17019,8 @@ public class BatteryStatsImpl extends BatteryStats {
            pw.println(MAX_HISTORY_BUFFER/1024);
            pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
            pw.println(BATTERY_CHARGED_DELAY_MS);
            pw.print(KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS); pw.print("=");
            pw.println(RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS);
        }
    }
+5 −0
Original line number Diff line number Diff line
@@ -6092,4 +6092,9 @@

    <!-- Whether to show weather on the lock screen by default. -->
    <bool name="config_lockscreenWeatherEnabledByDefault">false</bool>

    <!-- Whether to reset Battery Stats on unplug when the battery level is high. -->
    <bool name="config_batteryStatsResetOnUnplugHighBatteryLevel">true</bool>
    <!-- Whether to reset Battery Stats on unplug if the battery was significantly charged -->
    <bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool>
</resources>
+3 −0
Original line number Diff line number Diff line
@@ -4903,4 +4903,7 @@

  <!-- Whether to show weather on the lockscreen by default. -->
  <java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />

  <java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
  <java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
</resources>
+362 −0

File added.

Preview size limit exceeded, changes collapsed.

+4 −4
Original line number Diff line number Diff line
@@ -342,7 +342,7 @@ public class BatteryUsageStatsProviderTest {
        Context context = InstrumentationRegistry.getContext();
        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
        mStatsRule.setCurrentTime(5 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();
        batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);

        BatteryUsageStatsStore batteryUsageStatsStore = new BatteryUsageStatsStore(context,
                batteryStats, new File(context.getCacheDir(), "BatteryUsageStatsProviderTest"),
@@ -357,14 +357,14 @@ public class BatteryUsageStatsProviderTest {
        batteryStats.noteFlashlightOffLocked(APP_UID,
                20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(25 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();
        batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);

        batteryStats.noteFlashlightOnLocked(APP_UID,
                30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
        batteryStats.noteFlashlightOffLocked(APP_UID,
                50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(55 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();
        batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);

        // This section should be ignored because the timestamp is out or range
        batteryStats.noteFlashlightOnLocked(APP_UID,
@@ -372,7 +372,7 @@ public class BatteryUsageStatsProviderTest {
        batteryStats.noteFlashlightOffLocked(APP_UID,
                70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(75 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();
        batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND);

        // This section should be ignored because it represents the current stats session
        batteryStats.noteFlashlightOnLocked(APP_UID,
Loading