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

This commit is contained in:
Dmitri Plotnikov
2021-02-26 04:51:40 +00:00
committed by Android (Google) Code Review
5 changed files with 232 additions and 34 deletions

View File

@@ -16,9 +16,13 @@
package android.os; package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** /**
* Contains power consumption data attributed to a specific UID. * 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 { 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; private final int mUid;
@Nullable @Nullable
private final String mPackageWithHighestDrain; private final String mPackageWithHighestDrain;
private final long mTimeInForegroundMs;
private final long mTimeInBackgroundMs;
public int getUid() { public int getUid() {
return mUid; return mUid;
@@ -39,16 +71,33 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
return mPackageWithHighestDrain; 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) { private UidBatteryConsumer(@NonNull Builder builder) {
super(builder.mPowerComponentsBuilder.build()); super(builder.mPowerComponentsBuilder.build());
mUid = builder.mUid; mUid = builder.mUid;
mPackageWithHighestDrain = builder.mPackageWithHighestDrain; mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
mTimeInForegroundMs = builder.mTimeInForegroundMs;
mTimeInBackgroundMs = builder.mTimeInBackgroundMs;
} }
private UidBatteryConsumer(@NonNull Parcel source) { private UidBatteryConsumer(@NonNull Parcel source) {
super(new PowerComponents(source)); super(new PowerComponents(source));
mUid = source.readInt(); mUid = source.readInt();
mPackageWithHighestDrain = source.readString(); 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); super.writeToParcel(dest, flags);
dest.writeInt(mUid); dest.writeInt(mUid);
dest.writeString(mPackageWithHighestDrain); dest.writeString(mPackageWithHighestDrain);
dest.writeLong(mTimeInForegroundMs);
dest.writeLong(mTimeInBackgroundMs);
} }
@NonNull @NonNull
@@ -84,6 +135,8 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
private final BatteryStats.Uid mBatteryStatsUid; private final BatteryStats.Uid mBatteryStatsUid;
private final int mUid; private final int mUid;
private String mPackageWithHighestDrain; private String mPackageWithHighestDrain;
public long mTimeInForegroundMs;
public long mTimeInBackgroundMs;
private boolean mExcludeFromBatteryUsageStats; private boolean mExcludeFromBatteryUsageStats;
public Builder(int customPowerComponentCount, int customTimeComponentCount, public Builder(int customPowerComponentCount, int customTimeComponentCount,
@@ -112,6 +165,25 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
return this; 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. * Marks the UidBatteryConsumer for exclusion from the result set.
*/ */

View File

@@ -22,10 +22,12 @@ import android.os.BatteryStats;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery; import android.os.BatteryUsageStatsQuery;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock; import android.os.UidBatteryConsumer;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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) { public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {
@@ -112,12 +114,19 @@ public class BatteryUsageStatsProvider {
return results; 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 = final long[] customMeasuredEnergiesMicroJoules =
mStats.getCustomMeasuredEnergiesMicroJoules(); mStats.getCustomMeasuredEnergiesMicroJoules();
final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null
? customMeasuredEnergiesMicroJoules.length ? customMeasuredEnergiesMicroJoules.length
: 0; : 0;
// TODO(b/174186358): read extra time component number from configuration // TODO(b/174186358): read extra time component number from configuration
final int customTimeComponentCount = 0; final int customTimeComponentCount = 0;
@@ -128,12 +137,14 @@ public class BatteryUsageStatsProvider {
SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats(); SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
for (int i = uidStats.size() - 1; i >= 0; i--) { 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(); final List<PowerCalculator> powerCalculators = getPowerCalculators();
for (int i = 0, count = powerCalculators.size(); i < count; i++) { for (int i = 0, count = powerCalculators.size(); i < count; i++) {
PowerCalculator powerCalculator = powerCalculators.get(i); PowerCalculator powerCalculator = powerCalculators.get(i);
@@ -143,4 +154,35 @@ public class BatteryUsageStatsProvider {
return batteryUsageStatsBuilder.build(); 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;
}
} }

View File

@@ -40,6 +40,7 @@ import org.junit.runners.Suite;
BatteryStatsTimeBaseTest.class, BatteryStatsTimeBaseTest.class,
BatteryStatsTimerTest.class, BatteryStatsTimerTest.class,
BatteryStatsUidTest.class, BatteryStatsUidTest.class,
BatteryUsageStatsProviderTest.class,
BatteryUsageStatsTest.class, BatteryUsageStatsTest.class,
BatteryStatsUserLifecycleTests.class, BatteryStatsUserLifecycleTests.class,
BluetoothPowerCalculatorTest.class, BluetoothPowerCalculatorTest.class,

View File

@@ -0,0 +1,76 @@
/*
* 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);
}
}

View File

@@ -66,33 +66,36 @@ public class BatteryUsageStatsTest {
final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks); final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000); final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1); final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1)
builder.setDischargePercentage(20); .setDischargePercentage(20)
builder.setDischargedPowerRange(1000, 2000); .setDischargedPowerRange(1000, 2000);
final UidBatteryConsumer.Builder uidBatteryConsumerBuilder = builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid); .setPackageWithHighestDrain("foo")
uidBatteryConsumerBuilder.setPackageWithHighestDrain("foo"); .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 300); .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400); .setConsumedPower(
uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent( BatteryConsumer.POWER_COMPONENT_USAGE, 300)
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500); .setConsumedPower(
uidBatteryConsumerBuilder.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, 600); BatteryConsumer.POWER_COMPONENT_CPU, 400)
uidBatteryConsumerBuilder.setUsageDurationMillis( .setConsumedPowerForCustomComponent(
BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700); BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500)
uidBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis( .setUsageDurationMillis(
BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800); 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)
builder.getOrCreateSystemBatteryConsumerBuilder( .setConsumedPower(
SystemBatteryConsumer.DRAIN_TYPE_CAMERA); BatteryConsumer.POWER_COMPONENT_CPU, 10100)
systemBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100); .setConsumedPowerForCustomComponent(
systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200); .setUsageDurationMillis(
systemBatteryConsumerBuilder.setUsageDurationMillis( BatteryConsumer.TIME_COMPONENT_CPU, 10300)
BatteryConsumer.TIME_COMPONENT_CPU, 10300); .setUsageDurationForCustomComponentMillis(
systemBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis( BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
return builder.build(); return builder.build();
} }
@@ -108,6 +111,10 @@ public class BatteryUsageStatsTest {
for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) { for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
if (uidBatteryConsumer.getUid() == 2000) { if (uidBatteryConsumer.getUid() == 2000) {
assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo"); assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo");
assertThat(uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_FOREGROUND)).isEqualTo(1000);
assertThat(uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_BACKGROUND)).isEqualTo(2000);
assertThat(uidBatteryConsumer.getConsumedPower( assertThat(uidBatteryConsumer.getConsumedPower(
BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300); BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
assertThat(uidBatteryConsumer.getConsumedPower( assertThat(uidBatteryConsumer.getConsumedPower(