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

Commit 43e4dede authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge changes I612f840f,I2c4a3eab into main

* changes:
  Change battery history timestamp format
  Add extended_battery_history_continuous_collection_enabled flag
parents bfc1502e 398548ca
Loading
Loading
Loading
Loading
+76 −26
Original line number Diff line number Diff line
@@ -69,16 +69,19 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

/**
 * A class providing access to battery usage statistics, including information on
@@ -1868,6 +1871,11 @@ public abstract class BatteryStats {
        @UnsupportedAppUsage
        public long time;

        // Wall clock time of the event, GMT. Unlike `time`, this timestamp is affected
        // by changes in the clock setting.  When the wall clock is adjusted, BatteryHistory
        // records an event of type `CMD_CURRENT_TIME` or `CMD_RESET`.
        public long currentTime;

        @UnsupportedAppUsage
        public static final byte CMD_UPDATE = 0;        // These can be written as deltas
        public static final byte CMD_NULL = -1;
@@ -2108,9 +2116,6 @@ public abstract class BatteryStats {
        public int eventCode;
        public HistoryTag eventTag;

        // Only set for CMD_CURRENT_TIME or CMD_RESET, as per System.currentTimeMillis().
        public long currentTime;

        // Meta-data when reading.
        public int numReadInts;

@@ -6926,6 +6931,23 @@ public abstract class BatteryStats {
    }

    public static class HistoryPrinter {
        private static final int FORMAT_LEGACY = 1;

        // This constant MUST be incremented whenever the history dump format changes.
        private static final int FORMAT_VERSION = 2;

        private final SimpleDateFormat mHistoryItemTimestampFormat =
                new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);
        private final SimpleDateFormat mCurrentTimeEventTimeFormat =
                new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);

        // This API is error prone, but we are making an exception here to avoid excessive
        // object allocations.
        @SuppressWarnings("JavaUtilDate")
        private final Date mDate = new Date();

        private final int mFormatVersion;

        int oldState = 0;
        int oldState2 = 0;
        int oldLevel = -1;
@@ -6939,6 +6961,22 @@ public abstract class BatteryStats {
        double oldWifiRailChargeMah = -1;
        long lastTime = -1;

        public HistoryPrinter() {
            this(TimeZone.getDefault());
        }

        public HistoryPrinter(TimeZone timeZone) {
            this(com.android.server.power.optimization.Flags
                    .extendedBatteryHistoryContinuousCollectionEnabled()
                    ? FORMAT_VERSION : FORMAT_LEGACY, timeZone);
        }

        private HistoryPrinter(int formatVersion, TimeZone timeZone) {
            mFormatVersion = formatVersion;
            mHistoryItemTimestampFormat.getCalendar().setTimeZone(timeZone);
            mCurrentTimeEventTimeFormat.getCalendar().setTimeZone(timeZone);
        }

        void reset() {
            oldState = oldState2 = 0;
            oldLevel = -1;
@@ -6966,16 +7004,22 @@ public abstract class BatteryStats {
            }
        }

        @SuppressWarnings("JavaUtilDate")
        private String printNextItem(HistoryItem rec, long baseTime, boolean checkin,
                boolean verbose) {
            StringBuilder item = new StringBuilder();
            if (!checkin) {
                item.append("  ");
                if (mFormatVersion == FORMAT_LEGACY) {
                    TimeUtils.formatDuration(
                            rec.time - baseTime, item, TimeUtils.HUNDRED_DAY_FIELD_LEN);
                    item.append(" (");
                    item.append(rec.numReadInts);
                    item.append(") ");
                } else {
                    mDate.setTime(rec.currentTime);
                    item.append(mHistoryItemTimestampFormat.format(mDate)).append(' ');
                }
            } else {
                item.append(BATTERY_STATS_CHECKIN_VERSION); item.append(',');
                item.append(HISTORY_DATA); item.append(',');
@@ -7007,8 +7051,8 @@ public abstract class BatteryStats {
                    item.append("\n");
                } else {
                    item.append(" ");
                    item.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
                            rec.currentTime).toString());
                    mDate.setTime(rec.currentTime);
                    item.append(mCurrentTimeEventTimeFormat.format(mDate));
                    item.append("\n");
                }
            } else if (rec.cmd == HistoryItem.CMD_SHUTDOWN) {
@@ -7529,11 +7573,31 @@ public abstract class BatteryStats {
    public static final int DUMP_DEVICE_WIFI_ONLY = 1<<6;

    private void dumpHistory(PrintWriter pw, int flags, long histStart, boolean checkin) {
        final HistoryPrinter hprinter = new HistoryPrinter();
        synchronized (this) {
            if (!checkin) {
                final long historyTotalSize = getHistoryTotalSize();
                final long historyUsedSize = getHistoryUsedSize();
                pw.print("Battery History");
                if (hprinter.mFormatVersion != HistoryPrinter.FORMAT_LEGACY) {
                    pw.print(" [Format: " + hprinter.mFormatVersion + "]");
                }
                pw.print(" (");
                pw.print((100 * historyUsedSize) / historyTotalSize);
                pw.print("% used, ");
                printSizeValue(pw, historyUsedSize);
                pw.print(" used of ");
                printSizeValue(pw, historyTotalSize);
                pw.print(", ");
                pw.print(getHistoryStringPoolSize());
                pw.print(" strings using ");
                printSizeValue(pw, getHistoryStringPoolBytes());
                pw.println("):");
            } else {
                dumpHistoryTagPoolLocked(pw, checkin);
            }
        }

        final HistoryPrinter hprinter = new HistoryPrinter();
        long lastTime = -1;
        long baseTime = -1;
        boolean printed = false;
@@ -7645,20 +7709,6 @@ public abstract class BatteryStats {
                pw.print("\"");
                pw.println();
            }
        } else {
            final long historyTotalSize = getHistoryTotalSize();
            final long historyUsedSize = getHistoryUsedSize();
            pw.print("Battery History (");
            pw.print((100 * historyUsedSize) / historyTotalSize);
            pw.print("% used, ");
            printSizeValue(pw, historyUsedSize);
            pw.print(" used of ");
            printSizeValue(pw, historyTotalSize);
            pw.print(", ");
            pw.print(getHistoryStringPoolSize());
            pw.print(" strings using ");
            printSizeValue(pw, getHistoryStringPoolBytes());
            pw.println("):");
        }
    }

+11 −8
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
    private boolean mNextItemReady;
    private boolean mTimeInitialized;
    private boolean mClosed;
    private long mBaseMonotonicTime;
    private long mBaseTimeUtc;

    public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, long startTimeMs,
            long endTimeMs) {
@@ -84,24 +86,25 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
            }

            if (!mTimeInitialized) {
                mHistoryItem.time = mBatteryStatsHistory.getHistoryBufferStartTime(p);
                mBaseMonotonicTime = mBatteryStatsHistory.getHistoryBufferStartTime(p);
                mHistoryItem.time = mBaseMonotonicTime;
                mTimeInitialized = true;
            }

            final long lastMonotonicTimeMs = mHistoryItem.time;
            final long lastWalltimeMs = mHistoryItem.currentTime;
            try {
                readHistoryDelta(p, mHistoryItem);
            } catch (Throwable t) {
                Slog.wtf(TAG, "Corrupted battery history", t);
                break;
            }
            if (mHistoryItem.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME
                    && mHistoryItem.cmd != BatteryStats.HistoryItem.CMD_RESET
                    && lastWalltimeMs != 0) {
                mHistoryItem.currentTime =
                        lastWalltimeMs + (mHistoryItem.time - lastMonotonicTimeMs);

            if (mHistoryItem.cmd == BatteryStats.HistoryItem.CMD_CURRENT_TIME
                    || mHistoryItem.cmd == BatteryStats.HistoryItem.CMD_RESET) {
                mBaseTimeUtc = mHistoryItem.currentTime - (mHistoryItem.time - mBaseMonotonicTime);
            }

            mHistoryItem.currentTime = mBaseTimeUtc + (mHistoryItem.time - mBaseMonotonicTime);

            if (mEndTimeMs != 0 && mHistoryItem.time >= mEndTimeMs) {
                break;
            }
+10 −0
Original line number Diff line number Diff line
@@ -87,3 +87,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "extended_battery_history_continuous_collection_enabled"
    namespace: "backstage_power"
    description: "Disable automatic reset of battery stats history on full charge"
    bug: "381940953"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+45 −28
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.NetworkRegistrationInfo;
import android.util.AtomicFile;
import android.util.Log;
@@ -46,6 +48,7 @@ import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerStats;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@@ -61,14 +64,22 @@ import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;

/**
 * Test BatteryStatsHistory.
 */
