summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dmitri Plotnikov <dplotnikov@google.com> 2021-09-24 15:04:56 -0700
committer Dmitri Plotnikov <dplotnikov@google.com> 2021-10-13 15:46:48 -0700
commit2198961ab1f7c1c922e4792d9f436ae8b87f88ef (patch)
tree87e715004e34f86da4a4e524dc0793340e5dafe9
parentb7278347224427a8b317bf4ec37ca3d50f967fc4 (diff)
Add per-proc-state power components
Test: atest FrameworksCoreTests:BatteryStatsTests atest BatteryUsageStatsProtoTests:BatteryUsageStatsPulledTest Bug: 191921016 Change-Id: I698421a87766fcaef6569fd0ecfd1a44a9a3659f
-rw-r--r--core/java/android/os/BatteryConsumer.java361
-rw-r--r--core/java/android/os/BatteryStats.java6
-rw-r--r--core/java/android/os/BatteryUsageStats.java68
-rw-r--r--core/java/android/os/BatteryUsageStatsQuery.java19
-rw-r--r--core/java/android/os/PowerComponents.java305
-rw-r--r--core/java/android/os/UidBatteryConsumer.java27
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java5
-rw-r--r--core/java/com/android/internal/os/BatteryUsageStatsProvider.java38
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java241
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java2
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)