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

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

Merge "Limit amount of battery history included in BatteryUsageStats" into main

parents 25b0a52f c9ba6c23
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
    private final List<UserBatteryConsumer> mUserBatteryConsumers;
    private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
    private final BatteryStatsHistory mBatteryStatsHistory;
    private final long mPreferredHistoryDurationMs;
    private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout;
    private CursorWindow mBatteryConsumersCursorWindow;

@@ -174,6 +175,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
        mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
        mDischargeDurationMs = builder.mDischargeDurationMs;
        mBatteryStatsHistory = builder.mBatteryStatsHistory;
        mPreferredHistoryDurationMs = builder.mPreferredHistoryDurationMs;
        mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
        mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
        mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
@@ -402,8 +404,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable {

        if (source.readBoolean()) {
            mBatteryStatsHistory = BatteryStatsHistory.createFromBatteryUsageStatsParcel(source);
            mPreferredHistoryDurationMs = source.readLong();
        } else {
            mBatteryStatsHistory = null;
            mPreferredHistoryDurationMs = 0;
        }
    }

@@ -428,7 +432,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {

        if (mBatteryStatsHistory != null) {
            dest.writeBoolean(true);
            mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest);
            mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest, mPreferredHistoryDurationMs);
        } else {
            dest.writeBoolean(false);
        }
@@ -919,6 +923,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
        private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
                new SparseArray<>();
        private BatteryStatsHistory mBatteryStatsHistory;
        private long mPreferredHistoryDurationMs;

        public Builder(@NonNull String[] customPowerComponentNames) {
            this(customPowerComponentNames, false, false, false, 0);
@@ -1092,8 +1097,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
         * Sets the parceled recent history.
         */
        @NonNull
        public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory) {
        public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory,
                long preferredHistoryDurationMs) {
            mBatteryStatsHistory = batteryStatsHistory;
            mPreferredHistoryDurationMs = preferredHistoryDurationMs;
            return this;
        }

+25 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.internal.os.MonotonicClock;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * Query parameters for the {@link BatteryStatsManager#getBatteryUsageStats()} call.
@@ -77,6 +78,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
    public static final int FLAG_BATTERY_USAGE_STATS_ACCUMULATED = 0x0080;

    private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000;
    private static final long DEFAULT_PREFERRED_HISTORY_DURATION_MS = TimeUnit.HOURS.toMillis(2);

    private final int mFlags;
    @NonNull
@@ -89,6 +91,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
    private long mMonotonicEndTime;
    private final double mMinConsumedPowerThreshold;
    private final @BatteryConsumer.PowerComponentId int[] mPowerComponents;
    private final long mPreferredHistoryDurationMs;

    private BatteryUsageStatsQuery(@NonNull Builder builder) {
        mFlags = builder.mFlags;
@@ -101,6 +104,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        mMonotonicStartTime = builder.mMonotonicStartTime;
        mMonotonicEndTime = builder.mMonotonicEndTime;
        mPowerComponents = builder.mPowerComponents;
        mPreferredHistoryDurationMs = builder.mPreferredHistoryDurationMs;
    }

    @BatteryUsageStatsFlags
@@ -197,6 +201,13 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        return mAggregatedToTimestamp;
    }

    /**
     * Returns the preferred duration of battery history (tail) to be included in the query result.
     */
    public long getPreferredHistoryDurationMs() {
        return mPreferredHistoryDurationMs;
    }

    @Override
    public String toString() {
        return "BatteryUsageStatsQuery{"
@@ -209,6 +220,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
                + ", mMonotonicEndTime=" + mMonotonicEndTime
                + ", mMinConsumedPowerThreshold=" + mMinConsumedPowerThreshold
                + ", mPowerComponents=" + Arrays.toString(mPowerComponents)
                + ", mMaxHistoryDurationMs=" + mPreferredHistoryDurationMs
                + '}';
    }

@@ -223,6 +235,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        mAggregatedFromTimestamp = in.readLong();
        mAggregatedToTimestamp = in.readLong();
        mPowerComponents = in.createIntArray();
        mPreferredHistoryDurationMs = in.readLong();
    }

    @Override
