summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/BatteryUsageStats.java45
-rw-r--r--core/java/android/os/BatteryUsageStatsQuery.java33
-rw-r--r--core/java/android/os/UidBatteryConsumer.java34
-rw-r--r--core/java/android/os/UserBatteryConsumer.java115
-rw-r--r--core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/BatteryUsageStatsProvider.java26
-rw-r--r--core/java/com/android/internal/os/BluetoothPowerCalculator.java5
-rw-r--r--core/java/com/android/internal/os/GnssPowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/IdlePowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/MemoryPowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/MobileRadioPowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/PhonePowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/PowerCalculator.java11
-rw-r--r--core/java/com/android/internal/os/ScreenPowerCalculator.java3
-rw-r--r--core/java/com/android/internal/os/SystemServicePowerCalculator.java5
-rw-r--r--core/java/com/android/internal/os/UserPowerCalculator.java32
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java22
-rw-r--r--core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java145
19 files changed, 433 insertions, 62 deletions
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index af8e8de85d9f..305815ff9e51 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -33,20 +33,33 @@ public final class BatteryUsageStats implements Parcelable {
private final int mDischargePercentage;
private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
+ private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
private BatteryUsageStats(@NonNull Builder builder) {
mConsumedPower = builder.mConsumedPower;
mDischargePercentage = builder.mDischargePercentage;
+
int uidBatteryConsumerCount = builder.mUidBatteryConsumerBuilders.size();
mUidBatteryConsumers = new ArrayList<>(uidBatteryConsumerCount);
for (int i = 0; i < uidBatteryConsumerCount; i++) {
- mUidBatteryConsumers.add(builder.mUidBatteryConsumerBuilders.valueAt(i).build());
+ UidBatteryConsumer.Builder uidBatteryConsumerBuilder =
+ builder.mUidBatteryConsumerBuilders.valueAt(i);
+ if (!uidBatteryConsumerBuilder.isExcludedFromBatteryUsageStats()) {
+ mUidBatteryConsumers.add(uidBatteryConsumerBuilder.build());
+ }
}
+
int systemBatteryConsumerCount = builder.mSystemBatteryConsumerBuilders.size();
mSystemBatteryConsumers = new ArrayList<>(systemBatteryConsumerCount);
for (int i = 0; i < systemBatteryConsumerCount; i++) {
mSystemBatteryConsumers.add(builder.mSystemBatteryConsumerBuilders.valueAt(i).build());
}
+
+ int userBatteryConsumerCount = builder.mUserBatteryConsumerBuilders.size();
+ mUserBatteryConsumers = new ArrayList<>(userBatteryConsumerCount);
+ for (int i = 0; i < userBatteryConsumerCount; i++) {
+ mUserBatteryConsumers.add(builder.mUserBatteryConsumerBuilders.valueAt(i).build());
+ }
}
/**
@@ -75,6 +88,11 @@ public final class BatteryUsageStats implements Parcelable {
return mSystemBatteryConsumers;
}
+ @NonNull
+ public List<UserBatteryConsumer> getUserBatteryConsumers() {
+ return mUserBatteryConsumers;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -85,6 +103,8 @@ public final class BatteryUsageStats implements Parcelable {
source.readParcelableList(mUidBatteryConsumers, getClass().getClassLoader());
mSystemBatteryConsumers = new ArrayList<>();
source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
+ mUserBatteryConsumers = new ArrayList<>();
+ source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
mConsumedPower = source.readDouble();
mDischargePercentage = source.readInt();
}
@@ -93,6 +113,7 @@ public final class BatteryUsageStats implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelableList(mUidBatteryConsumers, flags);
dest.writeParcelableList(mSystemBatteryConsumers, flags);
+ dest.writeParcelableList(mUserBatteryConsumers, flags);
dest.writeDouble(mConsumedPower);
dest.writeInt(mDischargePercentage);
}
@@ -120,6 +141,8 @@ public final class BatteryUsageStats implements Parcelable {
new SparseArray<>();
private final SparseArray<SystemBatteryConsumer.Builder> mSystemBatteryConsumerBuilders =
new SparseArray<>();
+ private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
+ new SparseArray<>();
public Builder(int customPowerComponentCount, int customTimeComponentCount) {
mCustomPowerComponentCount = customPowerComponentCount;
@@ -137,7 +160,6 @@ public final class BatteryUsageStats implements Parcelable {
/**
* Sets the battery discharge amount since BatteryStats reset as percentage of the full
* charge.
- *
*/
@SuppressLint("PercentageInt") // See b/174188159
@NonNull
@@ -173,8 +195,8 @@ public final class BatteryUsageStats implements Parcelable {
}
/**
- * Creates or returns a exiting UidBatteryConsumer, which represents battery attribution
- * data for an individual UID.
+ * Creates or returns a exiting SystemBatteryConsumer, which represents battery attribution
+ * data for a specific drain type.
*/
@NonNull
public SystemBatteryConsumer.Builder getOrCreateSystemBatteryConsumerBuilder(
@@ -188,6 +210,21 @@ public final class BatteryUsageStats implements Parcelable {
return builder;
}
+ /**
+ * Creates or returns a exiting UserBatteryConsumer, which represents battery attribution
+ * data for an individual {@link UserHandle}.
+ */
+ @NonNull
+ public UserBatteryConsumer.Builder getOrCreateUserBatteryConsumerBuilder(int userId) {
+ UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId);
+ if (builder == null) {
+ builder = new UserBatteryConsumer.Builder(mCustomPowerComponentCount,
+ mCustomTimeComponentCount, userId);
+ mUserBatteryConsumerBuilders.put(userId, builder);
+ }
+ return builder;
+ }
+
@NonNull
public SparseArray<UidBatteryConsumer.Builder> getUidBatteryConsumerBuilders() {
return mUidBatteryConsumerBuilders;
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 48e7389e5ff2..5b5fe1d15a82 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.util.IntArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -53,9 +54,13 @@ public final class BatteryUsageStatsQuery implements Parcelable {
public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 1;
private final int mFlags;
+ @NonNull
+ private final int[] mUserIds;
private BatteryUsageStatsQuery(@NonNull Builder builder) {
mFlags = builder.mFlags;
+ mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
+ : new int[]{UserHandle.USER_ALL};
}
@BatteryUsageStatsFlags
@@ -63,13 +68,28 @@ public final class BatteryUsageStatsQuery implements Parcelable {
return mFlags;
}
+ /**
+ * Returns an array of users for which the attribution is requested. It may
+ * contain {@link UserHandle#USER_ALL} to indicate that the attribution
+ * should be performed for all users. Battery consumed by users <b>not</b> included
+ * in this array will be returned in the aggregated form as {@link UserBatteryConsumer}'s.
+ */
+ @NonNull
+ public int[] getUserIds() {
+ return mUserIds;
+ }
+
private BatteryUsageStatsQuery(Parcel in) {
mFlags = in.readInt();
+ mUserIds = new int[in.readInt()];
+ in.readIntArray(mUserIds);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mFlags);
+ dest.writeInt(mUserIds.length);
+ dest.writeIntArray(mUserIds);
}
@Override
@@ -96,6 +116,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
*/
public static final class Builder {
private int mFlags;
+ private IntArray mUserIds;
/**
* Builds a read-only BatteryUsageStatsQuery object.
@@ -105,6 +126,18 @@ public final class BatteryUsageStatsQuery implements Parcelable {
}
/**
+ * Add a user whose battery stats should be included in the battery usage stats.
+ * {@link UserHandle#USER_ALL} will be used by default if no users are added explicitly.
+ */
+ public Builder addUser(@NonNull UserHandle userHandle) {
+ if (mUserIds == null) {
+ mUserIds = new IntArray(1);
+ }
+ mUserIds.add(userHandle.getIdentifier());
+ return this;
+ }
+
+ /**
* Sets flags to modify the behavior of {@link BatteryStatsManager#getBatteryUsageStats}.
*/
public Builder setFlags(@BatteryUsageStatsFlags int flags) {
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 3ffaa9e4b1f0..d1ca6a560c3f 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -96,6 +96,7 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
private final int mUid;
private String mPackageWithHighestDrain;
private boolean mSystemComponent;
+ private boolean mExcludeFromBatteryUsageStats;
public Builder(int customPowerComponentCount, int customTimeComponentCount,
BatteryStats.Uid batteryStatsUid) {
@@ -113,14 +114,6 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
}
/**
- * Creates a read-only object out of the Builder values.
- */
- @NonNull
- public UidBatteryConsumer build() {
- return new UidBatteryConsumer(this);
- }
-
- /**
* Sets the name of the package owned by this UID that consumed the highest amount
* of power since BatteryStats reset.
*/
@@ -131,12 +124,27 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
}
/**
- * Marks the UidBatteryConsumer as part of the system. For example,
- * the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID} is considered
- * as a system component.
+ * Marks the UidBatteryConsumer for exclusion from the result set.
*/
- public void setSystemComponent(boolean systemComponent) {
- mSystemComponent = systemComponent;
+ public Builder excludeFromBatteryUsageStats() {
+ mExcludeFromBatteryUsageStats = true;
+ return this;
+ }
+
+ /**
+ * Returns true if this UidBatteryConsumer must be excluded from the
+ * BatteryUsageStats.
+ */
+ public boolean isExcludedFromBatteryUsageStats() {
+ return mExcludeFromBatteryUsageStats;
+ }
+
+ /**
+ * Creates a read-only object out of the Builder values.
+ */
+ @NonNull
+ public UidBatteryConsumer build() {
+ return new UidBatteryConsumer(this);
}
}
}
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
new file mode 100644
index 000000000000..94e567f368b0
--- /dev/null
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -0,0 +1,115 @@
+/*
+ * 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 android.os;
+
+import android.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Contains power consumption data attributed to a {@link UserHandle}.
+ *
+ * {@hide}
+ */
+public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
+ private final int mUserId;
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ private UserBatteryConsumer(@NonNull UserBatteryConsumer.Builder builder) {
+ super(builder.mPowerComponentsBuilder.build());
+ mUserId = builder.mUserId;
+ }
+
+ private UserBatteryConsumer(Parcel in) {
+ super(new PowerComponents(in));
+ mUserId = in.readInt();
+ }
+
+ /**
+ * Writes the contents into a Parcel.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mUserId);
+ }
+
+ public static final Creator<UserBatteryConsumer> CREATOR =
+ new Creator<UserBatteryConsumer>() {
+ @Override
+ public UserBatteryConsumer createFromParcel(Parcel in) {
+ return new UserBatteryConsumer(in);
+ }
+
+ @Override
+ public UserBatteryConsumer[] newArray(int size) {
+ return new UserBatteryConsumer[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Builder for UserBatteryConsumer.
+ */
+ public static final class Builder extends BaseBuilder<Builder> {
+ private final int mUserId;
+ private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
+
+ Builder(int customPowerComponentCount, int customTimeComponentCount, int userId) {
+ super(customPowerComponentCount, customTimeComponentCount);
+ mUserId = userId;
+ }
+
+ /**
+ * Add a UidBatteryConsumer to this UserBatteryConsumer.
+ * <p>
+ * Calculated power and duration components of the added UID battery consumers
+ * are aggregated at the time the UserBatteryConsumer is built by the {@link #build()}
+ * method.
+ * </p>
+ */
+ public void addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder) {
+ if (mUidBatteryConsumers == null) {
+ mUidBatteryConsumers = new ArrayList<>();
+ }
+ mUidBatteryConsumers.add(uidBatteryConsumerBuilder);
+ }
+
+ /**
+ * Creates a read-only object out of the Builder values.
+ */
+ @NonNull
+ public UserBatteryConsumer build() {
+ if (mUidBatteryConsumers != null) {
+ for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
+ UidBatteryConsumer.Builder uidBatteryConsumer = mUidBatteryConsumers.get(i);
+ mPowerComponentsBuilder.addPowerAndDuration(
+ uidBatteryConsumer.mPowerComponentsBuilder);
+ }
+ }
+ return new UserBatteryConsumer(this);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index 8fe17fb1565c..16b6f3a155f8 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -43,8 +43,7 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
*/
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = mPowerEstimator.calculatePower(durationMs);
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index e76e34f840ba..094724c00508 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -24,7 +24,6 @@ import android.os.BatteryUsageStatsQuery;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.os.UserManager;
import android.util.SparseArray;
import java.util.ArrayList;
@@ -89,26 +88,27 @@ public class BatteryUsageStatsProvider {
final BatteryStatsHelper batteryStatsHelper = new BatteryStatsHelper(mContext,
false /* collectBatteryBroadcast */);
batteryStatsHelper.create((Bundle) null);
- final UserManager userManager = mContext.getSystemService(UserManager.class);
- final List<UserHandle> asUsers = userManager.getUserProfiles();
- final int n = asUsers.size();
- SparseArray<UserHandle> users = new SparseArray<>(n);
- for (int i = 0; i < n; ++i) {
- UserHandle userHandle = asUsers.get(i);
- users.put(userHandle.getIdentifier(), userHandle);
+ final List<UserHandle> users = new ArrayList<>();
+ for (int i = 0; i < queries.size(); i++) {
+ BatteryUsageStatsQuery query = queries.get(i);
+ for (int userId : query.getUserIds()) {
+ UserHandle userHandle = UserHandle.of(userId);
+ if (!users.contains(userHandle)) {
+ users.add(userHandle);
+ }
+ }
}
-
batteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, users);
ArrayList<BatteryUsageStats> results = new ArrayList<>(queries.size());
for (int i = 0; i < queries.size(); i++) {
- results.add(getBatteryUsageStats(queries.get(i), batteryStatsHelper, users));
+ results.add(getBatteryUsageStats(queries.get(i), batteryStatsHelper));
}
return results;
}
private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
- BatteryStatsHelper batteryStatsHelper, SparseArray<UserHandle> users) {
+ BatteryStatsHelper batteryStatsHelper) {
// TODO(b/174186358): read extra power component number from configuration
final int customPowerComponentCount = 0;
final int customTimeComponentCount = 0;
@@ -128,8 +128,8 @@ public class BatteryUsageStatsProvider {
final List<PowerCalculator> powerCalculators = getPowerCalculators();
for (PowerCalculator powerCalculator : powerCalculators) {
- powerCalculator.calculate(batteryUsageStatsBuilder, mStats, realtimeUs, uptimeUs, query,
- users);
+ powerCalculator.calculate(batteryUsageStatsBuilder, mStats, realtimeUs, uptimeUs,
+ query);
}
return batteryUsageStatsBuilder.build();
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 4c3b950ff715..7d42de4486a4 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -50,8 +50,7 @@ public class BluetoothPowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
return;
}
@@ -68,7 +67,7 @@ public class BluetoothPowerCalculator extends PowerCalculator {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
calculateApp(app, total);
if (app.getUid() == Process.BLUETOOTH_UID) {
- app.setSystemComponent(true);
+ app.excludeFromBatteryUsageStats();
systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
}
}
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index 9ea934af642a..df25cdaee17f 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -45,8 +45,7 @@ public class GnssPowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
final double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index dcc8a15b2f50..4a4991bd3966 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -49,8 +49,7 @@ public class IdlePowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs,
BatteryStats.STATS_SINCE_CHARGED);
if (mPowerMah != 0) {
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index df4605838b28..21dcce9fb64f 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -26,8 +26,7 @@ public class MemoryPowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = calculatePower(batteryStats, rawRealtimeUs,
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index e3bd64d77e9b..22001d4ffbb7 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -85,8 +85,7 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
PowerAndDuration total = new PowerAndDuration();
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 6ab8c90d21d9..362ca0761b2c 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -39,8 +39,7 @@ public class PhonePowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED) / 1000;
final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index 05fcc705e734..13c59dcdbc4e 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -67,17 +67,10 @@ public abstract class PowerCalculator {
* @param batteryStats The recorded battery stats.
* @param rawRealtimeUs The raw system realtime in microseconds.
* @param rawUptimeUs The raw system uptime in microseconds.
- * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this
- * can only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
- * {@link BatteryStats#STATS_CURRENT} and
- * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
- * @param asUsers An array of users for which the attribution is requested. It may
- * contain {@link UserHandle#USER_ALL} to indicate that the attribution
- * should be performed for all users.
+ * @param query The query parameters for the calculator.
*/
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index c86c795c965a..bb1222eac11c 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -51,8 +51,7 @@ public class ScreenPowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
final long durationMs = computeDuration(batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED);
final double powerMah = computePower(batteryStats, rawRealtimeUs,
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index 55fc1bb607a9..955f6afe579c 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -51,10 +51,9 @@ public class SystemServicePowerCalculator extends PowerCalculator {
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
- SparseArray<UserHandle> asUsers) {
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
calculateSystemServicePower(batteryStats);
- super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query, asUsers);
+ super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query);
}
@Override
diff --git a/core/java/com/android/internal/os/UserPowerCalculator.java b/core/java/com/android/internal/os/UserPowerCalculator.java
index 53f85154330c..8e802869e2fc 100644
--- a/core/java/com/android/internal/os/UserPowerCalculator.java
+++ b/core/java/com/android/internal/os/UserPowerCalculator.java
@@ -17,10 +17,15 @@
package com.android.internal.os;
import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
import android.os.Process;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.SparseArray;
+import com.android.internal.util.ArrayUtils;
+
import java.util.List;
/**
@@ -29,6 +34,33 @@ import java.util.List;
public class UserPowerCalculator extends PowerCalculator {
@Override
+ public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ final int[] userIds = query.getUserIds();
+ if (ArrayUtils.contains(userIds, UserHandle.USER_ALL)) {
+ return;
+ }
+
+ SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
+ final int uid = uidBuilder.getUid();
+ if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
+ continue;
+ }
+
+ final int userId = UserHandle.getUserId(uid);
+ if (!ArrayUtils.contains(userIds, userId)) {
+ uidBuilder.excludeFromBatteryUsageStats();
+ builder.getOrCreateUserBatteryConsumerBuilder(userId)
+ .addUidBatteryConsumer(uidBuilder);
+ }
+ }
+ }
+
+ @Override
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
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 143e07a1c8a6..4b9286d4de26 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -65,6 +65,7 @@ import org.junit.runners.Suite;
ScreenPowerCalculatorTest.class,
SensorPowerCalculatorTest.class,
SystemServicePowerCalculatorTest.class,
+ UserPowerCalculatorTest.class,
VideoPowerCalculatorTest.class,
com.android.internal.power.MeasuredEnergyStatsTest.class
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 2c71287fac4a..0c31c5b9818b 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -28,6 +28,7 @@ import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
+import android.os.UserBatteryConsumer;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -113,15 +114,21 @@ public class BatteryUsageStatsRule implements TestRule {
mMockClocks.uptime = uptimeUs;
}
- void apply(PowerCalculator calculator) {
+ void apply(PowerCalculator... calculators) {
+ apply(BatteryUsageStatsQuery.DEFAULT, calculators);
+ }
+
+ void apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) {
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0);
SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
for (int i = 0; i < uidStats.size(); i++) {
builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
}
- calculator.calculate(builder, mBatteryStats, mMockClocks.realtime, mMockClocks.uptime,
- BatteryUsageStatsQuery.DEFAULT, null);
+ for (PowerCalculator calculator : calculators) {
+ calculator.calculate(builder, mBatteryStats, mMockClocks.realtime, mMockClocks.uptime,
+ query);
+ }
mBatteryUsageStats = builder.build();
}
@@ -144,4 +151,13 @@ public class BatteryUsageStatsRule implements TestRule {
}
return null;
}
+
+ public UserBatteryConsumer getUserBatteryConsumer(int userId) {
+ for (UserBatteryConsumer ubc : mBatteryUsageStats.getUserBatteryConsumers()) {
+ if (ubc.getUserId() == userId) {
+ return ubc;
+ }
+ }
+ return null;
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java
new file mode 100644
index 000000000000..6fa1d3bae0f7
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/UserPowerCalculatorTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+import android.os.UserBatteryConsumer;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UserPowerCalculatorTest {
+ public static final int USER1 = 0;
+ public static final int USER2 = 1625;
+
+ private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
+ private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 272;
+ private static final int APP_UID3 = Process.FIRST_APPLICATION_UID + 314;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+ @Test
+ public void testAllUsers() {
+ prepareUidBatteryConsumers();
+
+ UserPowerCalculator calculator = new UserPowerCalculator();
+
+ mStatsRule.apply(BatteryUsageStatsQuery.DEFAULT, calculator, new FakeAudioPowerCalculator(),
+ new FakeVideoPowerCalculator());
+
+ assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull();
+
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(3000);
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(7000);
+
+ assertThat(mStatsRule.getUserBatteryConsumer(USER2)).isNull();
+
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(5555);
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(9999);
+ }
+
+ @Test
+ public void testSpecificUser() {
+ prepareUidBatteryConsumers();
+
+ UserPowerCalculator calculator = new UserPowerCalculator();
+
+ mStatsRule.apply(new BatteryUsageStatsQuery.Builder().addUser(UserHandle.of(USER1)).build(),
+ calculator, new FakeAudioPowerCalculator(), new FakeVideoPowerCalculator());
+
+ assertThat(mStatsRule.getUserBatteryConsumer(USER1)).isNull();
+
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(3000);
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID1))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(7000);
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID2))).isNull();
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)).isEqualTo(7070);
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER1, APP_UID3))
+ .getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)).isEqualTo(11110);
+
+ UserBatteryConsumer user2 = mStatsRule.getUserBatteryConsumer(USER2);
+ assertThat(user2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO))
+ .isEqualTo(15308);
+ assertThat(user2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO))
+ .isEqualTo(24196);
+
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID1))).isNull();
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID2))).isNull();
+ assertThat(mStatsRule.getUidBatteryConsumer(UserHandle.getUid(USER2, APP_UID3))).isNull();
+ }
+
+ private void prepareUidBatteryConsumers() {
+ prepareUidBatteryConsumer(USER1, APP_UID1, 1000, 2000, 3000, 4000);
+ prepareUidBatteryConsumer(USER2, APP_UID2, 2222, 3333, 4444, 5555);
+ prepareUidBatteryConsumer(USER1, APP_UID3, 3030, 4040, 5050, 6060);
+ prepareUidBatteryConsumer(USER2, APP_UID3, 4321, 5432, 6543, 7654);
+ }
+
+ private void prepareUidBatteryConsumer(int userId, int uid, long audioDuration1Ms,
+ long audioDuration2Ms, long videoDuration1Ms, long videoDuration2Ms) {
+ BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(UserHandle.getUid(userId, uid));
+
+ // Use "audio" and "video" to fake some power consumption. Could be any other type of usage.
+ uidStats.noteAudioTurnedOnLocked(0);
+ uidStats.noteAudioTurnedOffLocked(audioDuration1Ms);
+ uidStats.noteAudioTurnedOnLocked(1000000);
+ uidStats.noteAudioTurnedOffLocked(1000000 + audioDuration2Ms);
+
+ uidStats.noteVideoTurnedOnLocked(0);
+ uidStats.noteVideoTurnedOffLocked(videoDuration1Ms);
+ uidStats.noteVideoTurnedOnLocked(2000000);
+ uidStats.noteVideoTurnedOffLocked(2000000 + videoDuration2Ms);
+ }
+
+ private static class FakeAudioPowerCalculator extends PowerCalculator {
+ @Override
+ protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ long durationMs = u.getAudioTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0);
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs / 1000);
+ }
+ }
+
+ private static class FakeVideoPowerCalculator extends PowerCalculator {
+ @Override
+ protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ long durationMs = u.getVideoTurnedOnTimer().getTotalTimeLocked(rawRealtimeUs, 0);
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs / 1000);
+ }
+ }
+}