diff options
author | 2021-09-24 15:04:56 -0700 | |
---|---|---|
committer | 2021-10-13 15:46:48 -0700 | |
commit | 2198961ab1f7c1c922e4792d9f436ae8b87f88ef (patch) | |
tree | 87e715004e34f86da4a4e524dc0793340e5dafe9 | |
parent | b7278347224427a8b317bf4ec37ca3d50f967fc4 (diff) |
Add per-proc-state power components
Test: atest FrameworksCoreTests:BatteryStatsTests
atest BatteryUsageStatsProtoTests:BatteryUsageStatsPulledTest
Bug: 191921016
Change-Id: I698421a87766fcaef6569fd0ecfd1a44a9a3659f
11 files changed, 840 insertions, 236 deletions
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index 34f079a8982c..1c1fc2c96f86 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -26,6 +26,7 @@ import android.util.proto.ProtoOutputStream; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; /** * Interface for objects containing battery attribution data. @@ -43,6 +44,7 @@ public abstract class BatteryConsumer { * @hide */ @IntDef(prefix = {"POWER_COMPONENT_"}, value = { + POWER_COMPONENT_ANY, POWER_COMPONENT_SCREEN, POWER_COMPONENT_CPU, POWER_COMPONENT_BLUETOOTH, @@ -65,6 +67,7 @@ public abstract class BatteryConsumer { public static @interface PowerComponent { } + public static final int POWER_COMPONENT_ANY = -1; public static final int POWER_COMPONENT_SCREEN = OsProtoEnums.POWER_COMPONENT_SCREEN; // 0 public static final int POWER_COMPONENT_CPU = OsProtoEnums.POWER_COMPONENT_CPU; // 1 public static final int POWER_COMPONENT_BLUETOOTH = OsProtoEnums.POWER_COMPONENT_BLUETOOTH; // 2 @@ -151,9 +154,145 @@ public abstract class BatteryConsumer { */ public static final int POWER_MODEL_MEASURED_ENERGY = 2; + /** + * Identifiers of consumed power aggregations. + * + * @hide + */ + @IntDef(prefix = {"PROCESS_STATE_"}, value = { + PROCESS_STATE_ANY, + PROCESS_STATE_FOREGROUND, + PROCESS_STATE_BACKGROUND, + PROCESS_STATE_FOREGROUND_SERVICE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ProcessState { + } + + public static final int PROCESS_STATE_ANY = 0; + public static final int PROCESS_STATE_FOREGROUND = 1; + public static final int PROCESS_STATE_BACKGROUND = 2; + public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3; + + static final int PROCESS_STATE_COUNT = 4; + + private static final String[] sProcessStateNames = new String[PROCESS_STATE_COUNT]; + + static { + // Assign individually to avoid future mismatch + sProcessStateNames[PROCESS_STATE_ANY] = "any"; + sProcessStateNames[PROCESS_STATE_FOREGROUND] = "fg"; + sProcessStateNames[PROCESS_STATE_BACKGROUND] = "bg"; + sProcessStateNames[PROCESS_STATE_FOREGROUND_SERVICE] = "fgs"; + } + + private static final int[] SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE = { + POWER_COMPONENT_CPU, + }; + static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0; static final int COLUMN_COUNT = 1; + /** + * Identifies power attribution dimensions that a caller is interested in. + */ + public static final class Dimensions { + public final @PowerComponent int powerComponent; + public final @ProcessState int processState; + + public Dimensions(int powerComponent, int processState) { + this.powerComponent = powerComponent; + this.processState = processState; + } + + @Override + public String toString() { + boolean dimensionSpecified = false; + StringBuilder sb = new StringBuilder(); + if (powerComponent != POWER_COMPONENT_ANY) { + sb.append("powerComponent=").append(sPowerComponentNames[powerComponent]); + dimensionSpecified = true; + } + if (processState != PROCESS_STATE_ANY) { + if (dimensionSpecified) { + sb.append(", "); + } + sb.append("processState=").append(sProcessStateNames[processState]); + dimensionSpecified = true; + } + if (!dimensionSpecified) { + sb.append("any components and process states"); + } + return sb.toString(); + } + } + + public static final Dimensions UNSPECIFIED_DIMENSIONS = + new Dimensions(POWER_COMPONENT_ANY, PROCESS_STATE_ANY); + + /** + * Identifies power attribution dimensions that are captured by an data element of + * a BatteryConsumer. These Keys are used to access those values and to set them using + * Builders. See for example {@link #getConsumedPower(Key)}. + * + * Keys cannot be allocated by the client - they can only be obtained by calling + * {@link #getKeys} or {@link #getKey}. All BatteryConsumers that are part of the + * same BatteryUsageStats share the same set of keys, therefore it is safe to obtain + * the keys from one BatteryConsumer and apply them to other BatteryConsumers + * in the same BatteryUsageStats. + */ + public static final class Key { + public final @PowerComponent int powerComponent; + public final @ProcessState int processState; + + final int mPowerModelColumnIndex; + final int mPowerColumnIndex; + final int mDurationColumnIndex; + private String mShortString; + + private Key(int powerComponent, int processState, int powerModelColumnIndex, + int powerColumnIndex, int durationColumnIndex) { + this.powerComponent = powerComponent; + this.processState = processState; + + mPowerModelColumnIndex = powerModelColumnIndex; + mPowerColumnIndex = powerColumnIndex; + mDurationColumnIndex = durationColumnIndex; + } + + @SuppressWarnings("EqualsUnsafeCast") + @Override + public boolean equals(Object o) { + // Skipping null and class check for performance + final Key key = (Key) o; + return powerComponent == key.powerComponent + && processState == key.processState; + } + + @Override + public int hashCode() { + int result = powerComponent; + result = 31 * result + processState; + return result; + } + + /** + * Returns a string suitable for use in dumpsys. + */ + public String toShortString() { + if (mShortString == null) { + StringBuilder sb = new StringBuilder(); + sb.append(powerComponentIdToString(powerComponent)); + if (processState != PROCESS_STATE_ANY) { + sb.append(':'); + sb.append(processStateToString(processState)); + } + mShortString = sb.toString(); + } + return mShortString; + } + } + protected final BatteryConsumerData mData; protected final PowerComponents mPowerComponents; @@ -171,7 +310,37 @@ public abstract class BatteryConsumer { * Total power consumed by this consumer, in mAh. */ public double getConsumedPower() { - return mPowerComponents.getConsumedPower(); + return mPowerComponents.getConsumedPower(UNSPECIFIED_DIMENSIONS); + } + + /** + * Returns power consumed aggregated over the specified dimensions, in mAh. + */ + public double getConsumedPower(Dimensions dimensions) { + return mPowerComponents.getConsumedPower(dimensions); + } + + /** + * Returns keys for various power values attributed to the specified component + * held by this BatteryUsageStats object. + */ + public Key[] getKeys(@PowerComponent int componentId) { + return mData.getKeys(componentId); + } + + /** + * Returns the key for the power attributed to the specified component, + * for all values of other dimensions such as process state. + */ + public Key getKey(@PowerComponent int componentId) { + return mData.getKey(componentId, PROCESS_STATE_ANY); + } + + /** + * Returns the key for the power attributed to the specified component and process state. + */ + public Key getKey(@PowerComponent int componentId, @ProcessState int processState) { + return mData.getKey(componentId, processState); } /** @@ -182,7 +351,19 @@ public abstract class BatteryConsumer { * @return Amount of consumed power in mAh. */ public double getConsumedPower(@PowerComponent int componentId) { - return mPowerComponents.getConsumedPower(componentId); + return mPowerComponents.getConsumedPower( + mData.getKeyOrThrow(componentId, PROCESS_STATE_ANY)); + } + + /** + * Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. + * + * @param key The key of the power component, obtained by calling {@link #getKey} or + * {@link #getKeys} method. + * @return Amount of consumed power in mAh. + */ + public double getConsumedPower(@NonNull Key key) { + return mPowerComponents.getConsumedPower(key); } /** @@ -192,7 +373,18 @@ public abstract class BatteryConsumer { * {@link BatteryConsumer#POWER_COMPONENT_CPU}. */ public @PowerModel int getPowerModel(@BatteryConsumer.PowerComponent int componentId) { - return mPowerComponents.getPowerModel(componentId); + return mPowerComponents.getPowerModel( + mData.getKeyOrThrow(componentId, PROCESS_STATE_ANY)); + } + + /** + * Returns the ID of the model that was used for power estimation. + * + * @param key The key of the power component, obtained by calling {@link #getKey} or + * {@link #getKeys} method. + */ + public @PowerModel int getPowerModel(@NonNull BatteryConsumer.Key key) { + return mPowerComponents.getPowerModel(key); } /** @@ -227,7 +419,20 @@ public abstract class BatteryConsumer { * @return Amount of time in milliseconds. */ public long getUsageDurationMillis(@PowerComponent int componentId) { - return mPowerComponents.getUsageDurationMillis(componentId); + return mPowerComponents.getUsageDurationMillis(getKey(componentId)); + } + + /** + * Returns the amount of time since BatteryStats reset used by the specified component, e.g. + * CPU, WiFi etc. + * + * + * @param key The key of the power component, obtained by calling {@link #getKey} or + * {@link #getKeys} method. + * @return Amount of time in milliseconds. + */ + public long getUsageDurationMillis(@NonNull Key key) { + return mPowerComponents.getUsageDurationMillis(key); } /** @@ -245,6 +450,9 @@ public abstract class BatteryConsumer { * Returns the name of the specified component. Intended for logging and debugging. */ public static String powerComponentIdToString(@BatteryConsumer.PowerComponent int componentId) { + if (componentId == POWER_COMPONENT_ANY) { + return "all"; + } return sPowerComponentNames[componentId]; } @@ -263,6 +471,13 @@ public abstract class BatteryConsumer { } /** + * Returns the name of the specified process state. Intended for logging and debugging. + */ + public static String processStateToString(@BatteryConsumer.ProcessState int processState) { + return sProcessStateNames[processState]; + } + + /** * Prints the stats in a human-readable format. */ public void dump(PrintWriter pw) { @@ -347,6 +562,44 @@ public abstract class BatteryConsumer { return new BatteryConsumerData(cursorWindow, cursorRow, layout); } + public Key[] getKeys(int componentId) { + return layout.keys[componentId]; + } + + Key getKeyOrThrow(int componentId, int processState) { + Key key = getKey(componentId, processState); + if (key == null) { + if (processState == PROCESS_STATE_ANY) { + throw new IllegalArgumentException( + "Unsupported power component ID: " + componentId); + } else { + throw new IllegalArgumentException( + "Unsupported power component ID: " + componentId + + " process state: " + processState); + } + } + return key; + } + + Key getKey(int componentId, int processState) { + if (componentId >= POWER_COMPONENT_COUNT) { + return null; + } + + if (processState == PROCESS_STATE_ANY) { + // The 0-th key for each component corresponds to the roll-up, + // across all dimensions. We might as well skip the iteration over the array. + return layout.keys[componentId][0]; + } else { + for (Key key : layout.keys[componentId]) { + if (key.processState == processState) { + return key; + } + } + } + return null; + } + void putInt(int columnIndex, int value) { if (mCursorRow == -1) { return; @@ -405,59 +658,91 @@ public abstract class BatteryConsumer { } static class BatteryConsumerDataLayout { + private static final Key[] KEY_ARRAY = new Key[0]; public final String[] customPowerComponentNames; public final int customPowerComponentCount; public final boolean powerModelsIncluded; - - public final int consumedPowerColumn; - public final int firstConsumedPowerColumn; + public final boolean processStateDataIncluded; + public final Key[][] keys; + public final int totalConsumedPowerColumnIndex; public final int firstCustomConsumedPowerColumn; - public final int firstUsageDurationColumn; public final int firstCustomUsageDurationColumn; - public final int firstPowerModelColumn; public final int columnCount; private BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames, - boolean powerModelsIncluded) { + boolean powerModelsIncluded, boolean includeProcessStateData) { this.customPowerComponentNames = customPowerComponentNames; this.customPowerComponentCount = customPowerComponentNames.length; this.powerModelsIncluded = powerModelsIncluded; + this.processStateDataIncluded = includeProcessStateData; int columnIndex = firstColumn; - consumedPowerColumn = columnIndex++; - firstConsumedPowerColumn = columnIndex; - columnIndex += BatteryConsumer.POWER_COMPONENT_COUNT; + totalConsumedPowerColumnIndex = columnIndex++; + + keys = new Key[POWER_COMPONENT_COUNT][]; + + ArrayList<Key> perComponentKeys = new ArrayList<>(); + for (int componentId = 0; componentId < POWER_COMPONENT_COUNT; componentId++) { + perComponentKeys.clear(); + + // Declare the Key for the power component, ignoring other dimensions. + perComponentKeys.add( + new Key(componentId, PROCESS_STATE_ANY, + powerModelsIncluded ? columnIndex++ : -1, // power model + columnIndex++, // power + columnIndex++ // usage duration + )); + + // Declare Keys for all process states, if needed + if (includeProcessStateData) { + boolean isSupported = false; + for (int id : SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE) { + if (id == componentId) { + isSupported = true; + break; + } + } + if (isSupported) { + for (int processState = 0; processState < PROCESS_STATE_COUNT; + processState++) { + if (processState == PROCESS_STATE_ANY) { + continue; + } + + perComponentKeys.add( + new Key(componentId, processState, + powerModelsIncluded ? columnIndex++ : -1, // power model + columnIndex++, // power + columnIndex++ // usage duration + )); + } + } + } + + keys[componentId] = perComponentKeys.toArray(KEY_ARRAY); + } firstCustomConsumedPowerColumn = columnIndex; columnIndex += customPowerComponentCount; - firstUsageDurationColumn = columnIndex; - columnIndex += BatteryConsumer.POWER_COMPONENT_COUNT; - firstCustomUsageDurationColumn = columnIndex; columnIndex += customPowerComponentCount; - if (powerModelsIncluded) { - firstPowerModelColumn = columnIndex; - columnIndex += BatteryConsumer.POWER_COMPONENT_COUNT; - } else { - firstPowerModelColumn = -1; - } - columnCount = columnIndex; } } static BatteryConsumerDataLayout createBatteryConsumerDataLayout( - String[] customPowerComponentNames, boolean includePowerModels) { + String[] customPowerComponentNames, boolean includePowerModels, + boolean includeProcessStateData) { int columnCount = BatteryConsumer.COLUMN_COUNT; columnCount = Math.max(columnCount, AggregateBatteryConsumer.COLUMN_COUNT); columnCount = Math.max(columnCount, UidBatteryConsumer.COLUMN_COUNT); columnCount = Math.max(columnCount, UserBatteryConsumer.COLUMN_COUNT); return new BatteryConsumerDataLayout(columnCount, customPowerComponentNames, - includePowerModels); + includePowerModels, includeProcessStateData); } protected abstract static class BaseBuilder<T extends BaseBuilder<?>> { @@ -471,6 +756,11 @@ public abstract class BatteryConsumer { mPowerComponentsBuilder = new PowerComponents.Builder(data); } + @Nullable + public Key getKey(@PowerComponent int componentId, @ProcessState int processState) { + return mData.getKey(componentId, processState); + } + /** * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. * @@ -494,7 +784,15 @@ public abstract class BatteryConsumer { @NonNull public T setConsumedPower(@PowerComponent int componentId, double componentPower, @PowerModel int powerModel) { - mPowerComponentsBuilder.setConsumedPower(componentId, componentPower, powerModel); + mPowerComponentsBuilder.setConsumedPower(getKey(componentId, PROCESS_STATE_ANY), + componentPower, powerModel); + return (T) this; + } + + @SuppressWarnings("unchecked") + @NonNull + public T setConsumedPower(Key key, double componentPower, @PowerModel int powerModel) { + mPowerComponentsBuilder.setConsumedPower(key, componentPower, powerModel); return (T) this; } @@ -522,7 +820,16 @@ public abstract class BatteryConsumer { @NonNull public T setUsageDurationMillis(@UidBatteryConsumer.PowerComponent int componentId, long componentUsageTimeMillis) { - mPowerComponentsBuilder.setUsageDurationMillis(componentId, componentUsageTimeMillis); + mPowerComponentsBuilder.setUsageDurationMillis(getKey(componentId, PROCESS_STATE_ANY), + componentUsageTimeMillis); + return (T) this; + } + + + @SuppressWarnings("unchecked") + @NonNull + public T setUsageDurationMillis(Key key, long componentUsageTimeMillis) { + mPowerComponentsBuilder.setUsageDurationMillis(key, componentUsageTimeMillis); return (T) this; } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index dd387dadd4dd..ce6421b1db8e 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -654,6 +654,11 @@ public abstract class BatteryStats implements Parcelable { } /** + * Returns true if battery consumption is tracked on a per-process-state basis. + */ + public abstract boolean isProcessStateDataAvailable(); + + /** * The statistics associated with a particular uid. */ public static abstract class Uid { @@ -5309,6 +5314,7 @@ public abstract class BatteryStats implements Parcelable { new BatteryUsageStatsQuery.Builder() .setMaxStatsAgeMs(0) .includePowerModels() + .includeProcessStateData() .build()); stats.dump(pw, prefix); diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index d37c0eb5f1d2..ed44fb62ee79 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -98,8 +98,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable { static final String XML_ATTR_USER_ID = "user_id"; static final String XML_ATTR_SCOPE = "scope"; static final String XML_ATTR_PREFIX_CUSTOM_COMPONENT = "custom_component_"; + static final String XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA = "includes_proc_state_data"; static final String XML_ATTR_START_TIMESTAMP = "start_timestamp"; static final String XML_ATTR_END_TIMESTAMP = "end_timestamp"; + static final String XML_ATTR_PROCESS_STATE = "process_state"; static final String XML_ATTR_POWER = "power"; static final String XML_ATTR_DURATION = "duration"; static final String XML_ATTR_MODEL = "model"; @@ -129,6 +131,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { private final long mChargeTimeRemainingMs; private final String[] mCustomPowerComponentNames; private final boolean mIncludesPowerModels; + private final boolean mIncludesProcessStateData; private final List<UidBatteryConsumer> mUidBatteryConsumers; private final List<UserBatteryConsumer> mUserBatteryConsumers; private final AggregateBatteryConsumer[] mAggregateBatteryConsumers; @@ -148,6 +151,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs; mCustomPowerComponentNames = builder.mCustomPowerComponentNames; mIncludesPowerModels = builder.mIncludePowerModels; + mIncludesProcessStateData = builder.mIncludesProcessStateData; mBatteryConsumersCursorWindow = builder.mBatteryConsumersCursorWindow; double totalPowerMah = 0; @@ -288,6 +292,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable { return mCustomPowerComponentNames; } + public boolean isProcessStateDataIncluded() { + return mIncludesProcessStateData; + } + /** * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s. */ @@ -317,11 +325,12 @@ public final class BatteryUsageStats implements Parcelable, Closeable { mChargeTimeRemainingMs = source.readLong(); mCustomPowerComponentNames = source.readStringArray(); mIncludesPowerModels = source.readBoolean(); + mIncludesProcessStateData = source.readBoolean(); mBatteryConsumersCursorWindow = CursorWindow.newFromParcel(source); BatteryConsumer.BatteryConsumerDataLayout dataLayout = BatteryConsumer.createBatteryConsumerDataLayout(mCustomPowerComponentNames, - mIncludesPowerModels); + mIncludesPowerModels, mIncludesProcessStateData); final int numRows = mBatteryConsumersCursorWindow.getNumRows(); @@ -376,6 +385,8 @@ public final class BatteryUsageStats implements Parcelable, Closeable { dest.writeLong(mChargeTimeRemainingMs); dest.writeStringArray(mCustomPowerComponentNames); dest.writeBoolean(mIncludesPowerModels); + dest.writeBoolean(mIncludesProcessStateData); + mBatteryConsumersCursorWindow.writeToParcel(dest, flags); if (mHistoryBuffer != null) { @@ -537,16 +548,22 @@ public final class BatteryUsageStats implements Parcelable, Closeable { 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; - } + for (BatteryConsumer.Key key : deviceConsumer.getKeys(componentId)) { + final double devicePowerMah = deviceConsumer.getConsumedPower(key); + final double appsPowerMah = appsConsumer.getConsumedPower(key); + if (devicePowerMah == 0 && appsPowerMah == 0) { + continue; + } - final String componentName = BatteryConsumer.powerComponentIdToString(componentId); - printPowerComponent(pw, prefix, componentName, devicePowerMah, appsPowerMah, - deviceConsumer.getPowerModel(componentId), - deviceConsumer.getUsageDurationMillis(componentId)); + String label = BatteryConsumer.powerComponentIdToString(componentId); + if (key.processState != BatteryConsumer.PROCESS_STATE_ANY) { + label = label + + "(" + BatteryConsumer.processStateToString(key.processState) + ")"; + } + printPowerComponent(pw, prefix, label, devicePowerMah, appsPowerMah, + deviceConsumer.getPowerModel(key), + deviceConsumer.getUsageDurationMillis(key)); + } } for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID; @@ -571,10 +588,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable { dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers()); } - private void printPowerComponent(PrintWriter pw, String prefix, String componentName, + private void printPowerComponent(PrintWriter pw, String prefix, String label, double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) { StringBuilder sb = new StringBuilder(); - sb.append(prefix).append(" ").append(componentName).append(": ") + sb.append(prefix).append(" ").append(label).append(": ") .append(PowerCalculator.formatCharge(devicePowerMah)); if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) { @@ -615,7 +632,8 @@ public final class BatteryUsageStats implements Parcelable, Closeable { serializer.attribute(null, XML_ATTR_PREFIX_CUSTOM_COMPONENT + i, mCustomPowerComponentNames[i]); } - + serializer.attributeBoolean(null, XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA, + mIncludesProcessStateData); serializer.attributeLong(null, XML_ATTR_START_TIMESTAMP, mStatsStartTimestampMs); serializer.attributeLong(null, XML_ATTR_END_TIMESTAMP, mStatsEndTimestampMs); serializer.attributeLong(null, XML_ATTR_DURATION, mStatsDurationMs); @@ -659,7 +677,11 @@ public final class BatteryUsageStats implements Parcelable, Closeable { i++; } - builder = new Builder(customComponentNames.toArray(new String[0]), true); + final boolean includesProcStateData = parser.getAttributeBoolean(null, + XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA, false); + + builder = new Builder(customComponentNames.toArray(new String[0]), true, + includesProcStateData); builder.setStatsStartTimestamp( parser.getAttributeLong(null, XML_ATTR_START_TIMESTAMP)); @@ -731,6 +753,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable { @NonNull private final String[] mCustomPowerComponentNames; private final boolean mIncludePowerModels; + private final boolean mIncludesProcessStateData; private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout; private long mStatsStartTimestampMs; private long mStatsEndTimestampMs; @@ -750,19 +773,21 @@ public final class BatteryUsageStats implements Parcelable, Closeable { private Parcel mHistoryBuffer; public Builder(@NonNull String[] customPowerComponentNames) { - this(customPowerComponentNames, false); + this(customPowerComponentNames, false, false); } - public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) { + public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels, + boolean includeProcessStateData) { mBatteryConsumersCursorWindow = new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE); mBatteryConsumerDataLayout = BatteryConsumer.createBatteryConsumerDataLayout(customPowerComponentNames, - includePowerModels); + includePowerModels, includeProcessStateData); mBatteryConsumersCursorWindow.setNumColumns(mBatteryConsumerDataLayout.columnCount); mCustomPowerComponentNames = customPowerComponentNames; mIncludePowerModels = includePowerModels; + mIncludesProcessStateData = includeProcessStateData; for (int scope = 0; scope < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; scope++) { final BatteryConsumer.BatteryConsumerData data = BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow, @@ -772,6 +797,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable { } } + public boolean isProcessStateDataNeeded() { + return mIncludesProcessStateData; + } + /** * Constructs a read-only object using the Builder values. */ @@ -954,6 +983,11 @@ public final class BatteryUsageStats implements Parcelable, Closeable { "BatteryUsageStats have different custom power components"); } + if (mIncludesProcessStateData && !stats.mIncludesProcessStateData) { + throw new IllegalArgumentException( + "Added BatteryUsageStats does not include process state data"); + } + if (mUserBatteryConsumerBuilders.size() != 0 || !stats.getUserBatteryConsumers().isEmpty()) { throw new UnsupportedOperationException( diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java index 97f24ccecaee..187b64f05a0c 100644 --- a/core/java/android/os/BatteryUsageStatsQuery.java +++ b/core/java/android/os/BatteryUsageStatsQuery.java @@ -41,6 +41,7 @@ public final class BatteryUsageStatsQuery implements Parcelable { @IntDef(flag = true, prefix = { "FLAG_BATTERY_USAGE_STATS_" }, value = { FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL, FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY, + FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA, }) @Retention(RetentionPolicy.SOURCE) public @interface BatteryUsageStatsFlags {} @@ -52,19 +53,21 @@ public final class BatteryUsageStatsQuery implements Parcelable { * * @hide */ - public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 1; + public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 0x0001; /** * Indicates that battery history should be included in the BatteryUsageStats. * @hide */ - public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2; + public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 0x0002; /** * Indicates that identifiers of power models used for computations of power * consumption should be included in the BatteryUsageStats. */ - public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS = 4; + public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS = 0x0004; + + public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA = 0x0008; private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000; @@ -209,6 +212,16 @@ public final class BatteryUsageStatsQuery implements Parcelable { } /** + * Requests that per-process state data be included in the BatteryUsageStats, if + * available. Check {@link BatteryUsageStats#isProcessStateDataIncluded()} on the result + * to see if the data is available. + */ + public Builder includeProcessStateData() { + mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA; + return this; + } + + /** * Requests to return modeled battery usage stats only, even if on-device * power monitoring data is available. * diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java index 259e6739b23a..4b12aa6a2634 100644 --- a/core/java/android/os/PowerComponents.java +++ b/core/java/android/os/PowerComponents.java @@ -15,6 +15,9 @@ */ package android.os; +import static android.os.BatteryConsumer.POWER_COMPONENT_ANY; +import static android.os.BatteryConsumer.POWER_COMPONENT_COUNT; +import static android.os.BatteryConsumer.PROCESS_STATE_ANY; import static android.os.BatteryConsumer.convertMahToDeciCoulombs; import android.annotation.NonNull; @@ -49,25 +52,41 @@ class PowerComponents { } /** - * Total power consumed by this consumer, in mAh. + * Total power consumed by this consumer, aggregated over the specified dimensions, in mAh. */ - public double getConsumedPower() { - return mData.getDouble(mData.layout.consumedPowerColumn); + public double getConsumedPower(@NonNull BatteryConsumer.Dimensions dimensions) { + if (dimensions.powerComponent != POWER_COMPONENT_ANY) { + return mData.getDouble(mData.getKeyOrThrow(dimensions.powerComponent, + dimensions.processState).mPowerColumnIndex); + } else if (dimensions.processState != PROCESS_STATE_ANY) { + boolean foundSome = false; + double totalPowerMah = 0; + for (int componentId = 0; componentId < POWER_COMPONENT_COUNT; componentId++) { + BatteryConsumer.Key key = mData.getKey(componentId, dimensions.processState); + if (key != null) { + foundSome = true; + totalPowerMah += mData.getDouble(key.mPowerColumnIndex); + } + } + if (!foundSome) { + throw new IllegalArgumentException( + "No data included in BatteryUsageStats for " + dimensions); + } + return totalPowerMah; + } else { + return mData.getDouble(mData.layout.totalConsumedPowerColumnIndex); + } } /** * Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. * - * @param componentId The ID of the power component, e.g. - * {@link BatteryConsumer#POWER_COMPONENT_CPU}. + * @param key The key of the power component, obtained by calling {@link BatteryConsumer#getKey} + * or {@link BatteryConsumer#getKeys} method. * @return Amount of consumed power in mAh. */ - public double getConsumedPower(@BatteryConsumer.PowerComponent int componentId) { - if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) { - throw new IllegalArgumentException( - "Unsupported power component ID: " + componentId); - } - return mData.getDouble(mData.layout.firstConsumedPowerColumn + componentId); + public double getConsumedPower(@NonNull BatteryConsumer.Key key) { + return mData.getDouble(key.mPowerColumnIndex); } /** @@ -102,27 +121,23 @@ class PowerComponents { } @BatteryConsumer.PowerModel - int getPowerModel(@BatteryConsumer.PowerComponent int componentId) { - if (!mData.layout.powerModelsIncluded) { + int getPowerModel(BatteryConsumer.Key key) { + if (key.mPowerModelColumnIndex == -1) { throw new IllegalStateException( "Power model IDs were not requested in the BatteryUsageStatsQuery"); } - return mData.getInt(mData.layout.firstPowerModelColumn + componentId); + return mData.getInt(key.mPowerModelColumnIndex); } /** * Returns the amount of time used by the specified component, e.g. CPU, WiFi etc. * - * @param componentId The ID of the power component, e.g. - * {@link BatteryConsumer#POWER_COMPONENT_CPU}. + * @param key The key of the power component, obtained by calling {@link BatteryConsumer#getKey} + * or {@link BatteryConsumer#getKeys} method. * @return Amount of time in milliseconds. */ - public long getUsageDurationMillis(@BatteryConsumer.PowerComponent int componentId) { - if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) { - throw new IllegalArgumentException( - "Unsupported power component ID: " + componentId); - } - return mData.getLong(mData.layout.firstUsageDurationColumn + componentId); + public long getUsageDurationMillis(BatteryConsumer.Key key) { + return mData.getLong(key.mDurationColumnIndex); } /** @@ -143,17 +158,29 @@ class PowerComponents { public void dump(PrintWriter pw, boolean skipEmptyComponents) { String separator = ""; + StringBuilder sb = new StringBuilder(); + for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; componentId++) { - final double componentPower = getConsumedPower(componentId); - if (skipEmptyComponents && componentPower == 0) { - continue; + for (BatteryConsumer.Key key: mData.getKeys(componentId)) { + final double componentPower = getConsumedPower(key); + final long durationMs = getUsageDurationMillis(key); + if (skipEmptyComponents && componentPower == 0 && durationMs == 0) { + continue; + } + + sb.append(separator); + separator = " "; + sb.append(key.toShortString()); + sb.append("="); + sb.append(PowerCalculator.formatCharge(componentPower)); + + if (durationMs != 0) { + sb.append(" ("); + BatteryStats.formatTimeMsNoSpace(sb, durationMs); + sb.append(")"); + } } - pw.print(separator); - separator = " "; - pw.print(BatteryConsumer.powerComponentIdToString(componentId)); - pw.print("="); - PowerCalculator.printPowerMah(pw, componentPower); } final int customComponentCount = mData.layout.customPowerComponentCount; @@ -166,12 +193,14 @@ class PowerComponents { if (skipEmptyComponents && customComponentPower == 0) { continue; } - pw.print(separator); + sb.append(separator); separator = " "; - pw.print(getCustomPowerComponentName(customComponentId)); - pw.print("="); - PowerCalculator.printPowerMah(pw, customComponentPower); + sb.append(getCustomPowerComponentName(customComponentId)); + sb.append("="); + sb.append(PowerCalculator.formatCharge(customComponentPower)); } + + pw.print(sb); } /** Returns whether there are any atoms.proto POWER_COMPONENTS data to write to a proto. */ @@ -193,8 +222,10 @@ class PowerComponents { for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; componentId++) { - final long powerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower(componentId)); - final long durationMs = getUsageDurationMillis(componentId); + + final BatteryConsumer.Key key = mData.getKey(componentId, PROCESS_STATE_ANY); + final long powerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower(key)); + final long durationMs = getUsageDurationMillis(key); if (powerDeciCoulombs == 0 && durationMs == 0) { // No interesting data. Make sure not to even write the COMPONENT int. @@ -254,25 +285,32 @@ class PowerComponents { serializer.startTag(null, BatteryUsageStats.XML_TAG_POWER_COMPONENTS); for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; componentId++) { - final double powerMah = getConsumedPower(componentId); - final long durationMs = getUsageDurationMillis(componentId); - if (powerMah == 0 && durationMs == 0) { - continue; - } + final BatteryConsumer.Key[] keys = mData.getKeys(componentId); + for (BatteryConsumer.Key key : keys) { + final double powerMah = getConsumedPower(key); + final long durationMs = getUsageDurationMillis(key); + if (powerMah == 0 && durationMs == 0) { + continue; + } - serializer.startTag(null, BatteryUsageStats.XML_TAG_COMPONENT); - serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_ID, componentId); - if (powerMah != 0) { - serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, powerMah); - } - if (durationMs != 0) { - serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs); - } - if (mData.layout.powerModelsIncluded) { - serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_MODEL, - getPowerModel(componentId)); + serializer.startTag(null, BatteryUsageStats.XML_TAG_COMPONENT); + serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_ID, componentId); + if (key.processState != PROCESS_STATE_ANY) { + serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_PROCESS_STATE, + key.processState); + } + if (powerMah != 0) { + serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, powerMah); + } + if (durationMs != 0) { + serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs); + } + if (mData.layout.powerModelsIncluded) { + serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_MODEL, + getPowerModel(key)); + } + serializer.endTag(null, BatteryUsageStats.XML_TAG_COMPONENT); } - serializer.endTag(null, BatteryUsageStats.XML_TAG_COMPONENT); } final int customComponentEnd = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID @@ -316,6 +354,7 @@ class PowerComponents { switch (parser.getName()) { case BatteryUsageStats.XML_TAG_COMPONENT: { int componentId = -1; + int processState = PROCESS_STATE_ANY; double powerMah = 0; long durationMs = 0; int model = BatteryConsumer.POWER_MODEL_UNDEFINED; @@ -324,6 +363,9 @@ class PowerComponents { case BatteryUsageStats.XML_ATTR_ID: componentId = parser.getAttributeInt(i); break; + case BatteryUsageStats.XML_ATTR_PROCESS_STATE: + processState = parser.getAttributeInt(i); + break; case BatteryUsageStats.XML_ATTR_POWER: powerMah = parser.getAttributeDouble(i); break; @@ -335,8 +377,10 @@ class PowerComponents { break; } } - builder.setConsumedPower(componentId, powerMah, model); - builder.setUsageDurationMillis(componentId, durationMs); + final BatteryConsumer.Key key = + builder.mData.getKey(componentId, processState); + builder.setConsumedPower(key, powerMah, model); + builder.setUsageDurationMillis(key, durationMs); break; } case BatteryUsageStats.XML_TAG_CUSTOM_COMPONENT: { @@ -376,33 +420,22 @@ class PowerComponents { Builder(BatteryConsumer.BatteryConsumerData data) { mData = data; - if (mData.layout.powerModelsIncluded) { - for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) { - mData.putLong(mData.layout.firstPowerModelColumn + i, - POWER_MODEL_UNINITIALIZED); + for (BatteryConsumer.Key[] keys : mData.layout.keys) { + for (BatteryConsumer.Key key : keys) { + if (key.mPowerModelColumnIndex != -1) { + mData.putInt(key.mPowerModelColumnIndex, POWER_MODEL_UNINITIALIZED); + } } } } - /** - * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc. - * - * @param componentId The ID of the power component, e.g. - * {@link BatteryConsumer#POWER_COMPONENT_CPU}. - * @param componentPower Amount of consumed power in mAh. - */ @NonNull - public Builder setConsumedPower(@BatteryConsumer.PowerComponent int componentId, - double componentPower, @BatteryConsumer.PowerModel int powerModel) { - if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) { - throw new IllegalArgumentException( - "Unsupported power component ID: " + componentId); - } - mData.putDouble(mData.layout.firstConsumedPowerColumn + componentId, componentPower); - if (mData.layout.powerModelsIncluded) { - mData.putLong(mData.layout.firstPowerModelColumn + componentId, powerModel); + public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower, + int powerModel) { + mData.putDouble(key.mPowerColumnIndex, componentPower); + if (key.mPowerModelColumnIndex != -1) { + mData.putInt(key.mPowerModelColumnIndex, powerModel); } - return this; } @@ -423,22 +456,10 @@ class PowerComponents { return this; } - /** - * Sets the amount of time used by the specified component, e.g. CPU, WiFi etc. - * - * @param componentId The ID of the power component, e.g. - * {@link BatteryConsumer#POWER_COMPONENT_CPU}. - * @param componentUsageDurationMillis Amount of time in milliseconds. - */ @NonNull - public Builder setUsageDurationMillis(@BatteryConsumer.PowerComponent int componentId, + public Builder setUsageDurationMillis(BatteryConsumer.Key key, long componentUsageDurationMillis) { - if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) { - throw new IllegalArgumentException( - "Unsupported power component ID: " + componentId); - } - mData.putLong(mData.layout.firstUsageDurationColumn + componentId, - componentUsageDurationMillis); + mData.putLong(key.mDurationColumnIndex, componentUsageDurationMillis); return this; } @@ -474,47 +495,75 @@ class PowerComponents { if (mData.layout.customPowerComponentCount != otherData.layout.customPowerComponentCount) { throw new IllegalArgumentException( - "Number of power components does not match: " + "Number of custom power components does not match: " + otherData.layout.customPowerComponentCount + ", expected: " + mData.layout.customPowerComponentCount); } - for (int i = BatteryConsumer.POWER_COMPONENT_COUNT - 1; i >= 0; i--) { - final int powerColumnIndex = mData.layout.firstConsumedPowerColumn + i; - mData.putDouble(powerColumnIndex, - mData.getDouble(powerColumnIndex) - + otherData.getDouble(powerColumnIndex)); + for (int componentId = BatteryConsumer.POWER_COMPONENT_COUNT - 1; componentId >= 0; + componentId--) { + final BatteryConsumer.Key[] keys = mData.layout.keys[componentId]; + for (BatteryConsumer.Key key: keys) { + BatteryConsumer.Key otherKey = null; + for (BatteryConsumer.Key aKey: otherData.layout.keys[componentId]) { + if (aKey.equals(key)) { + otherKey = aKey; + break; + } + } - final int durationColumnIndex = mData.layout.firstUsageDurationColumn + i; - mData.putLong(durationColumnIndex, - mData.getLong(durationColumnIndex) - + otherData.getLong(durationColumnIndex)); + if (otherKey == null) { + continue; + } + + mData.putDouble(key.mPowerColumnIndex, + mData.getDouble(key.mPowerColumnIndex) + + otherData.getDouble(otherKey.mPowerColumnIndex)); + mData.putLong(key.mDurationColumnIndex, + mData.getLong(key.mDurationColumnIndex) + + otherData.getLong(otherKey.mDurationColumnIndex)); + + if (key.mPowerModelColumnIndex == -1) { + continue; + } + + boolean undefined = false; + if (otherKey.mPowerModelColumnIndex == -1) { + undefined = true; + } else { + final int powerModel = mData.getInt(key.mPowerModelColumnIndex); + int otherPowerModel = otherData.getInt(otherKey.mPowerModelColumnIndex); + if (powerModel == POWER_MODEL_UNINITIALIZED) { + mData.putInt(key.mPowerModelColumnIndex, otherPowerModel); + } else if (powerModel != otherPowerModel + && otherPowerModel != POWER_MODEL_UNINITIALIZED) { + undefined = true; + } + } + + if (undefined) { + mData.putInt(key.mPowerModelColumnIndex, + BatteryConsumer.POWER_MODEL_UNDEFINED); + } + } } for (int i = mData.layout.customPowerComponentCount - 1; i >= 0; i--) { final int powerColumnIndex = mData.layout.firstCustomConsumedPowerColumn + i; + final int otherPowerColumnIndex = + otherData.layout.firstCustomConsumedPowerColumn + i; mData.putDouble(powerColumnIndex, - mData.getDouble(powerColumnIndex) + otherData.getDouble(powerColumnIndex)); + mData.getDouble(powerColumnIndex) + otherData.getDouble( + otherPowerColumnIndex)); final int usageColumnIndex = mData.layout.firstCustomUsageDurationColumn + i; + final int otherDurationColumnIndex = + otherData.layout.firstCustomUsageDurationColumn + i; mData.putLong(usageColumnIndex, - mData.getLong(usageColumnIndex) + otherData.getLong(usageColumnIndex) + mData.getLong(usageColumnIndex) + otherData.getLong( + otherDurationColumnIndex) ); } - - if (mData.layout.powerModelsIncluded && otherData.layout.powerModelsIncluded) { - for (int i = BatteryConsumer.POWER_COMPONENT_COUNT - 1; i >= 0; i--) { - final int columnIndex = mData.layout.firstPowerModelColumn + i; - int powerModel = mData.getInt(columnIndex); - int otherPowerModel = otherData.getInt(columnIndex); - if (powerModel == POWER_MODEL_UNINITIALIZED) { - mData.putLong(columnIndex, otherPowerModel); - } else if (powerModel != otherPowerModel - && otherPowerModel != POWER_MODEL_UNINITIALIZED) { - mData.putLong(columnIndex, BatteryConsumer.POWER_MODEL_UNDEFINED); - } - } - } } /** @@ -525,11 +574,12 @@ class PowerComponents { double totalPowerMah = 0; for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT; componentId++) { - totalPowerMah += - mData.getDouble(mData.layout.firstConsumedPowerColumn + componentId); + totalPowerMah += mData.getDouble( + mData.getKeyOrThrow(componentId, PROCESS_STATE_ANY).mPowerColumnIndex); } for (int i = 0; i < mData.layout.customPowerComponentCount; i++) { - totalPowerMah += mData.getDouble(mData.layout.firstCustomConsumedPowerColumn + i); + totalPowerMah += mData.getDouble( + mData.layout.firstCustomConsumedPowerColumn + i); } return totalPowerMah; } @@ -539,14 +589,15 @@ class PowerComponents { */ @NonNull public PowerComponents build() { - mData.putDouble(mData.layout.consumedPowerColumn, getTotalPower()); - - if (mData.layout.powerModelsIncluded) { - for (int i = BatteryConsumer.POWER_COMPONENT_COUNT - 1; i >= 0; i--) { - final int powerModel = mData.getInt(mData.layout.firstPowerModelColumn + i); - if (powerModel == POWER_MODEL_UNINITIALIZED) { - mData.putInt(mData.layout.firstPowerModelColumn + i, - BatteryConsumer.POWER_MODEL_UNDEFINED); + mData.putDouble(mData.layout.totalConsumedPowerColumnIndex, getTotalPower()); + + for (BatteryConsumer.Key[] keys : mData.layout.keys) { + for (BatteryConsumer.Key key : keys) { + if (key.mPowerModelColumnIndex != -1) { + if (mData.getInt(key.mPowerModelColumnIndex) == POWER_MODEL_UNINITIALIZED) { + mData.putInt(key.mPowerModelColumnIndex, + BatteryConsumer.POWER_MODEL_UNDEFINED); + } } } } diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java index f9f44631a015..1a082d103127 100644 --- a/core/java/android/os/UidBatteryConsumer.java +++ b/core/java/android/os/UidBatteryConsumer.java @@ -106,16 +106,39 @@ public final class UidBatteryConsumer extends BatteryConsumer { @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); + PowerCalculator.printPowerMah(pw, getConsumedPower()); + + if (mData.layout.processStateDataIncluded) { + StringBuilder sb = new StringBuilder(); + appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_FOREGROUND, + skipEmptyComponents); + appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_BACKGROUND, + skipEmptyComponents); + appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, + skipEmptyComponents); + pw.print(sb); + } + pw.print(" ( "); mPowerComponents.dump(pw, skipEmptyComponents /* skipTotalPowerComponent */); pw.print(" ) "); } + private void appendProcessStateData(StringBuilder sb, @ProcessState int processState, + boolean skipEmptyComponents) { + Dimensions dimensions = new Dimensions(POWER_COMPONENT_ANY, processState); + final double power = mPowerComponents.getConsumedPower(dimensions); + if (power == 0 && skipEmptyComponents) { + return; + } + + sb.append(" ").append(processStateToString(processState)).append(": ") + .append(PowerCalculator.formatCharge(power)); + } + static UidBatteryConsumer create(BatteryConsumerData data) { return new UidBatteryConsumer(data); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 63cce0a94052..78d73b9ca69f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -14769,6 +14769,11 @@ public class BatteryStatsImpl extends BatteryStats { mShuttingDown = true; } + @Override + public boolean isProcessStateDataAvailable() { + return trackPerProcStateCpuTimes(); + } + public boolean trackPerProcStateCpuTimes() { return mConstants.TRACK_CPU_TIMES_BY_PROC_STATE && mPerProcStateCpuTimesAvailable; } diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 615ab6367c30..88425be84313 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -152,9 +152,13 @@ public class BatteryUsageStatsProvider { final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; + final boolean includeProcessStateData = ((query.getFlags() + & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0) + && mStats.isProcessStateDataAvailable(); final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder( - mStats.getCustomEnergyConsumerNames(), includePowerModels); + mStats.getCustomEnergyConsumerNames(), includePowerModels, + includeProcessStateData); // TODO(b/188068523): use a monotonic clock to ensure resilience of order and duration // of stats sessions to wall-clock adjustments batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime()); @@ -224,10 +228,13 @@ public class BatteryUsageStatsProvider { private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryUsageStatsQuery query) { final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; + final boolean includeProcessStateData = ((query.getFlags() + & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0) + && mStats.isProcessStateDataAvailable(); final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames(); final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( - customEnergyConsumerNames, includePowerModels); + customEnergyConsumerNames, includePowerModels, includeProcessStateData); if (mBatteryUsageStatsStore == null) { Log.e(TAG, "BatteryUsageStatsStore is unavailable"); return builder.build(); @@ -238,16 +245,25 @@ public class BatteryUsageStatsProvider { if (timestamp > query.getFromTimestamp() && timestamp <= query.getToTimestamp()) { final BatteryUsageStats snapshot = mBatteryUsageStatsStore.loadBatteryUsageStats(timestamp); - if (snapshot != null) { - if (Arrays.equals(snapshot.getCustomPowerComponentNames(), - customEnergyConsumerNames)) { - builder.add(snapshot); - } else { - Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different " - + "custom power components: " - + Arrays.toString(snapshot.getCustomPowerComponentNames())); - } + if (snapshot == null) { + continue; } + + if (!Arrays.equals(snapshot.getCustomPowerComponentNames(), + customEnergyConsumerNames)) { + Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different " + + "custom power components: " + + Arrays.toString(snapshot.getCustomPowerComponentNames())); + continue; + } + + if (includeProcessStateData && !snapshot.isProcessStateDataIncluded()) { + Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which " + + " does not include process state data"); + continue; + } + + builder.add(snapshot); } } return builder.build(); 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 e7fa6566f16f..5d3d4963177a 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -183,8 +183,10 @@ public class BatteryUsageStatsRule implements TestRule { final String[] customPowerComponentNames = mBatteryStats.getCustomEnergyConsumerNames(); final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; + final boolean includeProcessStateData = (query.getFlags() + & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0; BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( - customPowerComponentNames, includePowerModels); + customPowerComponentNames, includePowerModels, includeProcessStateData); SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats(); for (int i = 0; i < uidStats.size(); i++) { builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i)); 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 b44de3b62398..4733f862ebba 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java @@ -16,9 +16,12 @@ package com.android.internal.os; +import static android.os.BatteryConsumer.POWER_COMPONENT_ANY; import static android.os.BatteryConsumer.POWER_MODEL_MEASURED_ENERGY; -import static android.os.BatteryConsumer.POWER_MODEL_POWER_PROFILE; import static android.os.BatteryConsumer.POWER_MODEL_UNDEFINED; +import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND; +import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND; +import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE; import static com.google.common.truth.Truth.assertThat; @@ -27,6 +30,7 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.os.AggregateBatteryConsumer; import android.os.BatteryConsumer; import android.os.BatteryUsageStats; import android.os.Parcel; @@ -68,6 +72,12 @@ public class BatteryUsageStatsTest { } @Test + public void testBuilder_noProcessStateData() { + BatteryUsageStats batteryUsageStats = buildBatteryUsageStats1(false).build(); + assertBatteryUsageStats1(batteryUsageStats, false); + } + + @Test public void testParcelability_smallNumberOfUids() { final BatteryUsageStats outBatteryUsageStats = buildBatteryUsageStats1(true).build(); final Parcel parcel = Parcel.obtain(); @@ -142,9 +152,14 @@ public class BatteryUsageStatsTest { 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("cpu(fg): 2333 apps: 1333 duration: 3s 332ms"); + assertThat(dump).contains("cpu(bg): 2444 apps: 1444 duration: 4s 442ms"); + assertThat(dump).contains("cpu(fgs): 2555 apps: 1555 duration: 5s 552ms"); assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms"); - assertThat(dump).contains("UID 271: 1200 ( screen=300 cpu=400 FOO=500 )"); - assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 FOO=20.0 )"); + assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 ( screen=300 " + + "cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) " + + "cpu:fgs=1999 (9s 991ms) FOO=500 )"); + assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 (30ms) FOO=20.0 )"); } @Test @@ -160,10 +175,10 @@ public class BatteryUsageStatsTest { @Test public void testAdd() { final BatteryUsageStats stats1 = buildBatteryUsageStats1(false).build(); - final BatteryUsageStats stats2 = buildBatteryUsageStats2(new String[] {"FOO"}).build(); + final BatteryUsageStats stats2 = buildBatteryUsageStats2(new String[]{"FOO"}, true).build(); final BatteryUsageStats sum = - new BatteryUsageStats.Builder(new String[] {"FOO"}, true) + new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true) .add(stats1) .add(stats2) .build(); @@ -175,12 +190,16 @@ public class BatteryUsageStatsTest { for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) { if (uidBatteryConsumer.getUid() == APP_UID1) { assertUidBatteryConsumer(uidBatteryConsumer, 2124, null, - 5321, 7432, 423, POWER_MODEL_POWER_PROFILE, 745, POWER_MODEL_UNDEFINED, - 956, 1167, 1478); + 5321, 7432, 423, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 745, + POWER_MODEL_UNDEFINED, + 956, 1167, 1478, + true, 3554, 3776, 3998, 3554, 15542, 3776, 17762, 3998, 19982); } else if (uidBatteryConsumer.getUid() == APP_UID2) { assertUidBatteryConsumer(uidBatteryConsumer, 1332, "bar", - 1111, 2222, 333, POWER_MODEL_POWER_PROFILE, 444, POWER_MODEL_POWER_PROFILE, - 555, 666, 777); + 1111, 2222, 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444, + BatteryConsumer.POWER_MODEL_POWER_PROFILE, + 555, 666, 777, + true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991); } else { fail("Unexpected UID " + uidBatteryConsumer.getUid()); } @@ -198,8 +217,17 @@ public class BatteryUsageStatsTest { @Test public void testAdd_customComponentMismatch() { final BatteryUsageStats.Builder builder = - new BatteryUsageStats.Builder(new String[] {"FOO"}, true); - final BatteryUsageStats stats = buildBatteryUsageStats2(new String[] {"BAR"}).build(); + new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true); + final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"BAR"}, false).build(); + + assertThrows(IllegalArgumentException.class, () -> builder.add(stats)); + } + + @Test + public void testAdd_processStateDataMismatch() { + final BatteryUsageStats.Builder builder = + new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true); + final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"FOO"}, false).build(); assertThrows(IllegalArgumentException.class, () -> builder.add(stats)); } @@ -227,7 +255,7 @@ public class BatteryUsageStatsTest { final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks); final BatteryUsageStats.Builder builder = - new BatteryUsageStats.Builder(new String[] {"FOO"}, true) + new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true) .setBatteryCapacity(4000) .setDischargePercentage(20) .setDischargedPowerRange(1000, 2000) @@ -236,16 +264,19 @@ public class BatteryUsageStatsTest { addUidBatteryConsumer(builder, batteryStats, APP_UID1, "foo", 1000, 2000, - 300, POWER_MODEL_POWER_PROFILE, 400, POWER_MODEL_POWER_PROFILE, 500, 600, 800); + 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400, + BatteryConsumer.POWER_MODEL_POWER_PROFILE, 500, 600, 800, + 1777, 7771, 1888, 8881, 1999, 9991); addAggregateBatteryConsumer(builder, BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0, - 10100, 10200, 10300, 10400); + 10100, 10200, 10300, 10400, + 1333, 3331, 1444, 4441, 1555, 5551); addAggregateBatteryConsumer(builder, BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 30000, - 20100, 20200, 20300, 20400); - + 20100, 20200, 20300, 20400, + 2333, 3332, 2444, 4442, 2555, 5552); if (includeUserBatteryConsumer) { builder.getOrCreateUserBatteryConsumerBuilder(USER_ID) @@ -261,43 +292,55 @@ public class BatteryUsageStatsTest { return builder; } - private BatteryUsageStats.Builder buildBatteryUsageStats2(String[] customPowerComponentNames) { + private BatteryUsageStats.Builder buildBatteryUsageStats2(String[] customPowerComponentNames, + boolean includeProcessStateData) { final MockClock clocks = new MockClock(); final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks); final BatteryUsageStats.Builder builder = - new BatteryUsageStats.Builder(customPowerComponentNames, true) - .setDischargePercentage(30) - .setDischargedPowerRange(1234, 2345) - .setStatsStartTimestamp(2000) - .setStatsEndTimestamp(5000); + new BatteryUsageStats.Builder(customPowerComponentNames, true, + includeProcessStateData); + builder.setDischargePercentage(30) + .setDischargedPowerRange(1234, 2345) + .setStatsStartTimestamp(2000) + .setStatsEndTimestamp(5000); addUidBatteryConsumer(builder, batteryStats, APP_UID1, null, 4321, 5432, - 123, POWER_MODEL_POWER_PROFILE, 345, POWER_MODEL_MEASURED_ENERGY, 456, 567, 678); + 123, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 345, POWER_MODEL_MEASURED_ENERGY, + 456, 567, 678, + 1777, 7771, 1888, 8881, 1999, 9991); addUidBatteryConsumer(builder, batteryStats, APP_UID2, "bar", 1111, 2222, - 333, POWER_MODEL_POWER_PROFILE, 444, POWER_MODEL_POWER_PROFILE, 555, 666, 777); + 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444, + BatteryConsumer.POWER_MODEL_POWER_PROFILE, 555, 666, 777, + 1777, 7771, 1888, 8881, 1999, 9991); addAggregateBatteryConsumer(builder, BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0, - 10123, 10234, 10345, 10456); + 10123, 10234, 10345, 10456, + 4333, 3334, 5444, 4445, 6555, 5556); addAggregateBatteryConsumer(builder, BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 12345, - 20111, 20222, 20333, 20444); + 20111, 20222, 20333, 20444, + 7333, 3337, 8444, 4448, 9555, 5559); return builder; } private void addUidBatteryConsumer(BatteryUsageStats.Builder builder, MockBatteryStatsImpl batteryStats, int uid, String packageWithHighestDrain, - int timeInStateForeground, int timeInStateBackground, int screenPower, - int screenPowerModel, int cpuPower, int cpuPowerModel, int customComponentPower, - int cpuDuration, int customComponentDuration) { + int timeInStateForeground, int timeInStateBackground, double screenPower, + int screenPowerModel, double cpuPower, int cpuPowerModel, double customComponentPower, + int cpuDuration, int customComponentDuration, double cpuPowerForeground, + int cpuDurationForeground, double cpuPowerBackground, int cpuDurationBackground, + double cpuPowerFgs, int cpuDurationFgs) { final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(uid); - builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid) + final UidBatteryConsumer.Builder uidBuilder = + builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid); + uidBuilder .setPackageWithHighestDrain(packageWithHighestDrain) .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, timeInStateForeground) .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, timeInStateBackground) @@ -311,21 +354,68 @@ public class BatteryUsageStatsTest { BatteryConsumer.POWER_COMPONENT_CPU, cpuDuration) .setUsageDurationForCustomComponentMillis( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, customComponentDuration); + if (builder.isProcessStateDataNeeded()) { + final BatteryConsumer.Key cpuFgKey = uidBuilder.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_FOREGROUND); + final BatteryConsumer.Key cpuBgKey = uidBuilder.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_BACKGROUND); + final BatteryConsumer.Key cpuFgsKey = uidBuilder.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE); + uidBuilder + .setConsumedPower(cpuFgKey, cpuPowerForeground, + BatteryConsumer.POWER_MODEL_POWER_PROFILE) + .setUsageDurationMillis(cpuFgKey, cpuDurationForeground) + .setConsumedPower(cpuBgKey, cpuPowerBackground, + BatteryConsumer.POWER_MODEL_POWER_PROFILE) + .setUsageDurationMillis(cpuBgKey, cpuDurationBackground) + .setConsumedPower(cpuFgsKey, cpuPowerFgs, + BatteryConsumer.POWER_MODEL_POWER_PROFILE) + .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs); + } } private void addAggregateBatteryConsumer(BatteryUsageStats.Builder builder, int scope, double consumedPower, int cpuPower, int customComponentPower, int cpuDuration, - int customComponentDuration) { - builder.getAggregateBatteryConsumerBuilder(scope) - .setConsumedPower(consumedPower) - .setConsumedPower( - BatteryConsumer.POWER_COMPONENT_CPU, cpuPower) - .setConsumedPowerForCustomComponent( - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, customComponentPower) - .setUsageDurationMillis( - BatteryConsumer.POWER_COMPONENT_CPU, cpuDuration) - .setUsageDurationForCustomComponentMillis( - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, customComponentDuration); + int customComponentDuration, double cpuPowerForeground, long cpuDurationForeground, + double cpuPowerBackground, long cpuDurationBackground, double cpuPowerFgs, + long cpuDurationFgs) { + final AggregateBatteryConsumer.Builder aggBuilder = + builder.getAggregateBatteryConsumerBuilder(scope) + .setConsumedPower(consumedPower) + .setConsumedPower( + BatteryConsumer.POWER_COMPONENT_CPU, cpuPower) + .setConsumedPowerForCustomComponent( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, + customComponentPower) + .setUsageDurationMillis( + BatteryConsumer.POWER_COMPONENT_CPU, cpuDuration) + .setUsageDurationForCustomComponentMillis( + BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, + customComponentDuration); + if (builder.isProcessStateDataNeeded()) { + final BatteryConsumer.Key cpuFgKey = aggBuilder.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_FOREGROUND); + final BatteryConsumer.Key cpuBgKey = aggBuilder.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_BACKGROUND); + final BatteryConsumer.Key cpuFgsKey = aggBuilder.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE); + aggBuilder + .setConsumedPower(cpuFgKey, cpuPowerForeground, + BatteryConsumer.POWER_MODEL_POWER_PROFILE) + .setUsageDurationMillis(cpuFgKey, cpuDurationForeground) + .setConsumedPower(cpuBgKey, cpuPowerBackground, + BatteryConsumer.POWER_MODEL_POWER_PROFILE) + .setUsageDurationMillis(cpuBgKey, cpuDurationBackground) + .setConsumedPower(cpuFgsKey, cpuPowerFgs, + BatteryConsumer.POWER_MODEL_POWER_PROFILE) + .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs); + } } public void assertBatteryUsageStats1(BatteryUsageStats batteryUsageStats, @@ -338,8 +428,10 @@ public class BatteryUsageStatsTest { for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) { if (uidBatteryConsumer.getUid() == APP_UID1) { assertUidBatteryConsumer(uidBatteryConsumer, 1200, "foo", - 1000, 2000, 300, POWER_MODEL_POWER_PROFILE, 400, POWER_MODEL_POWER_PROFILE, - 500, 600, 800); + 1000, 2000, 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400, + BatteryConsumer.POWER_MODEL_POWER_PROFILE, + 500, 600, 800, + true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991); } else { fail("Unexpected UID " + uidBatteryConsumer.getUid()); } @@ -384,10 +476,13 @@ public class BatteryUsageStatsTest { } private void assertUidBatteryConsumer(UidBatteryConsumer uidBatteryConsumer, - int consumedPower, String packageWithHighestDrain, int timeInStateForeground, - int timeInStateBackground, int screenPower, int screenPowerModel, int cpuPower, - int cpuPowerModel, int customComponentPower, int cpuDuration, - int customComponentDuration) { + double consumedPower, String packageWithHighestDrain, int timeInStateForeground, + int timeInStateBackground, int screenPower, int screenPowerModel, double cpuPower, + int cpuPowerModel, double customComponentPower, int cpuDuration, + int customComponentDuration, boolean processStateDataIncluded, + double totalPowerForeground, double totalPowerBackground, double totalPowerFgs, + double cpuPowerForeground, int cpuDurationForeground, double cpuPowerBackground, + int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs) { assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(consumedPower); assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo( packageWithHighestDrain); @@ -413,6 +508,58 @@ public class BatteryUsageStatsTest { assertThat(uidBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1); assertThat(uidBatteryConsumer.getCustomPowerComponentName( BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO"); + + if (processStateDataIncluded) { + assertThat(uidBatteryConsumer.getConsumedPower( + new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY, + PROCESS_STATE_FOREGROUND))) + .isEqualTo(totalPowerForeground); + assertThat(uidBatteryConsumer.getConsumedPower( + new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY, + PROCESS_STATE_BACKGROUND))) + .isEqualTo(totalPowerBackground); + assertThat(uidBatteryConsumer.getConsumedPower( + new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY, + PROCESS_STATE_FOREGROUND_SERVICE))) + .isEqualTo(totalPowerFgs); + } + + final BatteryConsumer.Key cpuFgKey = uidBatteryConsumer.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, BatteryConsumer.PROCESS_STATE_FOREGROUND); + if (processStateDataIncluded) { + assertThat(cpuFgKey).isNotNull(); + assertThat(uidBatteryConsumer.getConsumedPower(cpuFgKey)) + .isEqualTo(cpuPowerForeground); + assertThat(uidBatteryConsumer.getUsageDurationMillis(cpuFgKey)) + .isEqualTo(cpuDurationForeground); + } else { + assertThat(cpuFgKey).isNull(); + } + + final BatteryConsumer.Key cpuBgKey = uidBatteryConsumer.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, BatteryConsumer.PROCESS_STATE_BACKGROUND); + if (processStateDataIncluded) { + assertThat(cpuBgKey).isNotNull(); + assertThat(uidBatteryConsumer.getConsumedPower(cpuBgKey)) + .isEqualTo(cpuPowerBackground); + assertThat(uidBatteryConsumer.getUsageDurationMillis(cpuBgKey)) + .isEqualTo(cpuDurationBackground); + } else { + assertThat(cpuBgKey).isNull(); + } + + final BatteryConsumer.Key cpuFgsKey = uidBatteryConsumer.getKey( + BatteryConsumer.POWER_COMPONENT_CPU, + BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE); + if (processStateDataIncluded) { + assertThat(cpuFgsKey).isNotNull(); + assertThat(uidBatteryConsumer.getConsumedPower(cpuFgsKey)) + .isEqualTo(cpuPowerFgs); + assertThat(uidBatteryConsumer.getUsageDurationMillis(cpuFgsKey)) + .isEqualTo(cpuDurationFgs); + } else { + assertThat(cpuFgsKey).isNotNull(); + } } private void assertUserBatteryConsumer(UserBatteryConsumer userBatteryConsumer, diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java index 2e4b6da3ba13..fe2fe0b40891 100644 --- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java +++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java @@ -159,7 +159,7 @@ public class BatteryUsageStatsPerfTest { private static BatteryUsageStats buildBatteryUsageStats() { final BatteryUsageStats.Builder builder = - new BatteryUsageStats.Builder(new String[]{"FOO"}, true) + new BatteryUsageStats.Builder(new String[]{"FOO"}, true, false) .setBatteryCapacity(4000) .setDischargePercentage(20) .setDischargedPowerRange(1000, 2000) |