@@ -237,6 +250,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        dest.writeLong(mAggregatedFromTimestamp);
        dest.writeLong(mAggregatedToTimestamp);
        dest.writeIntArray(mPowerComponents);
        dest.writeLong(mPreferredHistoryDurationMs);
    }

    @Override
@@ -271,6 +285,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        private long mAggregateToTimestamp;
        private double mMinConsumedPowerThreshold = 0;
        private @BatteryConsumer.PowerComponentId int[] mPowerComponents;
        private long mPreferredHistoryDurationMs = DEFAULT_PREFERRED_HISTORY_DURATION_MS;

        /**
         * Builds a read-only BatteryUsageStatsQuery object.
@@ -310,6 +325,16 @@ public final class BatteryUsageStatsQuery implements Parcelable {
            return this;
        }

        /**
         * Set the preferred amount of battery history to be included in the result, provided
         * that `includeBatteryHistory` is also called. The actual amount of history included in
         * the result may vary for performance reasons and may exceed the specified preference.
         */
        public Builder setPreferredHistoryDurationMs(long preferredHistoryDurationMs) {
            mPreferredHistoryDurationMs = preferredHistoryDurationMs;
            return this;
        }

        /**
         * Requests that per-process state data be included in the BatteryUsageStats, if
         * available. Check {@link BatteryUsageStats#isProcessStateDataIncluded()} on the result
+37 −14
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ public class BatteryStatsHistory {
    private static final String TAG = "BatteryStatsHistory";

    // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
    private static final int VERSION = 211;
    private static final int VERSION = 212;

    private static final String HISTORY_DIR = "battery-history";
    private static final String FILE_SUFFIX = ".bh";
@@ -211,6 +211,8 @@ public class BatteryStatsHistory {
    private final MonotonicClock mMonotonicClock;
    // Monotonic time when we started writing to the history buffer
    private long mHistoryBufferStartTime;
    // Monotonic time when the last event was written to the history buffer
    private long mHistoryMonotonicEndTime;
    // Monotonically increasing size of written history
    private long mMonotonicHistorySize;
    private final ArraySet<PowerStats.Descriptor> mWrittenPowerStatsDescriptors = new ArraySet<>();
@@ -423,13 +425,22 @@ public class BatteryStatsHistory {
            return file;
        }

        void writeToParcel(Parcel out, boolean useBlobs) {
        void writeToParcel(Parcel out, boolean useBlobs,
                long preferredEarliestIncludedTimestampMs) {
            Trace.traceBegin(TRACE_TAG_SYSTEM_SERVER, "BatteryStatsHistory.writeToParcel");
            lock();
            try {
                final long start = SystemClock.uptimeMillis();
                out.writeInt(mHistoryFiles.size() - 1);
                for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
                    long monotonicEndTime = Long.MAX_VALUE;
                    if (i < mHistoryFiles.size() - 1) {
                        monotonicEndTime = mHistoryFiles.get(i + 1).monotonicTimeMs;
                    }

                    if (monotonicEndTime < preferredEarliestIncludedTimestampMs) {
                        continue;
                    }

                    AtomicFile file = mHistoryFiles.get(i).atomicFile;
                    byte[] raw = new byte[0];
                    try {
@@ -437,6 +448,8 @@ public class BatteryStatsHistory {
                    } catch (Exception e) {
                        Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
                    }

                    out.writeBoolean(true);
                    if (useBlobs) {
                        out.writeBlob(raw);
                    } else {
@@ -444,6 +457,7 @@ public class BatteryStatsHistory {
                        out.writeByteArray(raw);
                    }
                }
                out.writeBoolean(false);
                if (DEBUG) {
                    Slog.d(TAG,
                            "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
@@ -634,6 +648,7 @@ public class BatteryStatsHistory {
        mWritableHistory = writableHistory;
        if (mWritableHistory != null) {
            mMutable = false;
            mHistoryMonotonicEndTime = mWritableHistory.mHistoryMonotonicEndTime;
        }

        if (historyBuffer != null) {
@@ -937,6 +952,8 @@ public class BatteryStatsHistory {
                }
                // skip monotonic time field.
                p.readLong();
                // skip monotonic end time field
                p.readLong();
                // skip monotonic size field
                p.readLong();

@@ -996,6 +1013,8 @@ public class BatteryStatsHistory {
            }
            // skip monotonic time field.
            out.readLong();
            // skip monotonic end time field
            out.readLong();
            // skip monotonic size field
            out.readLong();
            return true;
@@ -1024,6 +1043,7 @@ public class BatteryStatsHistory {
        p.setDataPosition(0);
        p.readInt();        // Skip the version field
        long monotonicTime = p.readLong();
        p.readLong();       // Skip monotonic end time field
        p.readLong();       // Skip monotonic size field
        p.setDataPosition(pos);
        return monotonicTime;
@@ -1086,7 +1106,10 @@ public class BatteryStatsHistory {
    public void writeToParcel(Parcel out) {
        synchronized (this) {
            writeHistoryBuffer(out);
            writeToParcel(out, false /* useBlobs */);
            /* useBlobs */
            if (mHistoryDir != null) {
                mHistoryDir.writeToParcel(out, false /* useBlobs */, 0);
            }
        }
    }

