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

Commit 36e0ae27 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Add BatteryUsageStats.add(BatteryUsageStats)

Bug: 187223764
Test: atest FrameworksCoreTests:com.android.internal.os.BatteryUsageStatsTest
Change-Id: I1e5060d726fd0f4634fd658483e80a9ab02e24fb
Merged-In: I1e5060d726fd0f4634fd658483e80a9ab02e24fb
(cherry picked from commit 63d9aecd)
parent 9da336b4
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -90,6 +90,14 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
            return this;
        }

        /**
         * Adds power and usage duration from the supplied AggregateBatteryConsumer.
         */
        public void add(AggregateBatteryConsumer aggregateBatteryConsumer) {
            mConsumedPowerMah += aggregateBatteryConsumer.mConsumedPowerMah;
            mPowerComponentsBuilder.addPowerAndDuration(aggregateBatteryConsumer.mPowerComponents);
        }

        /**
         * Creates a read-only object out of the Builder values.
         */
+80 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@@ -96,11 +97,7 @@ public final class BatteryUsageStats implements Parcelable {
    private BatteryUsageStats(@NonNull Builder builder) {
        mStatsStartTimestampMs = builder.mStatsStartTimestampMs;
        mStatsEndTimestampMs = builder.mStatsEndTimestampMs;
        if (builder.mStatsDurationMs != -1) {
            mStatsDurationMs = builder.mStatsDurationMs;
        } else {
            mStatsDurationMs = mStatsEndTimestampMs - mStatsStartTimestampMs;
        }
        mStatsDurationMs = builder.getStatsDuration();
        mBatteryCapacityMah = builder.mBatteryCapacityMah;
        mDischargePercentage = builder.mDischargePercentage;
        mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
@@ -658,6 +655,14 @@ public final class BatteryUsageStats implements Parcelable {
            return this;
        }

        private long getStatsDuration() {
            if (mStatsDurationMs != -1) {
                return mStatsDurationMs;
            } else {
                return mStatsEndTimestampMs - mStatsStartTimestampMs;
            }
        }

        /**
         * Sets the battery discharge amount since BatteryStats reset as percentage of the full
         * charge.
@@ -737,6 +742,22 @@ public final class BatteryUsageStats implements Parcelable {
            return builder;
        }

        /**
         * Creates or returns a UidBatteryConsumer, which represents battery attribution
         * data for an individual UID. This version of the method is not suitable for use
         * with PowerCalculators.
         */
        @NonNull
        public UidBatteryConsumer.Builder getOrCreateUidBatteryConsumerBuilder(int uid) {
            UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
            if (builder == null) {
                builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames,
                        mIncludePowerModels, uid);
                mUidBatteryConsumerBuilders.put(uid, builder);
            }
            return builder;
        }

        /**
         * Creates or returns a UserBatteryConsumer, which represents battery attribution
         * data for an individual {@link UserHandle}.
@@ -756,5 +777,59 @@ public final class BatteryUsageStats implements Parcelable {
        public SparseArray<UidBatteryConsumer.Builder> getUidBatteryConsumerBuilders() {
            return mUidBatteryConsumerBuilders;
        }

        /**
         * Adds battery usage stats from another snapshots. The two snapshots are assumed to be
         * non-overlapping, meaning that the power consumption estimates and session durations
         * can be simply summed across the two snapshots.  This remains true even if the timestamps
         * seem to indicate that the sessions are in fact overlapping: timestamps may be off as a
         * result of realtime clock adjustments by the user or the system.
         */
        @NonNull
        public Builder add(BatteryUsageStats stats) {
            if (!Arrays.equals(mCustomPowerComponentNames, stats.mCustomPowerComponentNames)) {
                throw new IllegalArgumentException(
                        "BatteryUsageStats have different custom power components");
            }

            if (mUserBatteryConsumerBuilders.size() != 0
                    || !stats.getUserBatteryConsumers().isEmpty()) {
                throw new UnsupportedOperationException(
                        "Combining UserBatteryConsumers is not supported");
            }

            mDischargedPowerLowerBoundMah += stats.mDischargedPowerLowerBound;
            mDischargedPowerUpperBoundMah += stats.mDischargedPowerUpperBound;
            mDischargePercentage += stats.mDischargePercentage;

            mStatsDurationMs = getStatsDuration() + stats.getStatsDuration();

            if (mStatsStartTimestampMs == 0
                    || stats.mStatsStartTimestampMs < mStatsStartTimestampMs) {
                mStatsStartTimestampMs = stats.mStatsStartTimestampMs;
            }

            final boolean addingLaterSnapshot = stats.mStatsEndTimestampMs > mStatsEndTimestampMs;
            if (addingLaterSnapshot) {
                mStatsEndTimestampMs = stats.mStatsEndTimestampMs;
            }

            for (int scope = 0; scope < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; scope++) {
                getAggregateBatteryConsumerBuilder(scope)
                        .add(stats.mAggregateBatteryConsumers[scope]);
            }

            for (UidBatteryConsumer consumer : stats.getUidBatteryConsumers()) {
                getOrCreateUidBatteryConsumerBuilder(consumer.getUid()).add(consumer);
            }

            if (addingLaterSnapshot) {
                mBatteryCapacityMah = stats.mBatteryCapacityMah;
                mBatteryTimeRemainingMs = stats.mBatteryTimeRemainingMs;
                mChargeTimeRemainingMs = stats.mChargeTimeRemainingMs;
            }

            return this;
        }
    }
}
+56 −5
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.os.PowerCalculator;

