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

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

Merge "Add battery history to BatteryStatsUsage" into sc-dev

parents c3459a6e 20720fa1
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import android.annotation.NonNull;
import android.util.Range;
import android.util.SparseArray;

import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;

import java.util.ArrayList;
import java.util.List;

@@ -37,12 +40,16 @@ public final class BatteryUsageStats implements Parcelable {
    private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
    private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
    private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
    private final Parcel mHistoryBuffer;
    private final List<BatteryStats.HistoryTag> mHistoryTagPool;

    private BatteryUsageStats(@NonNull Builder builder) {
        mStatsStartRealtimeMs = builder.mStatsStartRealtimeMs;
        mDischargePercentage = builder.mDischargePercentage;
        mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
        mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
        mHistoryBuffer = builder.mHistoryBuffer;
        mHistoryTagPool = builder.mHistoryTagPool;

        double totalPower = 0;

@@ -125,6 +132,19 @@ public final class BatteryUsageStats implements Parcelable {
        return mUserBatteryConsumers;
    }

    /**
     * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
     */
    @NonNull
    public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
        if (mHistoryBuffer == null) {
            throw new IllegalStateException(
                    "Battery history was not requested in the BatteryUsageStatsQuery");
        }
        return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer),
                mHistoryTagPool);
    }

    @Override
    public int describeContents() {
        return 0;
@@ -142,6 +162,29 @@ public final class BatteryUsageStats implements Parcelable {
        source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
        mUserBatteryConsumers = new ArrayList<>();
        source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
        if (source.readBoolean()) {
            mHistoryBuffer = Parcel.obtain();
            mHistoryBuffer.setDataSize(0);
            mHistoryBuffer.setDataPosition(0);

            int historyBufferSize = source.readInt();
            int curPos = source.dataPosition();
            mHistoryBuffer.appendFrom(source, curPos, historyBufferSize);
            source.setDataPosition(curPos + historyBufferSize);

            int historyTagCount = source.readInt();
            mHistoryTagPool = new ArrayList<>(historyTagCount);
            for (int i = 0; i < historyTagCount; i++) {
                BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag();
                tag.string = source.readString();
                tag.uid = source.readInt();
                tag.poolIdx = source.readInt();
                mHistoryTagPool.add(tag);
            }
        } else {
            mHistoryBuffer = null;
            mHistoryTagPool = null;
        }
    }

    @Override
@@ -154,6 +197,23 @@ public final class BatteryUsageStats implements Parcelable {
        dest.writeParcelableList(mUidBatteryConsumers, flags);
        dest.writeParcelableList(mSystemBatteryConsumers, flags);
        dest.writeParcelableList(mUserBatteryConsumers, flags);
        if (mHistoryBuffer != null) {
            dest.writeBoolean(true);

            final int historyBufferSize = mHistoryBuffer.dataSize();
            dest.writeInt(historyBufferSize);
            dest.appendFrom(mHistoryBuffer, 0, historyBufferSize);

            dest.writeInt(mHistoryTagPool.size());
            for (int i = mHistoryTagPool.size() - 1; i >= 0; i--) {
                final BatteryStats.HistoryTag tag = mHistoryTagPool.get(i);
                dest.writeString(tag.string);
                dest.writeInt(tag.uid);
                dest.writeInt(tag.poolIdx);
            }
        } else {
            dest.writeBoolean(false);
        }
    }

    @NonNull
@@ -183,6 +243,8 @@ public final class BatteryUsageStats implements Parcelable {
                new SparseArray<>();
        private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
                new SparseArray<>();
        private Parcel mHistoryBuffer;
        private List<BatteryStats.HistoryTag> mHistoryTagPool;

        public Builder(int customPowerComponentCount, int customTimeComponentCount) {
            mCustomPowerComponentCount = customPowerComponentCount;
@@ -226,6 +288,17 @@ public final class BatteryUsageStats implements Parcelable {
            return this;
        }

        /**
         * Sets the parceled recent history.
         */
        @NonNull
        public Builder setBatteryHistory(Parcel historyBuffer,
                List<BatteryStats.HistoryTag> historyTagPool) {
            mHistoryBuffer = historyBuffer;
            mHistoryTagPool = historyTagPool;
            return this;
        }

        /**
         * Creates or returns a exiting UidBatteryConsumer, which represents battery attribution
         * data for an individual UID.
+10 −3
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
     */
    @IntDef(flag = true, prefix = { "FLAG_BATTERY_USAGE_STATS_" }, value = {
            FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL,
            FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface BatteryUsageStatsFlags {}
@@ -53,6 +54,12 @@ public final class BatteryUsageStatsQuery implements Parcelable {
     */
    public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 1;

    /**
     * Indicates that battery history should be included in the BatteryUsageStats.
     * @hide
     */
    public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2;

    private final int mFlags;
    @NonNull
    private final int[] mUserIds;
@@ -146,10 +153,10 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        }

        /**
         * Sets flags to modify the behavior of {@link BatteryStatsManager#getBatteryUsageStats}.
         * Requests that battery history be included in the BatteryUsageStats.
         */
        public Builder setFlags(@BatteryUsageStatsFlags int flags) {
            mFlags = flags;
        public Builder includeBatteryHistory() {
            mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY;
            return this;
        }

+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ public class BatteryStatsHistoryIterator {
    private final String[] mReadHistoryStrings;
    private final int[] mReadHistoryUids;

    BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
    public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
            @NonNull List<BatteryStats.HistoryTag> historyTagPool) {
        mBatteryStatsHistory = history;

+15 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Uses accumulated battery stats data and PowerCalculators to produce power
@@ -152,6 +153,20 @@ public class BatteryUsageStatsProvider {
                    query);
        }

        if ((query.getFlags()
                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
            ArrayList<BatteryStats.HistoryTag> tags = new ArrayList<>(
                    mStats.mHistoryTagPool.size());
            for (Map.Entry<BatteryStats.HistoryTag, Integer> entry :
                    mStats.mHistoryTagPool.entrySet()) {
                final BatteryStats.HistoryTag tag = entry.getKey();
                tag.poolIdx = entry.getValue();
                tags.add(tag);
            }

            batteryUsageStatsBuilder.setBatteryHistory(mStats.mHistoryBuffer, tags);
        }

        return batteryUsageStatsBuilder.build();
    }

+85 −0
Original line number Diff line number Diff line
@@ -20,8 +20,11 @@ import static com.google.common.truth.Truth.assertThat;

import android.app.ActivityManager;
import android.content.Context;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;

@@ -73,4 +76,86 @@ public class BatteryUsageStatsProviderTest {
        assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
                .isEqualTo(10 * MINUTE_IN_MS);
    }

    @Test
    public void testWriteAndReadHistory() {
        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
        batteryStats.setRecordAllHistoryLocked(true);
        batteryStats.forceRecordAllHistory();

        batteryStats.setNoAutoReset(true);

        batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
                /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
                1_000_000, 1_000_000);

        batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
        batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);

        Context context = InstrumentationRegistry.getContext();
        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);

        final BatteryUsageStats batteryUsageStats =
                provider.getBatteryUsageStats(
                        new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());

        Parcel in = Parcel.obtain();
        batteryUsageStats.writeToParcel(in, 0);
        final byte[] bytes = in.marshall();

        Parcel out = Parcel.obtain();
        out.unmarshall(bytes, 0, bytes.length);
        out.setDataPosition(0);

        BatteryUsageStats unparceled = BatteryUsageStats.CREATOR.createFromParcel(out);

        final BatteryStatsHistoryIterator iterator =
                unparceled.iterateBatteryStatsHistory();
        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();

        assertThat(iterator.next(item)).isTrue();
        assertHistoryItem(item,
                BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE,
                null, 0, 3_600_000, 90, 1_000_000);

        assertThat(iterator.next(item)).isTrue();
        assertHistoryItem(item,
                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
                null, 0, 3_600_000, 90, 1_000_000);

        assertThat(iterator.next(item)).isTrue();
        assertHistoryItem(item,
                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
                null, 0, 3_600_000, 90, 2_000_000);

        assertThat(iterator.next(item)).isTrue();
        assertHistoryItem(item,
                BatteryStats.HistoryItem.CMD_UPDATE,
                BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START,
                "foo", APP_UID, 3_600_000, 90, 3_000_000);

        assertThat(iterator.next(item)).isTrue();
        assertHistoryItem(item,
                BatteryStats.HistoryItem.CMD_UPDATE,
                BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH,
                "foo", APP_UID, 3_600_000, 90, 3_001_000);

        assertThat(iterator.next(item)).isFalse();
    }

    private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
            String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) {
        assertThat(item.cmd).isEqualTo(command);
        assertThat(item.eventCode).isEqualTo(eventCode);
        if (tag == null) {
            assertThat(item.eventTag).isNull();
        } else {
            assertThat(item.eventTag.string).isEqualTo(tag);
            assertThat(item.eventTag.uid).isEqualTo(uid);
        }
        assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah);
        assertThat(item.batteryLevel).isEqualTo(batteryLevel);

        assertThat(item.time).isEqualTo(elapsedTimeMs);
    }
}