diff options
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); + } + } +} |