import java.io.PrintWriter;
import java.util.Arrays;

/**
 * Contains details of battery attribution data broken down to individual power drain types
@@ -36,9 +37,12 @@ class PowerComponents {
            - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;

    private final double mConsumedPowerMah;
    @NonNull
    private final double[] mPowerComponentsMah;
    @NonNull
    private final long[] mUsageDurationsMs;
    private final int mCustomPowerComponentCount;
    @Nullable
    private final byte[] mPowerModels;
    // Not written to Parcel and must be explicitly restored during the parent object's unparceling
    private String[] mCustomPowerComponentNames;
@@ -49,7 +53,7 @@ class PowerComponents {
        mPowerComponentsMah = builder.mPowerComponentsMah;
        mUsageDurationsMs = builder.mUsageDurationsMs;
        mConsumedPowerMah = builder.getTotalPower();
        mPowerModels = builder.mPowerModels;
        mPowerModels = builder.getPowerModels();
    }

    PowerComponents(@NonNull Parcel source) {
@@ -146,9 +150,13 @@ class PowerComponents {
        }
    }

    public boolean hasPowerModels() {
        return mPowerModels != null;
    }

    @BatteryConsumer.PowerModel
    int getPowerModel(@BatteryConsumer.PowerComponent int component) {
        if (mPowerModels == null) {
        if (!hasPowerModels()) {
            throw new IllegalStateException(
                    "Power model IDs were not requested in the BatteryUsageStatsQuery");
        }
@@ -298,6 +306,8 @@ class PowerComponents {
     * Builder for PowerComponents.
     */
    static final class Builder {
        private static final byte POWER_MODEL_UNINITIALIZED = -1;

        private final double[] mPowerComponentsMah;
        private final String[] mCustomPowerComponentNames;
        private final long[] mUsageDurationsMs;
@@ -311,6 +321,7 @@ class PowerComponents {
            mUsageDurationsMs = new long[powerComponentCount];
            if (includePowerModels) {
                mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
                Arrays.fill(mPowerModels, POWER_MODEL_UNINITIALIZED);
            } else {
                mPowerModels = null;
            }
@@ -412,12 +423,39 @@ class PowerComponents {
            return this;
        }

        public void addPowerAndDuration(Builder other) {
        public void addPowerAndDuration(PowerComponents.Builder other) {
            addPowerAndDuration(other.mPowerComponentsMah, other.mUsageDurationsMs,
                    other.mPowerModels);
        }

        public void addPowerAndDuration(PowerComponents other) {
            addPowerAndDuration(other.mPowerComponentsMah, other.mUsageDurationsMs,
                    other.mPowerModels);
        }

        private void addPowerAndDuration(double[] powerComponentsMah,
                long[] usageDurationsMs, byte[] powerModels) {
            if (mPowerComponentsMah.length != powerComponentsMah.length) {
                throw new IllegalArgumentException(
                        "Number of power components does not match: " + powerComponentsMah.length
                                + ", expected: " + mPowerComponentsMah.length);
            }

            for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) {
                mPowerComponentsMah[i] += other.mPowerComponentsMah[i];
                mPowerComponentsMah[i] += powerComponentsMah[i];
            }
            for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) {
                mUsageDurationsMs[i] += other.mUsageDurationsMs[i];
                mUsageDurationsMs[i] += usageDurationsMs[i];
            }
            if (mPowerModels != null && powerModels != null) {
                for (int i = mPowerModels.length - 1; i >= 0; i--) {
                    if (mPowerModels[i] == POWER_MODEL_UNINITIALIZED) {
                        mPowerModels[i] = powerModels[i];
                    } else if (mPowerModels[i] != powerModels[i]
                            && powerModels[i] != POWER_MODEL_UNINITIALIZED) {
                        mPowerModels[i] = BatteryConsumer.POWER_MODEL_UNDEFINED;
                    }
                }
            }
        }

@@ -433,6 +471,19 @@ class PowerComponents {
            return totalPowerMah;
        }

        private byte[] getPowerModels() {
            if (mPowerModels == null) {
                return null;
            }

            byte[] powerModels = new byte[mPowerModels.length];
            for (int i = mPowerModels.length - 1; i >= 0; i--) {
                powerModels[i] = mPowerModels[i] != POWER_MODEL_UNINITIALIZED ? mPowerModels[i]
                        : BatteryConsumer.POWER_MODEL_UNDEFINED;
            }
            return powerModels;
        }

        /**
         * Creates a read-only object out of the Builder values.
         */
+42 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.TextUtils;

import com.android.internal.os.PowerCalculator;

@@ -147,9 +148,10 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
     * Builder for UidBatteryConsumer.
     */
    public static final class Builder extends BaseBuilder<Builder> {
        private static final String PACKAGE_NAME_UNINITIALIZED = "";
        private final BatteryStats.Uid mBatteryStatsUid;
        private final int mUid;
        private String mPackageWithHighestDrain;
        private String mPackageWithHighestDrain = PACKAGE_NAME_UNINITIALIZED;
        public long mTimeInForegroundMs;
        public long mTimeInBackgroundMs;
        private boolean mExcludeFromBatteryUsageStats;
@@ -161,8 +163,19 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
            mUid = batteryStatsUid.getUid();
        }

        public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
                int uid) {
            super(customPowerComponentNames, includePowerModels);
            mBatteryStatsUid = null;
            mUid = uid;
        }

        @NonNull
        public BatteryStats.Uid getBatteryStatsUid() {
            if (mBatteryStatsUid == null) {
                throw new IllegalStateException(
                        "UidBatteryConsumer.Builder was initialized without a BatteryStats.Uid");
            }
            return mBatteryStatsUid;
        }