@@ -1096,16 +1119,13 @@ public class BatteryStatsHistory {
     *
     * @param out the output parcel
     */
    public void writeToBatteryUsageStatsParcel(Parcel out) {
    public void writeToBatteryUsageStatsParcel(Parcel out, long preferredHistoryDurationMs) {
        synchronized (this) {
            out.writeBlob(mHistoryBuffer.marshall());
            writeToParcel(out, true /* useBlobs */);
        }
    }

    private void writeToParcel(Parcel out, boolean useBlobs) {
            if (mHistoryDir != null) {
            mHistoryDir.writeToParcel(out, useBlobs);
                mHistoryDir.writeToParcel(out, true /* useBlobs */,
                        mHistoryMonotonicEndTime - preferredHistoryDurationMs);
            }
        }
    }

@@ -1166,8 +1186,7 @@ public class BatteryStatsHistory {
    private void readFromParcel(Parcel in, boolean useBlobs) {
        final long start = SystemClock.uptimeMillis();
        mHistoryParcels = new ArrayList<>();
        final int count = in.readInt();
        for (int i = 0; i < count; i++) {
        while (in.readBoolean()) {
            byte[] temp = useBlobs ? in.readBlob() : in.createByteArray();
            if (temp == null || temp.length == 0) {
                continue;
@@ -2081,6 +2100,8 @@ public class BatteryStatsHistory {
     */
    @GuardedBy("this")
    private void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
        mHistoryMonotonicEndTime = cur.time;

        if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
            dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
            cur.writeToParcel(dest, 0);
@@ -2396,6 +2417,7 @@ public class BatteryStatsHistory {
            }

            mHistoryBufferStartTime = in.readLong();
            mHistoryMonotonicEndTime = in.readLong();
            mMonotonicHistorySize = in.readLong();

            mHistoryBuffer.setDataSize(0);
@@ -2424,6 +2446,7 @@ public class BatteryStatsHistory {
    private void writeHistoryBuffer(Parcel out) {
        out.writeInt(BatteryStatsHistory.VERSION);
        out.writeLong(mHistoryBufferStartTime);
        out.writeLong(mHistoryMonotonicEndTime);
        out.writeLong(mMonotonicHistorySize);
        out.writeInt(mHistoryBuffer.dataSize());
        if (DEBUG) {
+6 −2
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.internal.os.CpuScalingPolicies;
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
import com.android.internal.util.ArrayUtils;
import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.BatteryStatsImpl.BatteryStatsSession;

import java.io.PrintWriter;
@@ -351,7 +352,7 @@ public class BatteryUsageStatsProvider {
        accumulatedStats.endMonotonicTime = endMonotonicTime;

        accumulatedStats.builder.setStatsEndTimestamp(endWallClockTime);
        accumulatedStats.builder.setStatsDuration(endWallClockTime - startMonotonicTime);
        accumulatedStats.builder.setStatsDuration(endMonotonicTime - startMonotonicTime);

        mPowerAttributor.estimatePowerConsumption(accumulatedStats.builder, session.getHistory(),
                startMonotonicTime, endMonotonicTime);
@@ -403,7 +404,10 @@ public class BatteryUsageStatsProvider {
        }
        if ((query.getFlags()
                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
            batteryUsageStatsBuilder.setBatteryHistory(session.getHistory().copy());
            batteryUsageStatsBuilder.setBatteryHistory(session.getHistory().copy(),
                    Flags.extendedBatteryHistoryContinuousCollectionEnabled()
                            ? query.getPreferredHistoryDurationMs()
                            : Long.MAX_VALUE);
        }

        mPowerAttributor.estimatePowerConsumption(batteryUsageStatsBuilder, session.getHistory(),
+66 −1
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ import android.os.Handler;
import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseLongArray;

@@ -49,6 +51,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.processor.MultiStatePowerAttributor;

import org.junit.Before;
@@ -59,6 +62,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -68,11 +72,14 @@ public class BatteryUsageStatsProviderTest {
            .setProvideMainThread(true)
            .build();

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

    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
    private static final long MINUTE_IN_MS = 60 * 1000;
    private static final double PRECISION = 0.00001;

    @Rule(order = 1)
    @Rule(order = 2)
    public final BatteryUsageStatsRule mStatsRule =
            new BatteryUsageStatsRule(12345)
                    .createTempDirectory()
@@ -868,4 +875,62 @@ public class BatteryUsageStatsProviderTest {

        stats.close();
    }

    @Test
    @EnableFlags(Flags.FLAG_EXTENDED_BATTERY_HISTORY_CONTINUOUS_COLLECTION_ENABLED)
    public void testIncludeSubsetOfHistory() throws IOException {
        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
        batteryStats.getHistory().setMaxHistoryBufferSize(100);
        synchronized (batteryStats) {
            batteryStats.setRecordAllHistoryLocked(true);
        }
        batteryStats.forceRecordAllHistory();
        batteryStats.setNoAutoReset(true);

        long lastIncludedEventTimestamp = 0;
        String tag = "work work work work work work work work work work work work work work work";
        for (int i = 1; i < 50; i++) {
            mStatsRule.advanceTime(TimeUnit.MINUTES.toMillis(9));
            synchronized (batteryStats) {
                batteryStats.noteJobStartLocked(tag, 42);
            }
            mStatsRule.advanceTime(TimeUnit.MINUTES.toMillis(1));
            synchronized (batteryStats) {
                batteryStats.noteJobFinishLocked(tag, 42, 0);
            }
            lastIncludedEventTimestamp = mMonotonicClock.monotonicTime();
        }

        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext,
                mock(PowerAttributor.class), mStatsRule.getPowerProfile(),
                mStatsRule.getCpuScalingPolicies(), mock(PowerStatsStore.class), 0, mMockClock,
                mMonotonicClock);

        BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
                .includeBatteryHistory()
                .setPreferredHistoryDurationMs(TimeUnit.MINUTES.toMillis(20))
                .build();
        final BatteryUsageStats stats = provider.getBatteryUsageStats(batteryStats, query);
        Parcel parcel = Parcel.obtain();
        stats.writeToParcel(parcel, 0);
        stats.close();

        parcel.setDataPosition(0);
        BatteryUsageStats actual = BatteryUsageStats.CREATOR.createFromParcel(parcel);

        long firstIncludedEventTimestamp = 0;
        try (BatteryStatsHistoryIterator it = actual.iterateBatteryStatsHistory()) {
            BatteryStats.HistoryItem item;
            while ((item = it.next()) != null) {
                if (item.eventCode == BatteryStats.HistoryItem.EVENT_JOB_START) {
                    firstIncludedEventTimestamp = item.time;
                    break;
                }
            }
        }
        actual.close();

        assertThat(firstIncludedEventTimestamp)
                .isAtLeast(lastIncludedEventTimestamp - TimeUnit.MINUTES.toMillis(30));
    }
}