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

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

Merge "Add UID time-in-state to UidBatteryConsumer" into sc-dev

parents 47c37c62 f441fbf7
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -16,9 +16,13 @@

package android.os;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Contains power consumption data attributed to a specific UID.
 *
@@ -26,9 +30,37 @@ import android.annotation.Nullable;
 */
public final class UidBatteryConsumer extends BatteryConsumer implements Parcelable {

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({
            STATE_FOREGROUND,
            STATE_BACKGROUND
    })
    public @interface State {
    }

    /**
     * The state of an application when it is either running a foreground (top) activity
     * or a foreground service.
     */
    public static final int STATE_FOREGROUND = 0;

    /**
     * The state of an application when it is running in the background, including the following
     * states:
     *
     * {@link android.app.ActivityManager#PROCESS_STATE_IMPORTANT_BACKGROUND},
     * {@link android.app.ActivityManager#PROCESS_STATE_TRANSIENT_BACKGROUND},
     * {@link android.app.ActivityManager#PROCESS_STATE_BACKUP},
     * {@link android.app.ActivityManager#PROCESS_STATE_SERVICE},
     * {@link android.app.ActivityManager#PROCESS_STATE_RECEIVER}.
     */
    public static final int STATE_BACKGROUND = 1;

    private final int mUid;
    @Nullable
    private final String mPackageWithHighestDrain;
    private final long mTimeInForegroundMs;
    private final long mTimeInBackgroundMs;

    public int getUid() {
        return mUid;
@@ -39,16 +71,33 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
        return mPackageWithHighestDrain;
    }

    /**
     * Returns the amount of time in milliseconds this UID spent in the specified state.
     */
    public long getTimeInStateMs(@State int state) {
        switch (state) {
            case STATE_BACKGROUND:
                return mTimeInBackgroundMs;
            case STATE_FOREGROUND:
                return mTimeInForegroundMs;
        }
        return 0;
    }

    private UidBatteryConsumer(@NonNull Builder builder) {
        super(builder.mPowerComponentsBuilder.build());
        mUid = builder.mUid;
        mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
        mTimeInForegroundMs = builder.mTimeInForegroundMs;
        mTimeInBackgroundMs = builder.mTimeInBackgroundMs;
    }

    private UidBatteryConsumer(@NonNull Parcel source) {
        super(new PowerComponents(source));
        mUid = source.readInt();
        mPackageWithHighestDrain = source.readString();
        mTimeInForegroundMs = source.readLong();
        mTimeInBackgroundMs = source.readLong();
    }

    /**
@@ -59,6 +108,8 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
        super.writeToParcel(dest, flags);
        dest.writeInt(mUid);
        dest.writeString(mPackageWithHighestDrain);
        dest.writeLong(mTimeInForegroundMs);
        dest.writeLong(mTimeInBackgroundMs);
    }

    @NonNull
@@ -84,6 +135,8 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
        private final BatteryStats.Uid mBatteryStatsUid;
        private final int mUid;
        private String mPackageWithHighestDrain;
        public long mTimeInForegroundMs;
        public long mTimeInBackgroundMs;
        private boolean mExcludeFromBatteryUsageStats;

        public Builder(int customPowerComponentCount, int customTimeComponentCount,
@@ -112,6 +165,25 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
            return this;
        }

        /**
         * Sets the duration, in milliseconds, that this UID was active in a particular state,
         * such as foreground or background.
         */
        @NonNull
        public Builder setTimeInStateMs(@State int state, long timeInStateMs) {
            switch (state) {
                case STATE_FOREGROUND:
                    mTimeInForegroundMs = timeInStateMs;
                    break;
                case STATE_BACKGROUND:
                    mTimeInBackgroundMs = timeInStateMs;
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported state: " + state);
            }
            return this;
        }

        /**
         * Marks the UidBatteryConsumer for exclusion from the result set.
         */
+51 −9
Original line number Diff line number Diff line
@@ -22,10 +22,12 @@ import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;

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

@@ -85,7 +87,7 @@ public class BatteryUsageStatsProvider {
    }