@RunWith(AndroidJUnit4.class)
@EnableFlags({com.android.server.power.optimization.Flags
        .FLAG_EXTENDED_BATTERY_HISTORY_CONTINUOUS_COLLECTION_ENABLED})
public class BatteryStatsHistoryTest {
    private static final String TAG = "BatteryStatsHistoryTest";

    private static final int MAX_HISTORY_BUFFER_SIZE = 1024;

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    private final Parcel mHistoryBuffer = Parcel.obtain();
    private File mSystemDir;
    private File mHistoryDir;
@@ -98,15 +109,18 @@ public class BatteryStatsHistoryTest {
        mHistoryDir.delete();

        mClock.realtime = 123;
        mClock.currentTime = 1743645660000L;    //  2025-04-03, 2:01:00 AM

        mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32768,
                MAX_HISTORY_BUFFER_SIZE, mStepDetailsCalculator, mClock, mMonotonicClock, mTracer,
                mEventLogger);
        mHistory.forceRecordAllHistory();
        mHistory.startRecordingHistory(mClock.realtime, mClock.uptime, false);

        when(mStepDetailsCalculator.getHistoryStepDetails())
                .thenReturn(new BatteryStats.HistoryStepDetails());

        mHistoryPrinter = new BatteryStats.HistoryPrinter();
        mHistoryPrinter = new BatteryStats.HistoryPrinter(TimeZone.getTimeZone("GMT"));
    }

    @Test
