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

Commit 3347b015 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Include proc state change in battery history

Bug: 285646152
Test: atest FrameworksCoreTests:BatteryStatsTests FrameworksServicesTests:BatteryStatsTests

Change-Id: I042ef568f15d329a9129d2345aa29fda6c9e6010
parent 0e2f3922
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -1793,6 +1793,59 @@ public abstract class BatteryStats {
        }
    }

    /**
     * An extension to the history item describing a proc state change for a UID.
     */
    public static final class ProcessStateChange {
        public int uid;
        public @BatteryConsumer.ProcessState int processState;

        private static final int LARGE_UID_FLAG = 0x80000000;
        private static final int SMALL_UID_MASK = 0x00FFFFFF;
        private static final int PROC_STATE_MASK = 0x7F000000;
        private static final int PROC_STATE_SHIFT = Integer.numberOfTrailingZeros(PROC_STATE_MASK);

        /**
         * Writes this object to the supplied parcel.
         */
        public void writeToParcel(Parcel out) {
            int bits = processState << PROC_STATE_SHIFT;
            if ((uid & ~SMALL_UID_MASK) == 0) {
                bits |= uid;
                out.writeInt(bits);
            } else {
                bits |= LARGE_UID_FLAG;
                out.writeInt(bits);
                out.writeInt(uid);
            }
        }

        /**
         * Reads this object from the supplied parcel.
         */
        public void readFromParcel(Parcel in) {
            int bits = in.readInt();
            processState = (bits & PROC_STATE_MASK) >>> PROC_STATE_SHIFT;
            if (processState >= BatteryConsumer.PROCESS_STATE_COUNT) {
                Slog.e(TAG, "Unrecognized proc state in battery history: " + processState);
                processState = BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
            }
            if ((bits & LARGE_UID_FLAG) == 0) {
                uid = bits & ~PROC_STATE_MASK;
            } else {
                uid = in.readInt();
            }
        }

        /**
         * String representation for inclusion in the battery history dump.
         */
        public String formatForBatteryHistory() {
            return UserHandle.formatUid(uid) + ": "
                    + BatteryConsumer.processStateToString(processState);
        }
    }

    /**
     * Battery history record.
     */