    /**
     * Returns a snapshot of battery attribution data.
     * Returns snapshots of battery attribution data, one per supplied query.
     */
    public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {

@@ -112,7 +114,14 @@ public class BatteryUsageStatsProvider {
        return results;
    }

    private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
    /**
     * Returns a snapshot of battery attribution data.
     */
    @VisibleForTesting
    public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
        final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000;
        final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000;

        final long[] customMeasuredEnergiesMicroJoules =
                mStats.getCustomMeasuredEnergiesMicroJoules();
        final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null
@@ -128,12 +137,14 @@ public class BatteryUsageStatsProvider {

        SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
        for (int i = uidStats.size() - 1; i >= 0; i--) {
            batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
            final BatteryStats.Uid uid = uidStats.valueAt(i);
            batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid)
                    .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND,
                            getProcessBackgroundTimeMs(uid, realtimeUs))
                    .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND,
                            getProcessForegroundTimeMs(uid, realtimeUs));
        }

        final long realtimeUs = SystemClock.elapsedRealtime() * 1000;
        final long uptimeUs = SystemClock.uptimeMillis() * 1000;

        final List<PowerCalculator> powerCalculators = getPowerCalculators();
        for (int i = 0, count = powerCalculators.size(); i < count; i++) {
            PowerCalculator powerCalculator = powerCalculators.get(i);
@@ -143,4 +154,35 @@ public class BatteryUsageStatsProvider {

        return batteryUsageStatsBuilder.build();
    }

    private long getProcessForegroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
        final long topStateDurationMs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
                realtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000;

        long foregroundActivityDurationMs = 0;
        final BatteryStats.Timer foregroundActivityTimer = uid.getForegroundActivityTimer();
        if (foregroundActivityTimer != null) {
            foregroundActivityDurationMs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
        }

        // Use the min value of STATE_TOP time and foreground activity time, since both of these
        // times are imprecise
        final long foregroundDurationMs = Math.min(topStateDurationMs,
                foregroundActivityDurationMs);

        long foregroundServiceDurationMs = 0;
        final BatteryStats.Timer foregroundServiceTimer = uid.getForegroundServiceTimer();
        if (foregroundServiceTimer != null) {
            foregroundServiceDurationMs = foregroundServiceTimer.getTotalTimeLocked(realtimeUs,
                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
        }

        return foregroundDurationMs + foregroundServiceDurationMs;
    }

    private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
        return uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND, realtimeUs,
                BatteryStats.STATS_SINCE_CHARGED) / 1000;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import org.junit.runners.Suite;
        BatteryStatsTimeBaseTest.class,
        BatteryStatsTimerTest.class,
        BatteryStatsUidTest.class,
        BatteryUsageStatsProviderTest.class,
        BatteryUsageStatsTest.class,
        BatteryStatsUserLifecycleTests.class,
        BluetoothPowerCalculatorTest.class,
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.os;

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

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

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.List;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class BatteryUsageStatsProviderTest {
    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
    private static final long MINUTE_IN_MS = 60 * 1000;

    @Rule
    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();

    @Test
    public void test_getBatteryUsageStats() {
        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();

        batteryStats.noteActivityResumedLocked(APP_UID,
                10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_TOP,
                10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
        batteryStats.noteActivityPausedLocked(APP_UID,
                30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_SERVICE,
                30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS);

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

        final BatteryUsageStats batteryUsageStats =
                provider.getBatteryUsageStats(BatteryUsageStatsQuery.DEFAULT);

        final List<UidBatteryConsumer> uidBatteryConsumers =
                batteryUsageStats.getUidBatteryConsumers();
        final UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(0);
        assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
                .isEqualTo(20 * MINUTE_IN_MS);
        assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
                .isEqualTo(10 * MINUTE_IN_MS);
    }
}
+34 −27
Original line number Diff line number Diff line
@@ -66,32 +66,35 @@ public class BatteryUsageStatsTest {
        final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
        final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);

        final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1);
        builder.setDischargePercentage(20);
        builder.setDischargedPowerRange(1000, 2000);

        final UidBatteryConsumer.Builder uidBatteryConsumerBuilder =
                builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
        uidBatteryConsumerBuilder.setPackageWithHighestDrain("foo");
        uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 300);
        uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400);
        uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500);
        uidBatteryConsumerBuilder.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, 600);
        uidBatteryConsumerBuilder.setUsageDurationMillis(
                BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700);
        uidBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
        final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1)
                .setDischargePercentage(20)
                .setDischargedPowerRange(1000, 2000);

        builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)
                .setPackageWithHighestDrain("foo")
                .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
                .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
                .setConsumedPower(
                        BatteryConsumer.POWER_COMPONENT_USAGE, 300)
                .setConsumedPower(
                        BatteryConsumer.POWER_COMPONENT_CPU, 400)
                .setConsumedPowerForCustomComponent(
                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500)
                .setUsageDurationMillis(
                        BatteryConsumer.TIME_COMPONENT_CPU, 600)
                .setUsageDurationMillis(
                        BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700)
                .setUsageDurationForCustomComponentMillis(
                        BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);

        final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
                builder.getOrCreateSystemBatteryConsumerBuilder(
                        SystemBatteryConsumer.DRAIN_TYPE_CAMERA);
        systemBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100);
        systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
        systemBatteryConsumerBuilder.setUsageDurationMillis(
                BatteryConsumer.TIME_COMPONENT_CPU, 10300);
        systemBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
        builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_CAMERA)
                .setConsumedPower(
                        BatteryConsumer.POWER_COMPONENT_CPU, 10100)
                .setConsumedPowerForCustomComponent(
                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
                .setUsageDurationMillis(
                        BatteryConsumer.TIME_COMPONENT_CPU, 10300)
                .setUsageDurationForCustomComponentMillis(
                        BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);

        return builder.build();
@@ -108,6 +111,10 @@ public class BatteryUsageStatsTest {
        for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
            if (uidBatteryConsumer.getUid() == 2000) {
                assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo");
                assertThat(uidBatteryConsumer.getTimeInStateMs(
                        UidBatteryConsumer.STATE_FOREGROUND)).isEqualTo(1000);
                assertThat(uidBatteryConsumer.getTimeInStateMs(
                        UidBatteryConsumer.STATE_BACKGROUND)).isEqualTo(2000);
                assertThat(uidBatteryConsumer.getConsumedPower(
                        BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
                assertThat(uidBatteryConsumer.getConsumedPower(