summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/UidBatteryConsumer.java72
-rw-r--r--core/java/com/android/internal/os/BatteryUsageStatsProvider.java60
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java76
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java61
5 files changed, 234 insertions, 36 deletions
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index bb40d905d481..dfa0c396485d 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -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,
@@ -113,6 +166,25 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
}
/**
+ * 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.
*/
public Builder excludeFromBatteryUsageStats() {
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index eef9fa74e83a..0163acc295fb 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -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,12 +114,19 @@ 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
- ? customMeasuredEnergiesMicroJoules.length
- : 0;
+ ? customMeasuredEnergiesMicroJoules.length
+ : 0;
// TODO(b/174186358): read extra time component number from configuration
final int customTimeComponentCount = 0;
@@ -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;
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index b819d9edb2a8..434b7ef73118 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -40,6 +40,7 @@ import org.junit.runners.Suite;
BatteryStatsTimeBaseTest.class,
BatteryStatsTimerTest.class,
BatteryStatsUidTest.class,
+ BatteryUsageStatsProviderTest.class,
BatteryUsageStatsTest.class,
BatteryStatsUserLifecycleTests.class,
BluetoothPowerCalculatorTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
new file mode 100644
index 000000000000..c4b7796b49cf
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -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);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 355ac6dbcc00..9ef628848beb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -66,33 +66,36 @@ 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(
- 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(
- BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
+ 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);
+
+ 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(