summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/os/PowerStats.java199
-rw-r--r--core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java71
-rw-r--r--services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java29
-rw-r--r--services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java6
-rw-r--r--services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java61
-rw-r--r--services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java23
-rw-r--r--services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java33
-rw-r--r--services/core/java/com/android/server/power/stats/MultiStateStats.java38
-rw-r--r--services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java17
-rw-r--r--services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java70
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsLayout.java69
-rw-r--r--services/core/java/com/android/server/power/stats/PowerStatsProcessor.java8
-rw-r--r--services/core/java/com/android/server/power/stats/WifiPowerStatsLayout.java26
-rw-r--r--services/core/java/com/android/server/power/stats/WifiPowerStatsProcessor.java33
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java32
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java24
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java12
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java164
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java15
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java12
20 files changed, 593 insertions, 349 deletions
diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java
index 9f9aae53e0af..24971f51aabf 100644
--- a/core/java/com/android/internal/os/PowerStats.java
+++ b/core/java/com/android/internal/os/PowerStats.java
@@ -19,6 +19,7 @@ package com.android.internal.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.BatteryConsumer;
+import android.os.BatteryStats;
import android.os.Bundle;
import android.os.Parcel;
import android.os.PersistableBundle;
@@ -34,8 +35,12 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Container for power stats, acquired by various PowerStatsCollector classes. See subclasses for
@@ -75,6 +80,10 @@ public final class PowerStats {
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
public static class Descriptor {
+ public static final String EXTRA_DEVICE_STATS_FORMAT = "format-device";
+ public static final String EXTRA_STATE_STATS_FORMAT = "format-state";
+ public static final String EXTRA_UID_STATS_FORMAT = "format-uid";
+
public static final String XML_TAG_DESCRIPTOR = "descriptor";
private static final String XML_ATTR_ID = "id";
private static final String XML_ATTR_NAME = "name";
@@ -120,6 +129,10 @@ public final class PowerStats {
*/
public final PersistableBundle extras;
+ private PowerStatsFormatter mDeviceStatsFormatter;
+ private PowerStatsFormatter mStateStatsFormatter;
+ private PowerStatsFormatter mUidStatsFormatter;
+
public Descriptor(@BatteryConsumer.PowerComponent int powerComponentId,
int statsArrayLength, @Nullable SparseArray<String> stateLabels,
int stateStatsArrayLength, int uidStatsArrayLength,
@@ -131,7 +144,7 @@ public final class PowerStats {
public Descriptor(int customPowerComponentId, String name, int statsArrayLength,
@Nullable SparseArray<String> stateLabels, int stateStatsArrayLength,
- int uidStatsArrayLength, PersistableBundle extras) {
+ int uidStatsArrayLength, @NonNull PersistableBundle extras) {
if (statsArrayLength > MAX_STATS_ARRAY_LENGTH) {
throw new IllegalArgumentException(
"statsArrayLength is too high. Max = " + MAX_STATS_ARRAY_LENGTH);
@@ -154,6 +167,39 @@ public final class PowerStats {
}
/**
+ * Returns a custom formatter for this type of power stats.
+ */
+ public PowerStatsFormatter getDeviceStatsFormatter() {
+ if (mDeviceStatsFormatter == null) {
+ mDeviceStatsFormatter = new PowerStatsFormatter(
+ extras.getString(EXTRA_DEVICE_STATS_FORMAT));
+ }
+ return mDeviceStatsFormatter;
+ }
+
+ /**
+ * Returns a custom formatter for this type of power stats, specifically per-state stats.
+ */
+ public PowerStatsFormatter getStateStatsFormatter() {
+ if (mStateStatsFormatter == null) {
+ mStateStatsFormatter = new PowerStatsFormatter(
+ extras.getString(EXTRA_STATE_STATS_FORMAT));
+ }
+ return mStateStatsFormatter;
+ }
+
+ /**
+ * Returns a custom formatter for this type of power stats, specifically per-UID stats.
+ */
+ public PowerStatsFormatter getUidStatsFormatter() {
+ if (mUidStatsFormatter == null) {
+ mUidStatsFormatter = new PowerStatsFormatter(
+ extras.getString(EXTRA_UID_STATS_FORMAT));
+ }
+ return mUidStatsFormatter;
+ }
+
+ /**
* Returns the label associated with the give state key, e.g. "5G-high" for the
* state of Mobile Radio representing the 5G mode and high signal power.
*/
@@ -491,20 +537,22 @@ public final class PowerStats {
StringBuilder sb = new StringBuilder();
sb.append("duration=").append(durationMs).append(" ").append(descriptor.name);
if (stats.length > 0) {
- sb.append("=").append(Arrays.toString(stats));
+ sb.append("=").append(descriptor.getDeviceStatsFormatter().format(stats));
}
if (descriptor.stateStatsArrayLength != 0) {
+ PowerStatsFormatter formatter = descriptor.getStateStatsFormatter();
for (int i = 0; i < stateStats.size(); i++) {
- sb.append(" [");
+ sb.append(" (");
sb.append(descriptor.getStateLabel(stateStats.keyAt(i)));
- sb.append("]=");
- sb.append(Arrays.toString(stateStats.valueAt(i)));
+ sb.append(") ");
+ sb.append(formatter.format(stateStats.valueAt(i)));
}
}
+ PowerStatsFormatter uidStatsFormatter = descriptor.getUidStatsFormatter();
for (int i = 0; i < uidStats.size(); i++) {
sb.append(uidPrefix)
.append(UserHandle.formatUid(uidStats.keyAt(i)))
- .append(": ").append(Arrays.toString(uidStats.valueAt(i)));
+ .append(": ").append(uidStatsFormatter.format(uidStats.valueAt(i)));
}
return sb.toString();
}
@@ -513,26 +561,29 @@ public final class PowerStats {
* Prints the contents of the stats snapshot.
*/
public void dump(IndentingPrintWriter pw) {
- pw.println("PowerStats: " + descriptor.name + " (" + descriptor.powerComponentId + ')');
+ pw.println(descriptor.name + " (" + descriptor.powerComponentId + ')');
pw.increaseIndent();
pw.print("duration", durationMs).println();
+
if (descriptor.statsArrayLength != 0) {
- pw.print("stats", Arrays.toString(stats)).println();
+ pw.println(descriptor.getDeviceStatsFormatter().format(stats));
}
if (descriptor.stateStatsArrayLength != 0) {
+ PowerStatsFormatter formatter = descriptor.getStateStatsFormatter();
for (int i = 0; i < stateStats.size(); i++) {
- pw.print("state ");
+ pw.print(" (");
pw.print(descriptor.getStateLabel(stateStats.keyAt(i)));
- pw.print(": ");
- pw.print(Arrays.toString(stateStats.valueAt(i)));
+ pw.print(") ");
+ pw.print(formatter.format(stateStats.valueAt(i)));
pw.println();
}
}
+ PowerStatsFormatter uidStatsFormatter = descriptor.getUidStatsFormatter();
for (int i = 0; i < uidStats.size(); i++) {
pw.print("UID ");
- pw.print(uidStats.keyAt(i));
+ pw.print(UserHandle.formatUid(uidStats.keyAt(i)));
pw.print(": ");
- pw.print(Arrays.toString(uidStats.valueAt(i)));
+ pw.print(uidStatsFormatter.format(uidStats.valueAt(i)));
pw.println();
}
pw.decreaseIndent();
@@ -542,4 +593,126 @@ public final class PowerStats {
public String toString() {
return "PowerStats: " + formatForBatteryHistory(" UID ");
}
+
+ public static class PowerStatsFormatter {
+ private static class Section {
+ public String label;
+ public int position;
+ public int length;
+ public boolean optional;
+ public boolean typePower;
+ }
+
+ private static final double NANO_TO_MILLI_MULTIPLIER = 1.0 / 1000000.0;
+ private static final Pattern SECTION_PATTERN =
+ Pattern.compile("([^:]+):(\\d+)(\\[(?<L>\\d+)])?(?<F>\\S*)\\s*");
+ private final List<Section> mSections;
+
+ public PowerStatsFormatter(String format) {
+ mSections = parseFormat(format);
+ }
+
+ /**
+ * Produces a formatted string representing the supplied array, with labels
+ * and other adornments specific to the power stats layout.
+ */
+ public String format(long[] stats) {
+ return format(mSections, stats);
+ }
+
+ private List<Section> parseFormat(String format) {
+ if (format == null || format.isBlank()) {
+ return null;
+ }
+
+ ArrayList<Section> sections = new ArrayList<>();
+ Matcher matcher = SECTION_PATTERN.matcher(format);
+ for (int position = 0; position < format.length(); position = matcher.end()) {
+ if (!matcher.find() || matcher.start() != position) {
+ Slog.wtf(TAG, "Bad power stats format '" + format + "'");
+ return null;
+ }
+ Section section = new Section();
+ section.label = matcher.group(1);
+ section.position = Integer.parseUnsignedInt(matcher.group(2));
+ String length = matcher.group("L");
+ if (length != null) {
+ section.length = Integer.parseUnsignedInt(length);
+ } else {
+ section.length = 1;
+ }
+ String flags = matcher.group("F");
+ if (flags != null) {
+ for (int i = 0; i < flags.length(); i++) {
+ char flag = flags.charAt(i);
+ switch (flag) {
+ case '?':
+ section.optional = true;
+ break;
+ case 'p':
+ section.typePower = true;
+ break;
+ default:
+ Slog.e(TAG,
+ "Unsupported format option '" + flag + "' in " + format);
+ break;
+ }
+ }
+ }
+ sections.add(section);
+ }
+
+ return sections;
+ }
+
+ private String format(List<Section> sections, long[] stats) {
+ if (sections == null) {
+ return Arrays.toString(stats);
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0, count = sections.size(); i < count; i++) {
+ Section section = sections.get(i);
+ if (section.length == 0) {
+ continue;
+ }
+
+ if (section.optional) {
+ boolean nonZero = false;
+ for (int offset = 0; offset < section.length; offset++) {
+ if (stats[section.position + offset] != 0) {
+ nonZero = true;
+ break;
+ }
+ }
+ if (!nonZero) {
+ continue;
+ }
+ }
+
+ if (!sb.isEmpty()) {
+ sb.append(' ');
+ }
+ sb.append(section.label).append(": ");
+ if (section.length != 1) {
+ sb.append('[');
+ }
+ for (int offset = 0; offset < section.length; offset++) {
+ if (offset != 0) {
+ sb.append(", ");
+ }
+ if (section.typePower) {
+ sb.append(BatteryStats.formatCharge(
+ stats[section.position + offset] * NANO_TO_MILLI_MULTIPLIER));
+ } else {
+ sb.append(stats[section.position + offset]);
+ }
+ }
+ if (section.length != 1) {
+ sb.append(']');
+ }
+ }
+ return sb.toString();
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
index baab3b218746..4846ed27af22 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java
@@ -22,6 +22,7 @@ import android.os.BatteryConsumer;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.IndentingPrintWriter;
import android.util.SparseArray;
import android.util.Xml;
@@ -31,6 +32,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.google.common.truth.StringSubject;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -38,6 +41,7 @@ import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
@RunWith(AndroidJUnit4.class)
@@ -56,6 +60,9 @@ public class PowerStatsTest {
extras.putBoolean("hasPowerMonitor", true);
SparseArray<String> stateLabels = new SparseArray<>();
stateLabels.put(0x0F, "idle");
+ extras.putString(PowerStats.Descriptor.EXTRA_DEVICE_STATS_FORMAT, "device:0[3]");
+ extras.putString(PowerStats.Descriptor.EXTRA_STATE_STATS_FORMAT, "state:0");
+ extras.putString(PowerStats.Descriptor.EXTRA_UID_STATS_FORMAT, "a:0 b:1");
mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, 3, stateLabels,
1, 2, extras);
mRegistry.register(mDescriptor);
@@ -191,4 +198,68 @@ public class PowerStatsTest {
newParcel.setDataPosition(0);
return newParcel;
}
+
+ @Test
+ public void formatForBatteryHistory() {
+ PowerStats stats = new PowerStats(mDescriptor);
+ stats.durationMs = 1234;
+ stats.stats[0] = 10;
+ stats.stats[1] = 20;
+ stats.stats[2] = 30;
+ stats.stateStats.put(0x0F, new long[]{16});
+ stats.stateStats.put(0xF0, new long[]{17});
+ stats.uidStats.put(42, new long[]{40, 50});
+ stats.uidStats.put(99, new long[]{60, 70});
+
+ assertThat(stats.formatForBatteryHistory(" #"))
+ .isEqualTo("duration=1234 cpu="
+ + "device: [10, 20, 30]"
+ + " (idle) state: 16"
+ + " (cpu-f0) state: 17"
+ + " #42: a: 40 b: 50"
+ + " #99: a: 60 b: 70");
+ }
+
+ @Test
+ public void dump() {
+ PowerStats stats = new PowerStats(mDescriptor);
+ stats.durationMs = 1234;
+ stats.stats[0] = 10;
+ stats.stats[1] = 20;
+ stats.stats[2] = 30;
+ stats.stateStats.put(0x0F, new long[]{16});
+ stats.stateStats.put(0xF0, new long[]{17});
+ stats.uidStats.put(42, new long[]{40, 50});
+ stats.uidStats.put(99, new long[]{60, 70});
+
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter pw = new IndentingPrintWriter(sw);
+ stats.dump(pw);
+ pw.flush();
+ String dump = sw.toString();
+
+ assertThat(dump).contains("duration=1234");
+ assertThat(dump).contains("device: [10, 20, 30]");
+ assertThat(dump).contains("(idle) state: 16");
+ assertThat(dump).contains("(cpu-f0) state: 17");
+ assertThat(dump).contains("UID 42: a: 40 b: 50");
+ assertThat(dump).contains("UID 99: a: 60 b: 70");
+ }
+
+ @Test
+ public void formatter() {
+ assertThatFormatted(new long[]{12, 34, 56}, "a:0 b:1[2]")
+ .isEqualTo("a: 12 b: [34, 56]");
+ assertThatFormatted(new long[]{12, 0, 0}, "a:0? b:1[2]?")
+ .isEqualTo("a: 12");
+ assertThatFormatted(new long[]{0, 34, 56}, "a:0? b:1[2]?")
+ .isEqualTo("b: [34, 56]");
+ assertThatFormatted(new long[]{3141592, 2000000, 1414213}, "pi:0p sqrt:1[2]p")
+ .isEqualTo("pi: 3.14 sqrt: [2.00, 1.41]");
+ }
+
+ private static StringSubject assertThatFormatted(long[] stats, String format) {
+ return assertThat(new PowerStats.PowerStatsFormatter(format)
+ .format(stats));
+ }
}
diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java b/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java
index 5aad570ffd41..884c26ca3c00 100644
--- a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java
+++ b/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java
@@ -19,12 +19,9 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.BatteryConsumer;
-import com.android.internal.os.PowerStats;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -206,25 +203,9 @@ public class AggregatedPowerStatsConfig {
return mPowerComponents;
}
- private static final PowerStatsProcessor NO_OP_PROCESSOR =
- new PowerStatsProcessor() {
- @Override
- void finish(PowerComponentAggregatedPowerStats stats) {
- }
-
- @Override
- String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- return Arrays.toString(stats);
- }
-
- @Override
- String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) {
- return descriptor.getStateLabel(key) + " " + Arrays.toString(stats);
- }
-
- @Override
- String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- return Arrays.toString(stats);
- }
- };
+ private static final PowerStatsProcessor NO_OP_PROCESSOR = new PowerStatsProcessor() {
+ @Override
+ void finish(PowerComponentAggregatedPowerStats stats) {
+ }
+ };
}
diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java
index 1bcb2c4bc5fa..2a02bd0f9e6a 100644
--- a/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java
@@ -44,7 +44,7 @@ public class CpuPowerStatsLayout extends PowerStatsLayout {
* Declare that the stats array has a section capturing CPU time per scaling step
*/
public void addDeviceSectionCpuTimeByScalingStep(int scalingStepCount) {
- mDeviceCpuTimeByScalingStepPosition = addDeviceSection(scalingStepCount);
+ mDeviceCpuTimeByScalingStepPosition = addDeviceSection(scalingStepCount, "steps");
mDeviceCpuTimeByScalingStepCount = scalingStepCount;
}
@@ -72,7 +72,7 @@ public class CpuPowerStatsLayout extends PowerStatsLayout {
* Declare that the stats array has a section capturing CPU time in each cluster
*/
public void addDeviceSectionCpuTimeByCluster(int clusterCount) {
- mDeviceCpuTimeByClusterPosition = addDeviceSection(clusterCount);
+ mDeviceCpuTimeByClusterPosition = addDeviceSection(clusterCount, "clusters");
mDeviceCpuTimeByClusterCount = clusterCount;
}
@@ -102,7 +102,7 @@ public class CpuPowerStatsLayout extends PowerStatsLayout {
public void addUidSectionCpuTimeByPowerBracket(int[] scalingStepToPowerBracketMap) {
mScalingStepToPowerBracketMap = scalingStepToPowerBracketMap;
updatePowerBracketCount();
- mUidPowerBracketsPosition = addUidSection(mUidPowerBracketCount);
+ mUidPowerBracketsPosition = addUidSection(mUidPowerBracketCount, "time");
}
private void updatePowerBracketCount() {
diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java
index c34b8a8dc992..57b7259f9b56 100644
--- a/services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java
@@ -16,7 +16,6 @@
package com.android.server.power.stats;
-import android.os.BatteryStats;
import android.util.ArraySet;
import android.util.Log;
@@ -487,64 +486,4 @@ public class CpuPowerStatsProcessor extends PowerStatsProcessor {
stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
}
}
-
- @Override
- public String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- StringBuilder sb = new StringBuilder();
- int cpuScalingStepCount = mStatsLayout.getCpuScalingStepCount();
- sb.append("steps: [");
- for (int step = 0; step < cpuScalingStepCount; step++) {
- if (step != 0) {
- sb.append(", ");
- }
- sb.append(mStatsLayout.getTimeByScalingStep(stats, step));
- }
- int clusterCount = mStatsLayout.getCpuClusterCount();
- sb.append("] clusters: [");
- for (int cluster = 0; cluster < clusterCount; cluster++) {
- if (cluster != 0) {
- sb.append(", ");
- }
- sb.append(mStatsLayout.getTimeByCluster(stats, cluster));
- }
- sb.append("] uptime: ").append(mStatsLayout.getUsageDuration(stats));
- int energyConsumerCount = mStatsLayout.getEnergyConsumerCount();
- if (energyConsumerCount > 0) {
- sb.append(" energy: [");
- for (int i = 0; i < energyConsumerCount; i++) {
- if (i != 0) {
- sb.append(", ");
- }
- sb.append(mStatsLayout.getConsumedEnergy(stats, i));
- }
- sb.append("]");
- }
- sb.append(" power: ").append(
- BatteryStats.formatCharge(mStatsLayout.getDevicePowerEstimate(stats)));
- return sb.toString();
- }
-
- @Override
- String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) {
- // Unsupported for this power component
- return null;
- }
-
- @Override
- public String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- StringBuilder sb = new StringBuilder();
- sb.append("[");
- int powerBracketCount = mStatsLayout.getCpuPowerBracketCount();
- for (int bracket = 0; bracket < powerBracketCount; bracket++) {
- if (bracket != 0) {
- sb.append(", ");
- }
- sb.append(mStatsLayout.getUidTimeByPowerBracket(stats, bracket));
- }
- sb.append("] power: ").append(
- BatteryStats.formatCharge(mStatsLayout.getUidPowerEstimate(stats)));
- return sb.toString();
- }
}
diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java
index 81d7c2fa2880..07d78f8ce4d0 100644
--- a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java
@@ -64,29 +64,30 @@ class MobileRadioPowerStatsLayout extends PowerStatsLayout {
}
void addDeviceMobileActivity() {
- mDeviceSleepTimePosition = addDeviceSection(1);
- mDeviceIdleTimePosition = addDeviceSection(1);
- mDeviceScanTimePosition = addDeviceSection(1);
- mDeviceCallTimePosition = addDeviceSection(1);
+ mDeviceSleepTimePosition = addDeviceSection(1, "sleep");
+ mDeviceIdleTimePosition = addDeviceSection(1, "idle");
+ mDeviceScanTimePosition = addDeviceSection(1, "scan");
+ mDeviceCallTimePosition = addDeviceSection(1, "call", FLAG_OPTIONAL);
}
void addStateStats() {
- mStateRxTimePosition = addStateSection(1);
+ mStateRxTimePosition = addStateSection(1, "rx");
mStateTxTimesCount = ModemActivityInfo.getNumTxPowerLevels();
- mStateTxTimesPosition = addStateSection(mStateTxTimesCount);
+ mStateTxTimesPosition = addStateSection(mStateTxTimesCount, "tx");
}
void addUidNetworkStats() {
- mUidRxBytesPosition = addUidSection(1);
- mUidTxBytesPosition = addUidSection(1);
- mUidRxPacketsPosition = addUidSection(1);
- mUidTxPacketsPosition = addUidSection(1);
+ mUidRxPacketsPosition = addUidSection(1, "rx-pkts");
+ mUidRxBytesPosition = addUidSection(1, "rx-B");
+ mUidTxPacketsPosition = addUidSection(1, "tx-pkts");
+ mUidTxBytesPosition = addUidSection(1, "tx-B");
}
@Override
public void addDeviceSectionPowerEstimate() {
super.addDeviceSectionPowerEstimate();
- mDeviceCallPowerPosition = addDeviceSection(1);
+ // Printed as part of the PhoneCallPowerStatsProcessor
+ mDeviceCallPowerPosition = addDeviceSection(1, "call-power", FLAG_HIDDEN);
}
public void setDeviceSleepTime(long[] stats, long durationMillis) {
diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java
index c97c64bafcba..eebed2f21946 100644
--- a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java
@@ -398,37 +398,4 @@ public class MobileRadioPowerStatsProcessor extends PowerStatsProcessor {
}
}
}
-
- @Override
- String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- return "idle: " + mStatsLayout.getDeviceIdleTime(stats)
- + " sleep: " + mStatsLayout.getDeviceSleepTime(stats)
- + " scan: " + mStatsLayout.getDeviceScanTime(stats)
- + " power: " + mStatsLayout.getDevicePowerEstimate(stats);
- }
-
- @Override
- String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- StringBuilder sb = new StringBuilder();
- sb.append(descriptor.getStateLabel(key));
- sb.append(" rx: ").append(mStatsLayout.getStateRxTime(stats));
- sb.append(" tx: ");
- for (int txLevel = 0; txLevel < ModemActivityInfo.getNumTxPowerLevels(); txLevel++) {
- if (txLevel != 0) {
- sb.append(", ");
- }
- sb.append(mStatsLayout.getStateTxTime(stats, txLevel));
- }
- return sb.toString();
- }
-
- @Override
- String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- return "rx: " + mStatsLayout.getUidRxPackets(stats)
- + " tx: " + mStatsLayout.getUidTxPackets(stats)
- + " power: " + mStatsLayout.getUidPowerEstimate(stats);
- }
}
diff --git a/services/core/java/com/android/server/power/stats/MultiStateStats.java b/services/core/java/com/android/server/power/stats/MultiStateStats.java
index 6c4a2b6e6359..a8222811c341 100644
--- a/services/core/java/com/android/server/power/stats/MultiStateStats.java
+++ b/services/core/java/com/android/server/power/stats/MultiStateStats.java
@@ -28,10 +28,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.io.PrintWriter;
import java.util.Arrays;
import java.util.function.Consumer;
-import java.util.function.Function;
/**
* Maintains multidimensional multi-state stats. States could be something like on-battery (0,1),
@@ -287,6 +285,14 @@ public class MultiStateStats {
mCounter = new LongArrayMultiStateCounter(factory.mSerialStateCount, dimensionCount);
}
+ public int getDimensionCount() {
+ return mFactory.mDimensionCount;
+ }
+
+ public States[] getStates() {
+ return mFactory.mStates;
+ }
+
/**
* Copies time-in-state and timestamps from the supplied prototype. Does not
* copy accumulated counts.
@@ -343,11 +349,6 @@ public class MultiStateStats {
mTracking = false;
}
- @Override
- public String toString() {
- return mCounter.toString();
- }
-
/**
* Stores contents in an XML doc.
*/
@@ -451,10 +452,9 @@ public class MultiStateStats {
return true;
}
- /**
- * Prints the accumulated stats, one line of every combination of states that has data.
- */
- public void dump(PrintWriter pw, Function<long[], String> statsFormatter) {
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
long[] values = new long[mCounter.getArrayLength()];
States.forEachTrackedStateCombination(mFactory.mStates, states -> {
mCounter.getCounts(values, mFactory.getSerialState(states));
@@ -469,18 +469,24 @@ public class MultiStateStats {
return;
}
- StringBuilder sb = new StringBuilder();
+ if (!sb.isEmpty()) {
+ sb.append("\n");
+ }
+
+ sb.append("(");
+ boolean first = true;
for (int i = 0; i < states.length; i++) {
if (mFactory.mStates[i].mTracked) {
- if (sb.length() != 0) {
+ if (!first) {
sb.append(" ");
}
+ first = false;
sb.append(mFactory.mStates[i].mLabels[states[i]]);
}
}
- sb.append(" ");
- sb.append(statsFormatter.apply(values));
- pw.println(sb);
+ sb.append(") ");
+ sb.append(Arrays.toString(values));
});
+ return sb.toString();
}
}
diff --git a/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java
index 62b653f61373..5c545fd073b2 100644
--- a/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java
@@ -76,21 +76,4 @@ public class PhoneCallPowerStatsProcessor extends PowerStatsProcessor {
stats.setDeviceStats(states, mTmpDeviceStats);
});
}
-
- @Override
- String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- return "power: " + mStatsLayout.getDevicePowerEstimate(stats);
- }
-
- @Override
- String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) {
- // Unsupported for this power component
- return null;
- }
-
- @Override
- String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- // Unsupported for this power component
- return null;
- }
}
diff --git a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
index 6d58307dbefa..052873312d5c 100644
--- a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java
@@ -436,36 +436,76 @@ class PowerComponentAggregatedPowerStats {
void dumpDevice(IndentingPrintWriter ipw) {
if (mDeviceStats != null) {
- ipw.println(mPowerStatsDescriptor.name);
- ipw.increaseIndent();
- mDeviceStats.dump(ipw, stats ->
- mConfig.getProcessor().deviceStatsToString(mPowerStatsDescriptor, stats));
- ipw.decreaseIndent();
+ dumpMultiStateStats(ipw, mDeviceStats, mPowerStatsDescriptor.name, null,
+ mPowerStatsDescriptor.getDeviceStatsFormatter());
}
if (mStateStats.size() != 0) {
ipw.increaseIndent();
- ipw.println(mPowerStatsDescriptor.name + " states");
- ipw.increaseIndent();
+ String header = mPowerStatsDescriptor.name + " states";
+ PowerStats.PowerStatsFormatter formatter =
+ mPowerStatsDescriptor.getStateStatsFormatter();
for (int i = 0; i < mStateStats.size(); i++) {
int key = mStateStats.keyAt(i);
+ String stateLabel = mPowerStatsDescriptor.getStateLabel(key);
MultiStateStats stateStats = mStateStats.valueAt(i);
- stateStats.dump(ipw, stats ->
- mConfig.getProcessor().stateStatsToString(mPowerStatsDescriptor, key,
- stats));
+ dumpMultiStateStats(ipw, stateStats, header, stateLabel, formatter);
}
ipw.decreaseIndent();
- ipw.decreaseIndent();
}
}
void dumpUid(IndentingPrintWriter ipw, int uid) {
UidStats uidStats = mUidStats.get(uid);
if (uidStats != null && uidStats.stats != null) {
- ipw.println(mPowerStatsDescriptor.name);
- ipw.increaseIndent();
- uidStats.stats.dump(ipw, stats ->
- mConfig.getProcessor().uidStatsToString(mPowerStatsDescriptor, stats));
+ dumpMultiStateStats(ipw, uidStats.stats, mPowerStatsDescriptor.name, null,
+ mPowerStatsDescriptor.getUidStatsFormatter());
+ }
+ }
+
+ private void dumpMultiStateStats(IndentingPrintWriter ipw, MultiStateStats stats,
+ String header, String additionalLabel,
+ PowerStats.PowerStatsFormatter statsFormatter) {
+ boolean[] firstLine = new boolean[]{true};
+ long[] values = new long[stats.getDimensionCount()];
+ MultiStateStats.States[] stateInfo = stats.getStates();
+ MultiStateStats.States.forEachTrackedStateCombination(stateInfo, states -> {
+ stats.getStats(values, states);
+ boolean nonZero = false;
+ for (long value : values) {
+ if (value != 0) {
+ nonZero = true;
+ break;
+ }
+ }
+ if (!nonZero) {
+ return;
+ }
+
+ if (firstLine[0]) {
+ ipw.println(header);
+ ipw.increaseIndent();
+ }
+ firstLine[0] = false;
+ StringBuilder sb = new StringBuilder();
+ sb.append("(");
+ boolean first = true;
+ for (int i = 0; i < states.length; i++) {
+ if (stateInfo[i].isTracked()) {
+ if (!first) {
+ sb.append(" ");
+ }
+ first = false;
+ sb.append(stateInfo[i].getLabels()[states[i]]);
+ }
+ }
+ if (additionalLabel != null) {
+ sb.append(" ").append(additionalLabel);
+ }
+ sb.append(") ").append(statsFormatter.format(values));
+ ipw.println(sb);
+ });
+ if (!firstLine[0]) {
ipw.decreaseIndent();
}
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsLayout.java b/services/core/java/com/android/server/power/stats/PowerStatsLayout.java
index aa96409e85e9..58efd94bb82c 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsLayout.java
@@ -33,13 +33,20 @@ public class PowerStatsLayout {
private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT = "dec";
private static final String EXTRA_UID_POWER_POSITION = "up";
- protected static final double MILLI_TO_NANO_MULTIPLIER = 1000000.0;
protected static final int UNSUPPORTED = -1;
+ protected static final double MILLI_TO_NANO_MULTIPLIER = 1000000.0;
+ protected static final int FLAG_OPTIONAL = 1;
+ protected static final int FLAG_HIDDEN = 2;
+ protected static final int FLAG_FORMAT_AS_POWER = 4;
private int mDeviceStatsArrayLength;
private int mStateStatsArrayLength;
private int mUidStatsArrayLength;
+ private StringBuilder mDeviceFormat = new StringBuilder();
+ private StringBuilder mStateFormat = new StringBuilder();
+ private StringBuilder mUidFormat = new StringBuilder();
+
protected int mDeviceDurationPosition = UNSUPPORTED;
private int mDeviceEnergyConsumerPosition;
private int mDeviceEnergyConsumerCount;
@@ -65,29 +72,71 @@ public class PowerStatsLayout {
return mUidStatsArrayLength;
}
- protected int addDeviceSection(int length) {
+ /**
+ * @param label should not contain either spaces or colons
+ */
+ private void appendFormat(StringBuilder sb, int position, int length, String label,
+ int flags) {
+ if ((flags & FLAG_HIDDEN) != 0) {
+ return;
+ }
+
+ if (!sb.isEmpty()) {
+ sb.append(' ');
+ }
+
+ sb.append(label).append(':');
+ sb.append(position);
+ if (length != 1) {
+ sb.append('[').append(length).append(']');
+ }
+ if ((flags & FLAG_FORMAT_AS_POWER) != 0) {
+ sb.append('p');
+ }
+ if ((flags & FLAG_OPTIONAL) != 0) {
+ sb.append('?');
+ }
+ }
+
+ protected int addDeviceSection(int length, String label, int flags) {
int position = mDeviceStatsArrayLength;
mDeviceStatsArrayLength += length;
+ appendFormat(mDeviceFormat, position, length, label, flags);
return position;
}
- protected int addStateSection(int length) {
+ protected int addDeviceSection(int length, String label) {
+ return addDeviceSection(length, label, 0);
+ }
+
+ protected int addStateSection(int length, String label, int flags) {
int position = mStateStatsArrayLength;
mStateStatsArrayLength += length;
+ appendFormat(mStateFormat, position, length, label, flags);
return position;
}
- protected int addUidSection(int length) {
+ protected int addStateSection(int length, String label) {
+ return addStateSection(length, label, 0);
+ }
+
+
+ protected int addUidSection(int length, String label, int flags) {
int position = mUidStatsArrayLength;
mUidStatsArrayLength += length;
+ appendFormat(mUidFormat, position, length, label, flags);
return position;
}
+ protected int addUidSection(int length, String label) {
+ return addUidSection(length, label, 0);
+ }
+
/**
* Declare that the stats array has a section capturing usage duration
*/
public void addDeviceSectionUsageDuration() {
- mDeviceDurationPosition = addDeviceSection(1);
+ mDeviceDurationPosition = addDeviceSection(1, "usage", FLAG_OPTIONAL);
}
/**
@@ -109,7 +158,7 @@ public class PowerStatsLayout {
* PowerStatsService.
*/
public void addDeviceSectionEnergyConsumers(int energyConsumerCount) {
- mDeviceEnergyConsumerPosition = addDeviceSection(energyConsumerCount);
+ mDeviceEnergyConsumerPosition = addDeviceSection(energyConsumerCount, "energy");
mDeviceEnergyConsumerCount = energyConsumerCount;
}
@@ -137,7 +186,8 @@ public class PowerStatsLayout {
* Declare that the stats array has a section capturing a power estimate
*/
public void addDeviceSectionPowerEstimate() {
- mDevicePowerEstimatePosition = addDeviceSection(1);
+ mDevicePowerEstimatePosition = addDeviceSection(1, "power",
+ FLAG_FORMAT_AS_POWER | FLAG_OPTIONAL);
}
/**
@@ -159,7 +209,7 @@ public class PowerStatsLayout {
* Declare that the UID stats array has a section capturing a power estimate
*/
public void addUidSectionPowerEstimate() {
- mUidPowerEstimatePosition = addUidSection(1);
+ mUidPowerEstimatePosition = addUidSection(1, "power", FLAG_FORMAT_AS_POWER | FLAG_OPTIONAL);
}
/**
@@ -195,6 +245,9 @@ public class PowerStatsLayout {
mDeviceEnergyConsumerCount);
extras.putInt(EXTRA_DEVICE_POWER_POSITION, mDevicePowerEstimatePosition);
extras.putInt(EXTRA_UID_POWER_POSITION, mUidPowerEstimatePosition);
+ extras.putString(PowerStats.Descriptor.EXTRA_DEVICE_STATS_FORMAT, mDeviceFormat.toString());
+ extras.putString(PowerStats.Descriptor.EXTRA_STATE_STATS_FORMAT, mStateFormat.toString());
+ extras.putString(PowerStats.Descriptor.EXTRA_UID_STATS_FORMAT, mUidFormat.toString());
}
/**
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java
index 0d5c5422b45c..2fd0b9a9b001 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java
@@ -19,8 +19,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
-import com.android.internal.os.PowerStats;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -47,12 +45,6 @@ abstract class PowerStatsProcessor {
abstract void finish(PowerComponentAggregatedPowerStats stats);
- abstract String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats);
-
- abstract String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats);
-
- abstract String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats);
-
protected static class PowerEstimationPlan {
private final AggregatedPowerStatsConfig.PowerComponent mConfig;
public List<DeviceStateEstimation> deviceStateEstimations = new ArrayList<>();
diff --git a/services/core/java/com/android/server/power/stats/WifiPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/WifiPowerStatsLayout.java
index 0fa6ec65c4bc..e2e822690c55 100644
--- a/services/core/java/com/android/server/power/stats/WifiPowerStatsLayout.java
+++ b/services/core/java/com/android/server/power/stats/WifiPowerStatsLayout.java
@@ -65,28 +65,28 @@ public class WifiPowerStatsLayout extends PowerStatsLayout {
mPowerReportingSupported = powerReportingSupported;
if (mPowerReportingSupported) {
mDeviceActiveTimePosition = UNSPECIFIED;
- mDeviceRxTimePosition = addDeviceSection(1);
- mDeviceTxTimePosition = addDeviceSection(1);
- mDeviceIdleTimePosition = addDeviceSection(1);
- mDeviceScanTimePosition = addDeviceSection(1);
+ mDeviceRxTimePosition = addDeviceSection(1, "rx");
+ mDeviceTxTimePosition = addDeviceSection(1, "tx");
+ mDeviceIdleTimePosition = addDeviceSection(1, "idle");
+ mDeviceScanTimePosition = addDeviceSection(1, "scan");
} else {
- mDeviceActiveTimePosition = addDeviceSection(1);
+ mDeviceActiveTimePosition = addDeviceSection(1, "rx-tx");
mDeviceRxTimePosition = UNSPECIFIED;
mDeviceTxTimePosition = UNSPECIFIED;
mDeviceIdleTimePosition = UNSPECIFIED;
mDeviceScanTimePosition = UNSPECIFIED;
}
- mDeviceBasicScanTimePosition = addDeviceSection(1);
- mDeviceBatchedScanTimePosition = addDeviceSection(1);
+ mDeviceBasicScanTimePosition = addDeviceSection(1, "basic-scan", FLAG_OPTIONAL);
+ mDeviceBatchedScanTimePosition = addDeviceSection(1, "batched-scan", FLAG_OPTIONAL);
}
void addUidNetworkStats() {
- mUidRxBytesPosition = addUidSection(1);
- mUidTxBytesPosition = addUidSection(1);
- mUidRxPacketsPosition = addUidSection(1);
- mUidTxPacketsPosition = addUidSection(1);
- mUidScanTimePosition = addUidSection(1);
- mUidBatchScanTimePosition = addUidSection(1);
+ mUidRxPacketsPosition = addUidSection(1, "rx-pkts");
+ mUidRxBytesPosition = addUidSection(1, "rx-B");
+ mUidTxPacketsPosition = addUidSection(1, "tx-pkts");
+ mUidTxBytesPosition = addUidSection(1, "tx-B");
+ mUidScanTimePosition = addUidSection(1, "scan", FLAG_OPTIONAL);
+ mUidBatchScanTimePosition = addUidSection(1, "batched-scan", FLAG_OPTIONAL);
}
public boolean isPowerReportingSupported() {
diff --git a/services/core/java/com/android/server/power/stats/WifiPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/WifiPowerStatsProcessor.java
index 5e9cc4092029..a4a2e183f86b 100644
--- a/services/core/java/com/android/server/power/stats/WifiPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/WifiPowerStatsProcessor.java
@@ -389,37 +389,4 @@ public class WifiPowerStatsProcessor extends PowerStatsProcessor {
}
}
}
-
- @Override
- String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- if (mHasWifiPowerController) {
- return "rx: " + mStatsLayout.getDeviceRxTime(stats)
- + " tx: " + mStatsLayout.getDeviceTxTime(stats)
- + " scan: " + mStatsLayout.getDeviceScanTime(stats)
- + " idle: " + mStatsLayout.getDeviceIdleTime(stats)
- + " power: " + mStatsLayout.getDevicePowerEstimate(stats);
- } else {
- return "active: " + mStatsLayout.getDeviceActiveTime(stats)
- + " scan: " + mStatsLayout.getDeviceBasicScanTime(stats)
- + " batched-scan: " + mStatsLayout.getDeviceBatchedScanTime(stats)
- + " power: " + mStatsLayout.getDevicePowerEstimate(stats);
- }
- }
-
- @Override
- String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) {
- // Unsupported for this power component
- return null;
- }
-
- @Override
- String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {
- unpackPowerStatsDescriptor(descriptor);
- return "rx: " + mStatsLayout.getUidRxPackets(stats)
- + " tx: " + mStatsLayout.getUidTxPackets(stats)
- + " scan: " + mStatsLayout.getUidScanTime(stats)
- + " batched-scan: " + mStatsLayout.getUidBatchedScanTime(stats)
- + " power: " + mStatsLayout.getUidPowerEstimate(stats);
- }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
index 4e3e80f8ff10..b5bdafeb4696 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java
@@ -32,6 +32,7 @@ import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.IndentingPrintWriter;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -51,6 +52,7 @@ import org.mockito.MockitoAnnotations;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.io.StringWriter;
import java.util.function.IntSupplier;
@RunWith(AndroidJUnit4.class)
@@ -363,6 +365,36 @@ public class CpuPowerStatsCollectorTest {
.isEqualTo(528);
}
+ @Test
+ public void dump() {
+ mockCpuScalingPolicies(1);
+ mockPowerProfile();
+ mockEnergyConsumers();
+
+ CpuPowerStatsCollector collector = createCollector(8, 0);
+ collector.collectStats(); // Establish baseline
+
+ mockKernelCpuStats(new long[]{1111, 2222, 3333},
+ new SparseArray<>() {{
+ put(UID_1, new long[]{100, 200});
+ put(UID_2, new long[]{100, 150});
+ put(ISOLATED_UID, new long[]{200, 450});
+ }}, 0, 1234);
+
+ PowerStats powerStats = collector.collectStats();
+
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter pw = new IndentingPrintWriter(sw);
+ powerStats.dump(pw);
+ pw.flush();
+ String dump = sw.toString();
+
+ assertThat(dump).contains("duration=1234");
+ assertThat(dump).contains("steps: [1111, 2222, 3333]");
+ assertThat(dump).contains("UID 42: time: [100, 200]");
+ assertThat(dump).contains("UID 99: time: [300, 600]");
+ }
+
private void mockCpuScalingPolicies(int clusterCount) {
SparseArray<int[]> cpus = new SparseArray<>();
SparseArray<int[]> freqs = new SparseArray<>();
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
index 70c40f5052f0..644ae4717eb1 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.UserHandle;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -46,7 +47,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
@@ -92,9 +95,10 @@ public class CpuPowerStatsCollectorValidationTest {
long duration = 0;
long[] stats = null;
- String[] cpuStatsDump = dumpCpuStats();
+ List<String> cpuStatsDump = dumpCpuStats();
Pattern durationPattern = Pattern.compile("duration=([0-9]*)");
- Pattern uidPattern = Pattern.compile("UID " + mTestPkgUid + ": \\[([0-9,\\s]*)]");
+ Pattern uidPattern = Pattern.compile(
+ "UID " + UserHandle.formatUid(mTestPkgUid) + ": time: [\\[]?([0-9,\\s]*)[]]?");
for (String line : cpuStatsDump) {
Matcher durationMatcher = durationPattern.matcher(line);
if (durationMatcher.find()) {
@@ -119,15 +123,23 @@ public class CpuPowerStatsCollectorValidationTest {
assertThat(total).isAtLeast((long) (WORK_DURATION_MS * 0.8));
}
- private String[] dumpCpuStats() throws Exception {
+ private List<String> dumpCpuStats() throws Exception {
+ ArrayList<String> cpuStats = new ArrayList<>();
String dump = executeCmdSilent("dumpsys batterystats --sample");
String[] lines = dump.split("\n");
+ boolean inCpuSection = false;
for (int i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("CpuPowerStatsCollector")) {
- return Arrays.copyOfRange(lines, i + 1, lines.length);
+ if (!inCpuSection) {
+ if (lines[i].startsWith("CpuPowerStatsCollector")) {
+ inCpuSection = true;
+ }
+ } else if (lines[i].startsWith(" ")) {
+ cpuStats.add(lines[i]);
+ } else {
+ break;
}
}
- return new String[0];
+ return cpuStats;
}
private void doSomeWork() throws Exception {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
index f93c4da3d8d0..ca58db1bcad5 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java
@@ -337,12 +337,14 @@ public class MobileRadioPowerStatsCollectorTest {
pw.flush();
String dump = sw.toString();
assertThat(dump).contains("duration=100");
+ assertThat(dump).contains("sleep: 200 idle: 300 scan: 60000 call: 40000 energy: "
+ + ((64321 - 10000) * 1000 / 3500));
+ assertThat(dump).contains("(LTE) rx: 7000 tx: [8000, 9000, 1000, 2000, 3000]");
+ assertThat(dump).contains("(NR MMWAVE) rx: 6000 tx: [1000, 2000, 3000, 4000, 5000]");
assertThat(dump).contains(
- "stats=[200, 300, 60000, 40000, " + ((64321 - 10000) * 1000 / 3500) + ", 0, 0, 0]");
- assertThat(dump).contains("state LTE: [7000, 8000, 9000, 1000, 2000, 3000]");
- assertThat(dump).contains("state NR MMWAVE: [6000, 1000, 2000, 3000, 4000, 5000]");
- assertThat(dump).contains("UID 24: [6000, 3000, 60, 30, 0]");
- assertThat(dump).contains("UID 42: [1000, 2000, 100, 200, 0]");
+ "UID 24: rx-pkts: 60 rx-B: 6000 tx-pkts: 30 tx-B: 3000");
+ assertThat(dump).contains(
+ "UID 42: rx-pkts: 100 rx-B: 1000 tx-pkts: 200 tx-B: 2000");
}
private PowerStats collectPowerStats(boolean perNetworkTypeData) throws Throwable {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
index 4ac7ad8d07ff..d80ffb4a66c8 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java
@@ -305,7 +305,100 @@ public class MobileRadioPowerStatsProcessorTest {
}
@Test
- public void measuredEnergyModel() {
+ public void energyConsumerModel() {
+ PowerComponentAggregatedPowerStats aggregatedStats =
+ prepareAggregatedStats_energyConsumerModel();
+
+ MobileRadioPowerStatsLayout statsLayout =
+ new MobileRadioPowerStatsLayout(
+ aggregatedStats.getPowerStatsDescriptor());
+
+ // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+ double totalPower = 0;
+ long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength];
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.671837);
+ totalPower += statsLayout.getDevicePowerEstimate(deviceStats);
+ assertThat(statsLayout.getDeviceCallPowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.022494);
+ totalPower += statsLayout.getDeviceCallPowerEstimate(deviceStats);
+
+ aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(2.01596);
+ totalPower += statsLayout.getDevicePowerEstimate(deviceStats);
+ assertThat(statsLayout.getDeviceCallPowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.067484);
+ totalPower += statsLayout.getDeviceCallPowerEstimate(deviceStats);
+
+ // These estimates are supposed to add up to the measured energy, 2.77778 mAh
+ assertThat(totalPower).isWithin(PRECISION).of(2.77778);
+
+ double uidPower1 = 0;
+ long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength];
+ aggregatedStats.getUidStats(uidStats, APP_UID,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.198236);
+ uidPower1 += statsLayout.getUidPowerEstimate(uidStats);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.198236);
+ uidPower1 += statsLayout.getUidPowerEstimate(uidStats);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.396473);
+ uidPower1 += statsLayout.getUidPowerEstimate(uidStats);
+
+ double uidPower2 = 0;
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.066078);
+ uidPower2 += statsLayout.getUidPowerEstimate(uidStats);
+
+ aggregatedStats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.198236);
+ uidPower2 += statsLayout.getUidPowerEstimate(uidStats);
+
+ // Total power attributed to apps is significantly less than the grand total,
+ // because we only attribute TX/RX to apps but not maintaining a connection with the cell.
+ assertThat(uidPower1 + uidPower2)
+ .isWithin(PRECISION).of(1.057259);
+
+ // 3/4 of total packets were sent by APP_UID so 75% of total RX/TX power is attributed to it
+ assertThat(uidPower1 / (uidPower1 + uidPower2))
+ .isWithin(PRECISION).of(0.75);
+ }
+
+ @Test
+ public void test_toString() {
+ PowerComponentAggregatedPowerStats stats = prepareAggregatedStats_energyConsumerModel();
+ String string = stats.toString();
+ assertThat(string).contains("(pwr-other scr-on)"
+ + " sleep: 500 idle: 750 scan: 1388 call: 50 energy: 2500000 power: 0.672");
+ assertThat(string).contains("(pwr-other scr-other)"
+ + " sleep: 1500 idle: 2250 scan: 4166 call: 150 energy: 7500000 power: 2.02");
+ assertThat(string).contains("(pwr-other scr-on other)"
+ + " rx: 150 tx: [25, 50, 75, 100, 125]");
+ assertThat(string).contains("(pwr-other scr-other other)"
+ + " rx: 450 tx: [75, 150, 225, 300, 375]");
+ assertThat(string).contains("(pwr-other scr-on fg)"
+ + " rx-pkts: 375 rx-B: 2500 tx-pkts: 75 tx-B: 5000 power: 0.198");
+ assertThat(string).contains("(pwr-other scr-other bg)"
+ + " rx-pkts: 375 rx-B: 2500 tx-pkts: 75 tx-B: 5000 power: 0.198");
+ assertThat(string).contains("(pwr-other scr-other fgs)"
+ + " rx-pkts: 750 rx-B: 5000 tx-pkts: 150 tx-B: 10000 power: 0.396");
+ }
+
+ private PowerComponentAggregatedPowerStats prepareAggregatedStats_energyConsumerModel() {
// PowerStats hardware is available
when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.MOBILE_RADIO))
.thenReturn(new int[] {MOBILE_RADIO_ENERGY_CONSUMER_ID});
@@ -378,74 +471,7 @@ public class MobileRadioPowerStatsProcessorTest {
aggregatedStats.addPowerStats(powerStats, 10_000);
processor.finish(aggregatedStats);
-
- MobileRadioPowerStatsLayout statsLayout =
- new MobileRadioPowerStatsLayout(
- aggregatedStats.getPowerStatsDescriptor());
-
- // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
- double totalPower = 0;
- long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength];
- aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
- assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
- .isWithin(PRECISION).of(0.671837);
- totalPower += statsLayout.getDevicePowerEstimate(deviceStats);
- assertThat(statsLayout.getDeviceCallPowerEstimate(deviceStats))
- .isWithin(PRECISION).of(0.022494);
- totalPower += statsLayout.getDeviceCallPowerEstimate(deviceStats);
-
- aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
- assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
- .isWithin(PRECISION).of(2.01596);
- totalPower += statsLayout.getDevicePowerEstimate(deviceStats);
- assertThat(statsLayout.getDeviceCallPowerEstimate(deviceStats))
- .isWithin(PRECISION).of(0.067484);
- totalPower += statsLayout.getDeviceCallPowerEstimate(deviceStats);
-
- // These estimates are supposed to add up to the measured energy, 2.77778 mAh
- assertThat(totalPower).isWithin(PRECISION).of(2.77778);
-
- double uidPower1 = 0;
- long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength];
- aggregatedStats.getUidStats(uidStats, APP_UID,
- states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
- assertThat(statsLayout.getUidPowerEstimate(uidStats))
- .isWithin(PRECISION).of(0.198236);
- uidPower1 += statsLayout.getUidPowerEstimate(uidStats);
-
- aggregatedStats.getUidStats(uidStats, APP_UID,
- states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
- assertThat(statsLayout.getUidPowerEstimate(uidStats))
- .isWithin(PRECISION).of(0.198236);
- uidPower1 += statsLayout.getUidPowerEstimate(uidStats);
-
- aggregatedStats.getUidStats(uidStats, APP_UID,
- states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
- assertThat(statsLayout.getUidPowerEstimate(uidStats))
- .isWithin(PRECISION).of(0.396473);
- uidPower1 += statsLayout.getUidPowerEstimate(uidStats);
-
- double uidPower2 = 0;
- aggregatedStats.getUidStats(uidStats, APP_UID2,
- states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
- assertThat(statsLayout.getUidPowerEstimate(uidStats))
- .isWithin(PRECISION).of(0.066078);
- uidPower2 += statsLayout.getUidPowerEstimate(uidStats);
-
- aggregatedStats.getUidStats(uidStats, APP_UID2,
- states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
- assertThat(statsLayout.getUidPowerEstimate(uidStats))
- .isWithin(PRECISION).of(0.198236);
- uidPower2 += statsLayout.getUidPowerEstimate(uidStats);
-
- // Total power attributed to apps is significantly less than the grand total,
- // because we only attribute TX/RX to apps but not maintaining a connection with the cell.
- assertThat(uidPower1 + uidPower2)
- .isWithin(PRECISION).of(1.057259);
-
- // 3/4 of total packets were sent by APP_UID so 75% of total RX/TX power is attributed to it
- assertThat(uidPower1 / (uidPower1 + uidPower2))
- .isWithin(PRECISION).of(0.75);
+ return aggregatedStats;
}
private int[] states(int... states) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
index 1b045c532759..ae258cd3c234 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MultiStateStatsTest.java
@@ -29,8 +29,6 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.PrintWriter;
-import java.io.StringWriter;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@@ -165,7 +163,7 @@ public class MultiStateStatsTest {
}
@Test
- public void dump() {
+ public void test_toString() {
MultiStateStats.Factory factory = makeFactory(true, true, false);
MultiStateStats multiStateStats = factory.create();
multiStateStats.setState(0 /* batteryState */, 0 /* off */, 1000);
@@ -175,13 +173,10 @@ public class MultiStateStatsTest {
multiStateStats.setState(1 /* procState */, BatteryConsumer.PROCESS_STATE_BACKGROUND, 3000);
multiStateStats.increment(new long[]{100, 200}, 5000);
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw, true);
- multiStateStats.dump(pw, Arrays::toString);
- assertThat(sw.toString()).isEqualTo(
- "plugged-in fg [25, 50]\n"
- + "on-battery fg [25, 50]\n"
- + "on-battery bg [50, 100]\n"
+ assertThat(multiStateStats.toString()).isEqualTo(
+ "(plugged-in fg) [25, 50]\n"
+ + "(on-battery fg) [25, 50]\n"
+ + "(on-battery bg) [50, 100]"
);
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
index 8b1d423abd21..b4c012b3460f 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerStatsCollectorTest.java
@@ -304,10 +304,14 @@ public class WifiPowerStatsCollectorTest {
String dump = sw.toString();
assertThat(dump).contains("duration=7500");
assertThat(dump).contains(
- "stats=[6000, 1000, 300, 200, 634, 945, " + ((64321 - 10000) * 1000 / 3500)
- + ", 0, 0]");
- assertThat(dump).contains("UID 24: [6000, 3000, 60, 30, 400, 600, 0]");
- assertThat(dump).contains("UID 42: [1000, 2000, 100, 200, 234, 345, 0]");
+ "rx: 6000 tx: 1000 idle: 300 scan: 200 basic-scan: 634 batched-scan: 945"
+ + " energy: " + ((64321 - 10000) * 1000 / 3500));
+ assertThat(dump).contains(
+ "UID 24: rx-pkts: 60 rx-B: 6000 tx-pkts: 30 tx-B: 3000"
+ + " scan: 400 batched-scan: 600");
+ assertThat(dump).contains(
+ "UID 42: rx-pkts: 100 rx-B: 1000 tx-pkts: 200 tx-B: 2000"
+ + " scan: 234 batched-scan: 345");
}
private PowerStats collectPowerStats(boolean hasPowerReporting) {