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

Commit c24fb816 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Add BatteryUsageStatsQuery parameters: time range

Bug: 187223764
Test: atest FrameworksCoreTests:BatteryUsageStatsProviderTest
Change-Id: If370360695a3f0327f07457abac1fd02164864e1
Merged-In: If370360695a3f0327f07457abac1fd02164864e1
(cherry picked from commit 6ea400b2)
parent f7e7d084
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -72,12 +72,16 @@ public final class BatteryUsageStatsQuery implements Parcelable {
    @NonNull
    private final int[] mUserIds;
    private final long mMaxStatsAgeMs;
    private long mFromTimestamp;
    private long mToTimestamp;

    private BatteryUsageStatsQuery(@NonNull Builder builder) {
        mFlags = builder.mFlags;
        mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
                : new int[]{UserHandle.USER_ALL};
        mMaxStatsAgeMs = builder.mMaxStatsAgeMs;
        mFromTimestamp = builder.mFromTimestamp;
        mToTimestamp = builder.mToTimestamp;
    }

    @BatteryUsageStatsFlags
@@ -112,11 +116,30 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        return mMaxStatsAgeMs;
    }

    /**
     * Returns the exclusive lower bound of the stored snapshot timestamps that should be included
     * in the aggregation.  Ignored if {@link #getToTimestamp()} is zero.
     */
    public long getFromTimestamp() {
        return mFromTimestamp;
    }

    /**
     * Returns the inclusive upper bound of the stored snapshot timestamps that should
     * be included in the aggregation.  The default is to include only the current stats
     * accumulated since the latest battery reset.
     */
    public long getToTimestamp() {
        return mToTimestamp;
    }

    private BatteryUsageStatsQuery(Parcel in) {
        mFlags = in.readInt();
        mUserIds = new int[in.readInt()];
        in.readIntArray(mUserIds);
        mMaxStatsAgeMs = in.readLong();
        mFromTimestamp = in.readLong();
        mToTimestamp = in.readLong();
    }

    @Override
@@ -125,6 +148,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        dest.writeInt(mUserIds.length);
        dest.writeIntArray(mUserIds);
        dest.writeLong(mMaxStatsAgeMs);
        dest.writeLong(mFromTimestamp);
        dest.writeLong(mToTimestamp);
    }

    @Override