@@ -1939,6 +1992,9 @@ public abstract class BatteryStats {
        // Non-null when there are power stats to be written to history
        public PowerStats powerStats;

        // Non-null when there is procstate change to be written to history
        public ProcessStateChange processStateChange;

        public static final int EVENT_FLAG_START = 0x8000;
        public static final int EVENT_FLAG_FINISH = 0x4000;

@@ -2035,6 +2091,7 @@ public abstract class BatteryStats {
        public final HistoryTag localWakelockTag = new HistoryTag();
        public final HistoryTag localWakeReasonTag = new HistoryTag();
        public final HistoryTag localEventTag = new HistoryTag();
        public final ProcessStateChange localProcessStateChange = new ProcessStateChange();

        // Includes a tag's first occurrence in the parcel, so the value of the tag is written
        // rather than just its index in the history tag pool.
@@ -2148,6 +2205,7 @@ public abstract class BatteryStats {
            eventTag = null;
            tagsFirstOccurrence = false;
            powerStats = null;
            processStateChange = null;
        }

        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -2198,6 +2256,7 @@ public abstract class BatteryStats {
            tagsFirstOccurrence = o.tagsFirstOccurrence;
            currentTime = o.currentTime;
            powerStats = o.powerStats;
            processStateChange = o.processStateChange;
        }

        public boolean sameNonEvent(HistoryItem o) {
@@ -7077,6 +7136,12 @@ public abstract class BatteryStats {
                                "\n                    "));
                    }
                }
                if (rec.processStateChange != null && verbose) {
                    if (!checkin) {
                        item.append(" procstate: ");
                        item.append(rec.processStateChange.formatForBatteryHistory());
                    }
                }
                item.append("\n");
                if (rec.stepDetails != null) {
                    if (!checkin) {
+27 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.os;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.BitDescription;
@@ -124,6 +125,7 @@ public class BatteryStatsHistory {

    static final int EXTENSION_POWER_STATS_DESCRIPTOR_FLAG = 0x00000001;
    static final int EXTENSION_POWER_STATS_FLAG = 0x00000002;
    static final int EXTENSION_PROCESS_STATE_CHANGE_FLAG = 0x00000004;

    // For state1, trace everything except the wakelock bit (which can race with
    // suspend) and the running bit (which isn't meaningful in traces).
@@ -1052,6 +1054,18 @@ public class BatteryStatsHistory {
        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
    }

    /**
     * Records the change of a UID's proc state.
     */
    public void recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs,
            int uid, @BatteryConsumer.ProcessState int processState) {
        mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
        mHistoryCur.processStateChange.uid = uid;
        mHistoryCur.processStateChange.processState = processState;
        mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
    }

    /**
     * Records a history item with the amount of charge consumed by WiFi.  Used on certain devices
     * equipped with on-device power metering.
@@ -1337,7 +1351,9 @@ public class BatteryStatsHistory {
            mTraceLastState2 = cur.states2;
        }

        if ((!mHaveBatteryLevel || !mRecordingHistory) && cur.powerStats == null) {
        if ((!mHaveBatteryLevel || !mRecordingHistory)
                && cur.powerStats == null
                && cur.processStateChange == null) {
            return;
        }

@@ -1373,7 +1389,8 @@ public class BatteryStatsHistory {
                && mHistoryLastWritten.batteryPlugType == cur.batteryPlugType
                && mHistoryLastWritten.batteryTemperature == cur.batteryTemperature
                && mHistoryLastWritten.batteryVoltage == cur.batteryVoltage
                && mHistoryLastWritten.powerStats == null) {
                && mHistoryLastWritten.powerStats == null
                && mHistoryLastWritten.processStateChange == null) {
            // We can merge this new change in with the last one.  Merging is
            // allowed as long as only the states have changed, and within those states
            // as long as no bit has changed both between now and the last entry, as
@@ -1458,6 +1475,7 @@ public class BatteryStatsHistory {
            copy.eventTag = null;
            copy.tagsFirstOccurrence = false;
            copy.powerStats = null;
            copy.processStateChange = null;
            writeHistoryItem(elapsedRealtimeMs, uptimeMs, copy, HistoryItem.CMD_RESET);
        }
        writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
@@ -1486,6 +1504,7 @@ public class BatteryStatsHistory {
        cur.eventTag = null;
        cur.tagsFirstOccurrence = false;
        cur.powerStats = null;
        cur.processStateChange = null;
        if (DEBUG) {
            Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
                    + " now " + mHistoryBuffer.dataPosition()
@@ -1622,6 +1641,9 @@ public class BatteryStatsHistory {
                extensionFlags |= BatteryStatsHistory.EXTENSION_POWER_STATS_DESCRIPTOR_FLAG;
            }
        }
        if (cur.processStateChange != null) {
            extensionFlags |= BatteryStatsHistory.EXTENSION_PROCESS_STATE_CHANGE_FLAG;
        }
        if (extensionFlags != 0) {
            cur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
        } else {
@@ -1753,6 +1775,9 @@ public class BatteryStatsHistory {
                }
                cur.powerStats.writeToParcel(dest);
            }
            if (cur.processStateChange != null) {
                cur.processStateChange.writeToParcel(dest);
            }
        }
    }

+7 −0
Original line number Diff line number Diff line
@@ -232,8 +232,15 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor
            } else {
                cur.powerStats = null;
            }
            if ((extensionFlags & BatteryStatsHistory.EXTENSION_PROCESS_STATE_CHANGE_FLAG) != 0) {
                cur.processStateChange = cur.localProcessStateChange;
                cur.processStateChange.readFromParcel(src);
            } else {
                cur.processStateChange = null;
            }
        } else {
            cur.powerStats = null;
            cur.processStateChange = null;
        }
    }

+5 −0
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
import libcore.util.EmptyArray;
@@ -10552,6 +10553,10 @@ public class BatteryStatsImpl extends BatteryStats {
                final int batteryConsumerProcessState =
                        mapUidProcessStateToBatteryConsumerProcessState(uidRunningState);
                if (mBsi.mSystemReady && Flags.streamlinedBatteryStats()) {
                    mBsi.mHistory.recordProcessStateChange(elapsedRealtimeMs, uptimeMs, mUid,
                            batteryConsumerProcessState);
                }
                getCpuActiveTimeCounter().setState(batteryConsumerProcessState, elapsedRealtimeMs);
                getMobileRadioActiveTimeCounter()
+36 −2
Original line number Diff line number Diff line
@@ -24,10 +24,14 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Process;
import android.os.UserHandle;
import android.telephony.NetworkRegistrationInfo;
import android.util.Log;

@@ -484,6 +488,36 @@ public class BatteryStatsHistoryTest {
        assertThat(wakeReasonTagsUnpooled).isGreaterThan(0);
    }

    @Test
    public void recordProcStateChange() {
        mHistory.recordProcessStateChange(200, 200, 42, BatteryConsumer.PROCESS_STATE_BACKGROUND);
        mHistory.recordProcessStateChange(300, 300, 42, BatteryConsumer.PROCESS_STATE_FOREGROUND);
        // Large UID, > 0xFFFFFF
        mHistory.recordProcessStateChange(400, 400,
                UserHandle.getUid(777, Process.LAST_ISOLATED_UID),
                BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);

        BatteryStatsHistoryIterator iterator = mHistory.iterate();
        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("procstate: 42: bg");

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

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

    private String toString(BatteryStats.HistoryItem item, boolean checkin) {
        StringWriter writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);