@@ -145,8 +159,6 @@ public class BatteryStatsHistoryTest {

    @Test
    public void testAtraceExcludedState() {
        mHistory.forceRecordAllHistory();

        Mockito.when(mTracer.tracingEnabled()).thenReturn(true);

        mHistory.recordStateStartEvent(mClock.elapsedRealtime(),
@@ -354,8 +366,6 @@ public class BatteryStatsHistoryTest {
    }

    private void prepareMultiFileHistory() {
        mHistory.forceRecordAllHistory();

        mClock.realtime = 1000;
        mClock.uptime = 1000;
        mHistory.recordEvent(mClock.realtime, mClock.uptime,
@@ -428,7 +438,8 @@ public class BatteryStatsHistoryTest {
        powerStats.uidStats.put(300, new long[]{400, 500});
        powerStats.uidStats.put(600, new long[]{700, 800});

        mHistory.recordPowerStats(200, 200, powerStats);
        mClock.advance(200);
        mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats);

        BatteryStatsHistoryIterator iterator = mHistory.iterate(0, MonotonicClock.UNDEFINED);
        BatteryStats.HistoryItem item;
@@ -437,7 +448,7 @@ public class BatteryStatsHistoryTest {
        assertThat(item = iterator.next()).isNotNull();

        String dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+200ms");
        assertThat(dump).contains("04-03 02:01:00.200");
        assertThat(dump).contains("duration=100");
        assertThat(dump).contains("foo=[200]");
        assertThat(dump).contains("300: [400, 500]");
@@ -446,49 +457,49 @@ public class BatteryStatsHistoryTest {

    @Test
    public void testNrState_dump() {
        mHistory.forceRecordAllHistory();
        mHistory.startRecordingHistory(0, 0, /* reset */ true);
        mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
                1234);

        mHistory.recordNrStateChangeEvent(200, 200,
        mClock.advance(200);
        mHistory.recordNrStateChangeEvent(mClock.realtime, mClock.uptime,
                NetworkRegistrationInfo.NR_STATE_RESTRICTED);
        mHistory.recordNrStateChangeEvent(300, 300,
        mClock.advance(100);
        mHistory.recordNrStateChangeEvent(mClock.realtime, mClock.uptime,
                NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
        mHistory.recordNrStateChangeEvent(400, 400,
        mClock.advance(100);
        mHistory.recordNrStateChangeEvent(mClock.realtime, mClock.uptime,
                NetworkRegistrationInfo.NR_STATE_CONNECTED);
        mHistory.recordNrStateChangeEvent(500, 500,
        mClock.advance(100);
        mHistory.recordNrStateChangeEvent(mClock.realtime, mClock.uptime,
                NetworkRegistrationInfo.NR_STATE_NONE);

        BatteryStatsHistoryIterator iterator = mHistory.iterate(0, MonotonicClock.UNDEFINED);
        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
        BatteryStats.HistoryItem item;
        assertThat(item = iterator.next()).isNotNull(); // First item contains current time only

        assertThat(item = iterator.next()).isNotNull();
        String dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+200ms");
        assertThat(dump).contains("04-03 02:01:00.200");
        assertThat(dump).contains("nr_state=restricted");

        assertThat(item = iterator.next()).isNotNull();
        dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+300ms");
        assertThat(dump).contains("04-03 02:01:00.300");
        assertThat(dump).contains("nr_state=not_restricted");

        assertThat(item = iterator.next()).isNotNull();
        dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+400ms");
        assertThat(dump).contains("04-03 02:01:00.400");
        assertThat(dump).contains("nr_state=connected");

        assertThat(item = iterator.next()).isNotNull();
        dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+500ms");
        assertThat(dump).contains("04-03 02:01:00.500");
        assertThat(dump).contains("nr_state=none");
    }

    @Test
    public void testNrState_checkin() {
        mHistory.forceRecordAllHistory();
        mHistory.startRecordingHistory(0, 0, /* reset */ true);
        mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
                1234);

@@ -502,7 +513,7 @@ public class BatteryStatsHistoryTest {
                NetworkRegistrationInfo.NR_STATE_NONE);

        BatteryStatsHistoryIterator iterator = mHistory.iterate(0, MonotonicClock.UNDEFINED);
        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
        BatteryStats.HistoryItem item;
        assertThat(item = iterator.next()).isNotNull(); // First item contains current time only

        assertThat(item = iterator.next()).isNotNull();
@@ -633,10 +644,17 @@ public class BatteryStatsHistoryTest {

    @Test
    public void recordProcStateChange() {
        mHistory.recordProcessStateChange(200, 200, 42, BatteryConsumer.PROCESS_STATE_BACKGROUND);
        mHistory.recordProcessStateChange(300, 300, 42, BatteryConsumer.PROCESS_STATE_FOREGROUND);
        mClock.advance(200);
        mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, 42,
                BatteryConsumer.PROCESS_STATE_BACKGROUND);

        mClock.advance(100);
        mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime, 42,
                BatteryConsumer.PROCESS_STATE_FOREGROUND);

        mClock.advance(100);
        // Large UID, > 0xFFFFFF
        mHistory.recordProcessStateChange(400, 400,
        mHistory.recordProcessStateChange(mClock.realtime, mClock.uptime,
                UserHandle.getUid(777, Process.LAST_ISOLATED_UID),
                BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);

@@ -647,17 +665,17 @@ public class BatteryStatsHistoryTest {
        assertThat(item = iterator.next()).isNotNull();

        String dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+200ms");
        assertThat(dump).contains("04-03 02:01:00.200");
        assertThat(dump).contains("procstate: 42: bg");

        assertThat(item = iterator.next()).isNotNull();
        dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+300ms");
        assertThat(dump).contains("04-03 02:01:00.300");
        assertThat(dump).contains("procstate: 42: fg");

        assertThat(item = iterator.next()).isNotNull();
        dump = toString(item, /* checkin */ false);
        assertThat(dump).contains("+400ms");
        assertThat(dump).contains("04-03 02:01:00.400");
        assertThat(dump).contains("procstate: u777i999: fgs");
    }

@@ -672,7 +690,6 @@ public class BatteryStatsHistoryTest {
    @Test
    public void getMonotonicHistorySize() {
        long lastHistorySize = mHistory.getMonotonicHistorySize();
        mHistory.forceRecordAllHistory();

        mClock.realtime = 1000;
        mClock.uptime = 1000;
+9 −0
Original line number Diff line number Diff line
@@ -40,4 +40,13 @@ public class MockClock extends Clock {
    public long currentTimeMillis() {
        return currentTime;
    }

    /**
     * Advances the clock by the given number of milliseconds.
     */
    public void advance(long milliseconds) {
        realtime += milliseconds;
        uptime += milliseconds;
        currentTime += milliseconds;
    }
}