@@ -153,6 +178,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
        private int mFlags;
        private IntArray mUserIds;
        private long mMaxStatsAgeMs = DEFAULT_MAX_STATS_AGE_MS;
        private long mFromTimestamp;
        private long mToTimestamp;

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

        /**
         * Requests to aggregate stored snapshots between the two supplied timestamps
         * @param fromTimestamp Exclusive starting timestamp, as per System.currentTimeMillis()
         * @param toTimestamp Inclusive ending timestamp, as per System.currentTimeMillis()
         */
        public Builder aggregateSnapshots(long fromTimestamp, long toTimestamp) {
            mFromTimestamp = fromTimestamp;
            mToTimestamp = toTimestamp;
            return this;
        }

        /**
         * Set the client's tolerance for stale battery stats. The data may be up to
         * this many milliseconds out-of-date.
+4 −0
Original line number Diff line number Diff line
@@ -10749,6 +10749,10 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    PowerProfile getPowerProfile() {
        return mPowerProfile;
    }
    /**
     * Starts tracking CPU time-in-state for threads of the system server process,
     * keeping a separate account of threads receiving incoming binder calls.
+39 −1
Original line number Diff line number Diff line
@@ -38,14 +38,24 @@ import java.util.Map;
public class BatteryUsageStatsProvider {
    private final Context mContext;
    private final BatteryStats mStats;
    private final BatteryUsageStatsStore mBatteryUsageStatsStore;
    private final PowerProfile mPowerProfile;
    private final Object mLock = new Object();
    private List<PowerCalculator> mPowerCalculators;

    public BatteryUsageStatsProvider(Context context, BatteryStats stats) {
        this(context, stats, null);
    }

    @VisibleForTesting
    public BatteryUsageStatsProvider(Context context, BatteryStats stats,
            BatteryUsageStatsStore batteryUsageStatsStore) {
        mContext = context;
        mStats = stats;
        mPowerProfile = new PowerProfile(mContext);
        mBatteryUsageStatsStore = batteryUsageStatsStore;
        mPowerProfile = stats instanceof BatteryStatsImpl
                ? ((BatteryStatsImpl) stats).getPowerProfile()
                : new PowerProfile(context);
    }

    private List<PowerCalculator> getPowerCalculators() {
@@ -126,6 +136,15 @@ public class BatteryUsageStatsProvider {

    private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
            long currentTimeMs) {
        if (query.getToTimestamp() == 0) {
            return getCurrentBatteryUsageStats(query, currentTimeMs);
        } else {
            return getAggregatedBatteryUsageStats(query);
        }
    }

    private BatteryUsageStats getCurrentBatteryUsageStats(BatteryUsageStatsQuery query,
            long currentTimeMs) {
        final long realtimeUs = elapsedRealtime() * 1000;
        final long uptimeUs = uptimeMillis() * 1000;

@@ -209,6 +228,25 @@ public class BatteryUsageStatsProvider {
                BatteryStats.STATS_SINCE_CHARGED) / 1000;
    }

    private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryUsageStatsQuery query) {
        final boolean includePowerModels = (query.getFlags()
                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;

        final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
                mStats.getCustomEnergyConsumerNames(), includePowerModels);
        final long[] timestamps = mBatteryUsageStatsStore.listBatteryUsageStatsTimestamps();
        for (long timestamp : timestamps) {
            if (timestamp > query.getFromTimestamp() && timestamp <= query.getToTimestamp()) {
                final BatteryUsageStats snapshot =
                        mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp);
                if (snapshot != null) {
                    builder.add(snapshot);
                }
            }
        }
        return builder.build();
    }

    private long elapsedRealtime() {
        if (mStats instanceof BatteryStatsImpl) {
            return ((BatteryStatsImpl) mStats).mClocks.elapsedRealtime();
+87 −1
Original line number Diff line number Diff line
@@ -20,10 +20,14 @@ import static com.google.common.truth.Truth.assertThat;

import android.app.ActivityManager;
import android.content.Context;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;
@@ -36,6 +40,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.List;

@SmallTest
@@ -45,7 +50,8 @@ public class BatteryUsageStatsProviderTest {
    private static final long MINUTE_IN_MS = 60 * 1000;

    @Rule
    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345);
    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(12345)
            .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);

    @Test
    public void test_getBatteryUsageStats() {
@@ -187,4 +193,84 @@ public class BatteryUsageStatsProviderTest {
        mStatsRule.setTime(11500, 0);
        assertThat(provider.shouldUpdateStats(queries, 10000)).isTrue();
    }

    @Test
    public void testAggregateBatteryStats() {
        Context context = InstrumentationRegistry.getContext();
        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
        mStatsRule.setCurrentTime(5 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();

        BatteryUsageStatsStore batteryUsageStatsStore = new BatteryUsageStatsStore(context,
                batteryStats, new File(context.getCacheDir(), "BatteryUsageStatsProviderTest"),
                new TestHandler(), Integer.MAX_VALUE);

        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context,
                batteryStats, batteryUsageStatsStore);

        batteryStats.noteFlashlightOnLocked(APP_UID,
                10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
        batteryStats.noteFlashlightOffLocked(APP_UID,
                20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(25 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();

        batteryStats.noteFlashlightOnLocked(APP_UID,
                30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
        batteryStats.noteFlashlightOffLocked(APP_UID,
                50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(55 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();

        // This section should be ignored because the timestamp is out or range
        batteryStats.noteFlashlightOnLocked(APP_UID,
                60 * MINUTE_IN_MS, 60 * MINUTE_IN_MS);
        batteryStats.noteFlashlightOffLocked(APP_UID,
                70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(75 * MINUTE_IN_MS);
        batteryStats.resetAllStatsCmdLocked();

        // This section should be ignored because it represents the current stats session
        batteryStats.noteFlashlightOnLocked(APP_UID,
                80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
        batteryStats.noteFlashlightOffLocked(APP_UID,
                90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS);
        mStatsRule.setCurrentTime(95 * MINUTE_IN_MS);

        // Include the first and the second snapshot, but not the third or current
        BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
                .aggregateSnapshots(20 * MINUTE_IN_MS, 60 * MINUTE_IN_MS)
                .build();
        final BatteryUsageStats stats = provider.getBatteryUsageStats(query);

        assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS);
        assertThat(stats.getStatsEndTimestamp()).isEqualTo(55 * MINUTE_IN_MS);
        assertThat(stats.getAggregateBatteryConsumer(
                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
                .isWithin(0.0001)
                .of(180.0);  // 360 mA * 0.5 hours
        assertThat(stats.getAggregateBatteryConsumer(
                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
                .isEqualTo((10 + 20) * MINUTE_IN_MS);
        final UidBatteryConsumer uidBatteryConsumer = stats.getUidBatteryConsumers().stream()
                .filter(uid -> uid.getUid() == APP_UID).findFirst().get();
        assertThat(uidBatteryConsumer
                .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
                .isWithin(0.1)
                .of(180.0);
    }

    private static class TestHandler extends Handler {
        TestHandler() {
            super(Looper.getMainLooper());
        }

        @Override
        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            msg.getCallback().run();
            return true;
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.internal.os;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;

import android.content.Context;
import android.os.BatteryManager;
import android.os.BatteryUsageStats;
@@ -56,6 +58,7 @@ public class BatteryUsageStatsStoreTest {
        mMockClocks.currentTime = 123;
        mBatteryStats = new MockBatteryStatsImpl(mMockClocks);
        mBatteryStats.setNoAutoReset(true);
        mBatteryStats.setPowerProfile(mock(PowerProfile.class));

        Context context = InstrumentationRegistry.getContext();