diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java index 449e3aeb6be61..ee86265e81ada 100644 --- a/core/java/android/os/AggregateBatteryConsumer.java +++ b/core/java/android/os/AggregateBatteryConsumer.java @@ -18,6 +18,8 @@ package android.os; import android.annotation.NonNull; +import java.io.PrintWriter; + /** * Contains power consumption data across the entire device. * @@ -37,6 +39,11 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P mConsumedPowerMah = source.readDouble(); } + @Override + public void dump(PrintWriter pw, boolean skipEmptyComponents) { + mPowerComponents.dump(pw, skipEmptyComponents); + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { super.writeToParcel(dest, flags); diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index 6b628b0140e6a..edb30b0f26ca5 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -19,6 +19,7 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -27,7 +28,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -public class BatteryConsumer { +public abstract class BatteryConsumer { /** * Power usage component, describing the particular part of the system @@ -85,12 +86,37 @@ public class BatteryConsumer { public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000; public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999; + private static final String[] sPowerComponentNames = new String[POWER_COMPONENT_COUNT]; + + static { + // Assign individually to avoid future mismatch + sPowerComponentNames[POWER_COMPONENT_SCREEN] = "screen"; + sPowerComponentNames[POWER_COMPONENT_CPU] = "cpu"; + sPowerComponentNames[POWER_COMPONENT_BLUETOOTH] = "bluetooth"; + sPowerComponentNames[POWER_COMPONENT_CAMERA] = "camera"; + sPowerComponentNames[POWER_COMPONENT_AUDIO] = "audio"; + sPowerComponentNames[POWER_COMPONENT_VIDEO] = "video"; + sPowerComponentNames[POWER_COMPONENT_FLASHLIGHT] = "flashlight"; + sPowerComponentNames[POWER_COMPONENT_SYSTEM_SERVICES] = "system_services"; + sPowerComponentNames[POWER_COMPONENT_MOBILE_RADIO] = "mobile_radio"; + sPowerComponentNames[POWER_COMPONENT_SENSORS] = "sensors"; + sPowerComponentNames[POWER_COMPONENT_GNSS] = "gnss"; + sPowerComponentNames[POWER_COMPONENT_WIFI] = "wifi"; + sPowerComponentNames[POWER_COMPONENT_WAKELOCK] = "wakelock"; + sPowerComponentNames[POWER_COMPONENT_MEMORY] = "memory"; + sPowerComponentNames[POWER_COMPONENT_PHONE] = "phone"; + sPowerComponentNames[POWER_COMPONENT_AMBIENT_DISPLAY] = "ambient_display"; + sPowerComponentNames[POWER_COMPONENT_IDLE] = "idle"; + sPowerComponentNames[POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS] = "reattributed"; + } + /** * Identifiers of models used for power estimation. * * @hide */ @IntDef(prefix = {"POWER_MODEL_"}, value = { + POWER_MODEL_UNDEFINED, POWER_MODEL_POWER_PROFILE, POWER_MODEL_MEASURED_ENERGY, }) @@ -98,16 +124,21 @@ public class BatteryConsumer { public @interface PowerModel { } + /** + * Unspecified power model. + */ + public static final int POWER_MODEL_UNDEFINED = 0; + /** * Power model that is based on average consumption rates that hardware components * consume in various states. */ - public static final int POWER_MODEL_POWER_PROFILE = 0; + public static final int POWER_MODEL_POWER_PROFILE = 1; /** * Power model that is based on energy consumption measured by on-device power monitors. */ - public static final int POWER_MODEL_MEASURED_ENERGY = 1; + public static final int POWER_MODEL_MEASURED_ENERGY = 2; protected final PowerComponents mPowerComponents; @@ -197,6 +228,41 @@ public class BatteryConsumer { mPowerComponents.writeToParcel(dest, flags); } + /** + * Returns the name of the specified component. Intended for logging and debugging. + */ + public static String powerComponentIdToString(@BatteryConsumer.PowerComponent int componentId) { + return sPowerComponentNames[componentId]; + } + + /** + * Returns the name of the specified power model. Intended for logging and debugging. + */ + public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) { + switch (powerModel) { + case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: + return "measured energy"; + case BatteryConsumer.POWER_MODEL_POWER_PROFILE: + return "power profile"; + default: + return ""; + } + } + + /** + * Prints the stats in a human-readable format. + */ + public void dump(PrintWriter pw) { + dump(pw, true); + } + + /** + * Prints the stats in a human-readable format. + * + * @param skipEmptyComponents if true, omit any power components with a zero amount. + */ + public abstract void dump(PrintWriter pw, boolean skipEmptyComponents); + protected abstract static class BaseBuilder> { final PowerComponents.Builder mPowerComponentsBuilder; diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index eec6810fa8bcb..c97d1f8bcf02a 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -51,6 +51,7 @@ import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; +import com.android.internal.os.BatteryUsageStatsProvider; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -5299,154 +5300,19 @@ public abstract class BatteryStats implements Parcelable { pw.println(getDischargeAmountScreenDozeSinceCharge()); pw.println(); + final BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, this); + final BatteryUsageStats stats = provider.getBatteryUsageStats( + new BatteryUsageStatsQuery.Builder() + .setMaxStatsAgeMs(0) + .includePowerModels() + .build()); + stats.dump(pw, prefix); + final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); helper.create(this); helper.refreshStats(which, UserHandle.USER_ALL); - List sippers = helper.getUsageList(); - if (sippers != null && sippers.size() > 0) { - pw.print(prefix); pw.println(" Estimated power use (mAh):"); - pw.print(prefix); pw.print(" Capacity: "); - printmAh(pw, helper.getPowerProfile().getBatteryCapacity()); - pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower()); - pw.print(", actual drain: "); printmAh(pw, helper.getMinDrainedPower()); - if (helper.getMinDrainedPower() != helper.getMaxDrainedPower()) { - pw.print("-"); printmAh(pw, helper.getMaxDrainedPower()); - } - pw.println(); - for (int i=0; i sippers = helper.getMobilemsppList(); if (sippers != null && sippers.size() > 0) { pw.print(prefix); pw.println(" Per-app mobile ms per packet:"); long totalTime = 0; diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index 6bc861f87e48d..32256677c7f1d 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -23,10 +23,13 @@ import android.util.SparseArray; import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.BatteryStatsHistoryIterator; +import com.android.internal.os.PowerCalculator; +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; /** @@ -73,6 +76,7 @@ public final class BatteryUsageStats implements Parcelable { private final int mDischargePercentage; private final long mStatsStartTimestampMs; + private final double mBatteryCapacityMah; private final double mDischargedPowerLowerBound; private final double mDischargedPowerUpperBound; private final long mBatteryTimeRemainingMs; @@ -86,6 +90,7 @@ public final class BatteryUsageStats implements Parcelable { private BatteryUsageStats(@NonNull Builder builder) { mStatsStartTimestampMs = builder.mStatsStartTimestampMs; + mBatteryCapacityMah = builder.mBatteryCapacityMah; mDischargePercentage = builder.mDischargePercentage; mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah; mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah; @@ -144,6 +149,13 @@ public final class BatteryUsageStats implements Parcelable { .getConsumedPower(); } + /** + * Returns battery capacity in milli-amp-hours. + */ + public double getBatteryCapacity() { + return mBatteryCapacityMah; + } + /** * Portion of battery charge drained since BatteryStats reset (e.g. due to being fully * charged), as percentage of the full charge in the range [0:100] @@ -217,6 +229,7 @@ public final class BatteryUsageStats implements Parcelable { private BatteryUsageStats(@NonNull Parcel source) { mStatsStartTimestampMs = source.readLong(); + mBatteryCapacityMah = source.readDouble(); mDischargePercentage = source.readInt(); mDischargedPowerLowerBound = source.readDouble(); mDischargedPowerUpperBound = source.readDouble(); @@ -274,6 +287,7 @@ public final class BatteryUsageStats implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(mStatsStartTimestampMs); + dest.writeDouble(mBatteryCapacityMah); dest.writeInt(mDischargePercentage); dest.writeDouble(mDischargedPowerLowerBound); dest.writeDouble(mDischargedPowerUpperBound); @@ -321,6 +335,104 @@ public final class BatteryUsageStats implements Parcelable { } }; + /** + * Prints the stats in a human-readable format. + */ + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); + pw.println(" Estimated power use (mAh):"); + pw.print(prefix); + pw.print(" Capacity: "); + PowerCalculator.printPowerMah(pw, getBatteryCapacity()); + pw.print(", Computed drain: "); + PowerCalculator.printPowerMah(pw, getConsumedPower()); + final Range dischargedPowerRange = getDischargedPowerRange(); + pw.print(", actual drain: "); + PowerCalculator.printPowerMah(pw, dischargedPowerRange.getLower()); + if (!dischargedPowerRange.getLower().equals(dischargedPowerRange.getUpper())) { + pw.print("-"); + PowerCalculator.printPowerMah(pw, dischargedPowerRange.getUpper()); + } + pw.println(); + + pw.println(" Global"); + final BatteryConsumer deviceConsumer = getAggregateBatteryConsumer( + AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); + final BatteryConsumer appsConsumer = getAggregateBatteryConsumer( + AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); + + for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; + componentId++) { + final double devicePowerMah = deviceConsumer.getConsumedPower(componentId); + final double appsPowerMah = appsConsumer.getConsumedPower(componentId); + if (devicePowerMah == 0 && appsPowerMah == 0) { + continue; + } + + final String componentName = BatteryConsumer.powerComponentIdToString(componentId); + printPowerComponent(pw, prefix, componentName, devicePowerMah, appsPowerMah, + deviceConsumer.getPowerModel(componentId), + deviceConsumer.getUsageDurationMillis(componentId)); + } + + for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID; + componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + + mCustomPowerComponentNames.length; + componentId++) { + final double devicePowerMah = + deviceConsumer.getConsumedPowerForCustomComponent(componentId); + final double appsPowerMah = + appsConsumer.getConsumedPowerForCustomComponent(componentId); + if (devicePowerMah == 0 && appsPowerMah == 0) { + continue; + } + + printPowerComponent(pw, prefix, deviceConsumer.getCustomPowerComponentName(componentId), + devicePowerMah, appsPowerMah, + BatteryConsumer.POWER_MODEL_UNDEFINED, + deviceConsumer.getUsageDurationForCustomComponentMillis(componentId)); + } + + dumpSortedBatteryConsumers(pw, prefix, getUidBatteryConsumers()); + dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers()); + } + + private void printPowerComponent(PrintWriter pw, String prefix, String componentName, + double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) { + StringBuilder sb = new StringBuilder(); + sb.append(prefix).append(" ").append(componentName).append(": ") + .append(PowerCalculator.formatCharge(devicePowerMah)); + if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED + && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) { + sb.append(" ["); + sb.append(BatteryConsumer.powerModelToString(powerModel)); + sb.append("]"); + } + sb.append(" apps: ").append(PowerCalculator.formatCharge(appsPowerMah)); + if (durationMs != 0) { + sb.append(" duration: "); + BatteryStats.formatTimeMs(sb, durationMs); + } + + pw.println(sb.toString()); + } + + private void dumpSortedBatteryConsumers(PrintWriter pw, String prefix, + List batteryConsumers) { + batteryConsumers.sort( + Comparator.comparingDouble(BatteryConsumer::getConsumedPower) + .reversed()); + for (BatteryConsumer consumer : batteryConsumers) { + if (consumer.getConsumedPower() == 0) { + continue; + } + pw.print(prefix); + pw.print(" "); + consumer.dump(pw); + pw.println(); + } + } + /** * Builder for BatteryUsageStats. */ @@ -329,6 +441,7 @@ public final class BatteryUsageStats implements Parcelable { private final String[] mCustomPowerComponentNames; private final boolean mIncludePowerModels; private long mStatsStartTimestampMs; + private double mBatteryCapacityMah; private int mDischargePercentage; private double mDischargedPowerLowerBoundMah; private double mDischargedPowerUpperBoundMah; @@ -364,6 +477,14 @@ public final class BatteryUsageStats implements Parcelable { return new BatteryUsageStats(this); } + /** + * Sets the battery capacity in milli-amp-hours. + */ + public Builder setBatteryCapacity(double batteryCapacityMah) { + mBatteryCapacityMah = batteryCapacityMah; + return this; + } + /** * Sets the timestamp of the latest battery stats reset, in milliseconds. */ diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java index 47a2edccc640c..964f1b681866f 100644 --- a/core/java/android/os/PowerComponents.java +++ b/core/java/android/os/PowerComponents.java @@ -17,6 +17,10 @@ package android.os; import android.annotation.NonNull; +import com.android.internal.os.PowerCalculator; + +import java.io.PrintWriter; + /** * Contains details of battery attribution data broken down to individual power drain types * such as CPU, RAM, GPU etc. @@ -202,6 +206,37 @@ class PowerComponents { return max; } + public void dump(PrintWriter pw, boolean skipEmptyComponents) { + String separator = ""; + for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; + componentId++) { + final double componentPower = getConsumedPower(componentId); + if (skipEmptyComponents && componentPower == 0) { + continue; + } + pw.print(separator); separator = " "; + pw.print(BatteryConsumer.powerComponentIdToString(componentId)); + pw.print("="); + PowerCalculator.printPowerMah(pw, componentPower); + } + + final int customComponentCount = getCustomPowerComponentCount(); + for (int customComponentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID; + customComponentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + + customComponentCount; + customComponentId++) { + final double customComponentPower = + getConsumedPowerForCustomComponent(customComponentId); + if (skipEmptyComponents && customComponentPower == 0) { + continue; + } + pw.print(separator); separator = " "; + pw.print(getCustomPowerComponentName(customComponentId)); + pw.print("="); + PowerCalculator.printPowerMah(pw, customComponentPower); + } + } + /** * Builder for PowerComponents. */ diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java index b1fb570b43956..16a6c767da387 100644 --- a/core/java/android/os/UidBatteryConsumer.java +++ b/core/java/android/os/UidBatteryConsumer.java @@ -20,6 +20,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import com.android.internal.os.PowerCalculator; + +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -112,6 +115,18 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela dest.writeLong(mTimeInBackgroundMs); } + @Override + public void dump(PrintWriter pw, boolean skipEmptyComponents) { + final double consumedPower = getConsumedPower(); + pw.print("UID "); + UserHandle.formatUid(pw, getUid()); + pw.print(": "); + PowerCalculator.printPowerMah(pw, consumedPower); + pw.print(" ( "); + mPowerComponents.dump(pw, skipEmptyComponents /* skipTotalPowerComponent */); + pw.print(" ) "); + } + @NonNull public static final Creator CREATOR = new Creator() { public UidBatteryConsumer createFromParcel(@NonNull Parcel source) { diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java index d0d0d38a75d28..429d2c53a836b 100644 --- a/core/java/android/os/UserBatteryConsumer.java +++ b/core/java/android/os/UserBatteryConsumer.java @@ -18,6 +18,9 @@ package android.os; import android.annotation.NonNull; +import com.android.internal.os.PowerCalculator; + +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -52,6 +55,18 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable { dest.writeInt(mUserId); } + @Override + public void dump(PrintWriter pw, boolean skipEmptyComponents) { + final double consumedPower = getConsumedPower(); + pw.print("User "); + pw.print(mUserId); + pw.print(": "); + PowerCalculator.printPowerMah(pw, consumedPower); + pw.print(" ( "); + mPowerComponents.dump(pw, skipEmptyComponents /* skipTotalPowerComponent */); + pw.print(" ) "); + } + public static final Creator CREATOR = new Creator() { @Override diff --git a/core/java/com/android/internal/os/BatteryChargeCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java index 16f92efb922c0..0690d1f3fae67 100644 --- a/core/java/com/android/internal/os/BatteryChargeCalculator.java +++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java @@ -42,6 +42,8 @@ public class BatteryChargeCalculator extends PowerCalculator { batteryCapacityMah = batteryStats.getEstimatedBatteryCapacity(); } } + builder.setBatteryCapacity(batteryCapacityMah); + final double dischargedPowerLowerBoundMah = batteryStats.getLowDischargeAmountSinceCharge() * batteryCapacityMah / 100.0; final double dischargedPowerUpperBoundMah = diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java index d139b4f0aa9a7..4979ecbae8cb7 100644 --- a/core/java/com/android/internal/os/PowerCalculator.java +++ b/core/java/com/android/internal/os/PowerCalculator.java @@ -24,6 +24,7 @@ import android.os.UidBatteryConsumer; import android.os.UserHandle; import android.util.SparseArray; +import java.io.PrintWriter; import java.util.List; import java.util.Locale; @@ -157,6 +158,12 @@ public abstract class PowerCalculator { } } + /** + * Prints formatted amount of power in milli-amp-hours. + */ + public static void printPowerMah(PrintWriter pw, double powerMah) { + pw.print(formatCharge(powerMah)); + } /** * Converts charge in mAh to string. 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 127cea84ba8ca..c8564acfc656b 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java @@ -24,6 +24,7 @@ import android.os.BatteryConsumer; import android.os.BatteryUsageStats; import android.os.Parcel; import android.os.UidBatteryConsumer; +import android.os.UserBatteryConsumer; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -31,7 +32,11 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashSet; import java.util.List; +import java.util.Set; @SmallTest @RunWith(AndroidJUnit4.class) @@ -60,13 +65,42 @@ public class BatteryUsageStatsTest { validateBatteryUsageStats(inBatteryUsageStats); } + @Test + public void testDump() { + final BatteryUsageStats stats = buildBatteryUsageStats(); + final StringWriter out = new StringWriter(); + try (PrintWriter pw = new PrintWriter(out)) { + stats.dump(pw, " "); + } + final String dump = out.toString(); + + assertThat(dump).contains("Capacity: 4000"); + assertThat(dump).contains("Computed drain: 30000"); + assertThat(dump).contains("actual drain: 1000-2000"); + assertThat(dump).contains("cpu: 20100 apps: 10100 duration: 20s 300ms"); + assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms"); + assertThat(dump).contains("UID 2000: 1200 ( screen=300 cpu=400 FOO=500 )"); + assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 FOO=20.0 )"); + } + + @Test + public void testPowerComponentNames_existAndUnique() { + Set allNames = new HashSet<>(); + for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) { + assertThat(BatteryConsumer.powerComponentIdToString(i)).isNotNull(); + allNames.add(BatteryConsumer.powerComponentIdToString(i)); + } + assertThat(allNames).hasSize(BatteryConsumer.POWER_COMPONENT_COUNT); + } + private BatteryUsageStats buildBatteryUsageStats() { final MockClocks clocks = new MockClocks(); final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks); final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000); final BatteryUsageStats.Builder builder = - new BatteryUsageStats.Builder(new String[]{"FOO"}) + new BatteryUsageStats.Builder(new String[]{"FOO"}, true) + .setBatteryCapacity(4000) .setDischargePercentage(20) .setDischargedPowerRange(1000, 2000) .setStatsStartTimestamp(1000); @@ -108,11 +142,22 @@ public class BatteryUsageStatsTest { .setUsageDurationForCustomComponentMillis( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20400); + builder.getOrCreateUserBatteryConsumerBuilder(42) + .setConsumedPower( + BatteryConsumer.POWER_COMPONENT_CPU, 10) + .setConsumedPowerForCustomComponent( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20) + .setUsageDurationMillis( + BatteryConsumer.POWER_COMPONENT_CPU, 30) + .setUsageDurationForCustomComponentMillis( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 40); + return builder.build(); } public void validateBatteryUsageStats(BatteryUsageStats batteryUsageStats) { assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(30000); + assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000); assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(20); assertThat(batteryUsageStats.getDischargedPowerRange().getLower()).isEqualTo(1000); assertThat(batteryUsageStats.getDischargedPowerRange().getUpper()).isEqualTo(2000); @@ -173,5 +218,26 @@ public class BatteryUsageStatsTest { assertThat(deviceBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); assertThat(deviceBatteryConsumer.getCustomPowerComponentName( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO"); + + final List userBatteryConsumers = + batteryUsageStats.getUserBatteryConsumers(); + for (UserBatteryConsumer userBatteryConsumer : userBatteryConsumers) { + if (userBatteryConsumer.getUserId() == 42) { + assertThat(userBatteryConsumer.getConsumedPower( + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10); + assertThat(userBatteryConsumer.getConsumedPowerForCustomComponent( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(20); + assertThat(userBatteryConsumer.getUsageDurationMillis( + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(30); + assertThat(userBatteryConsumer.getUsageDurationForCustomComponentMillis( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(40); + assertThat(userBatteryConsumer.getConsumedPower()).isEqualTo(30); + assertThat(userBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); + assertThat(userBatteryConsumer.getCustomPowerComponentName( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO"); + } else { + fail("Unexpected user ID " + userBatteryConsumer.getUserId()); + } + } } }