@@ -176,7 +189,7 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
         */
        @NonNull
        public Builder setPackageWithHighestDrain(@Nullable String packageName) {
            mPackageWithHighestDrain = packageName;
            mPackageWithHighestDrain = TextUtils.nullIfEmpty(packageName);
            return this;
        }

@@ -207,6 +220,30 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
            return this;
        }

        /**
         * Adds power and usage duration from the supplied UidBatteryConsumer.
         */
        public Builder add(UidBatteryConsumer consumer) {
            mPowerComponentsBuilder.addPowerAndDuration(consumer.mPowerComponents);
            mTimeInBackgroundMs += consumer.mTimeInBackgroundMs;
            mTimeInForegroundMs += consumer.mTimeInForegroundMs;

            if (mPackageWithHighestDrain == PACKAGE_NAME_UNINITIALIZED) {
                mPackageWithHighestDrain = consumer.mPackageWithHighestDrain;
            } else if (!TextUtils.equals(mPackageWithHighestDrain,
                    consumer.mPackageWithHighestDrain)) {
                // Consider combining two UidBatteryConsumers with this distribution
                // of power drain between packages:
                // (package1=100, package2=10) and (package1=100, package2=101).
                // Since we don't know the actual power distribution between packages at this
                // point, we have no way to correctly declare package1 as the winner.
                // The naive logic of picking the consumer with the higher total consumed
                // power would produce an incorrect result.
                mPackageWithHighestDrain = null;
            }
            return this;
        }

        /**
         * Returns true if this UidBatteryConsumer must be excluded from the
         * BatteryUsageStats.
@@ -220,6 +257,9 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
         */
        @NonNull
        public UidBatteryConsumer build() {
            if (mPackageWithHighestDrain == PACKAGE_NAME_UNINITIALIZED) {
                mPackageWithHighestDrain = null;
            }
            return new UidBatteryConsumer(this);
        }
    }
+251 −117

File changed.

Preview size limit exceeded, changes collapsed.