summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/PowerComponents.java78
-rw-r--r--core/proto/android/os/batteryusagestats.proto20
-rw-r--r--core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java63
3 files changed, 140 insertions, 21 deletions
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 4b12aa6a2634..e8631119bbc6 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -223,22 +223,32 @@ class PowerComponents {
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
componentId++) {
- final BatteryConsumer.Key key = mData.getKey(componentId, PROCESS_STATE_ANY);
- final long powerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower(key));
- final long durationMs = getUsageDurationMillis(key);
+ final BatteryConsumer.Key[] keys = mData.getKeys(componentId);
+ for (BatteryConsumer.Key key : keys) {
+ 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.
- continue;
- }
+ if (powerDeciCoulombs == 0 && durationMs == 0) {
+ // No interesting data. Make sure not to even write the COMPONENT int.
+ continue;
+ }
- interestingData = true;
- if (proto == null) {
- // We're just asked whether there is data, not to actually write it. And there is.
- return true;
- }
+ interestingData = true;
+ if (proto == null) {
+ // We're just asked whether there is data, not to actually write it.
+ // And there is.
+ return true;
+ }
- writePowerComponent(proto, componentId, powerDeciCoulombs, durationMs);
+ if (key.processState == PROCESS_STATE_ANY) {
+ writePowerComponentUsage(proto,
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS,
+ componentId, powerDeciCoulombs, durationMs);
+ } else {
+ writePowerUsageSlice(proto, componentId, powerDeciCoulombs, durationMs,
+ key.processState);
+ }
+ }
}
for (int idx = 0; idx < mData.layout.customPowerComponentCount; idx++) {
final int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + idx;
@@ -257,15 +267,49 @@ class PowerComponents {
return true;
}
- writePowerComponent(proto, componentId, powerDeciCoulombs, durationMs);
+ writePowerComponentUsage(proto,
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS,
+ componentId, powerDeciCoulombs, durationMs);
}
return interestingData;
}
- private void writePowerComponent(ProtoOutputStream proto, int componentId,
+ private void writePowerUsageSlice(ProtoOutputStream proto, int componentId,
+ long powerDeciCoulombs, long durationMs, int processState) {
+ final long slicesToken =
+ proto.start(BatteryUsageStatsAtomsProto.BatteryConsumerData.SLICES);
+ writePowerComponentUsage(proto,
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .POWER_COMPONENT,
+ componentId, powerDeciCoulombs, durationMs);
+
+ final int procState;
+ switch (processState) {
+ case BatteryConsumer.PROCESS_STATE_FOREGROUND:
+ procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .FOREGROUND;
+ break;
+ case BatteryConsumer.PROCESS_STATE_BACKGROUND:
+ procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .BACKGROUND;
+ break;
+ case BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE:
+ procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .FOREGROUND_SERVICE;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown process state: " + processState);
+ }
+
+ proto.write(BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .PROCESS_STATE, procState);
+
+ proto.end(slicesToken);
+ }
+
+ private void writePowerComponentUsage(ProtoOutputStream proto, long tag, int componentId,
long powerDeciCoulombs, long durationMs) {
- final long token =
- proto.start(BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS);
+ final long token = proto.start(tag);
proto.write(
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
.COMPONENT,
diff --git a/core/proto/android/os/batteryusagestats.proto b/core/proto/android/os/batteryusagestats.proto
index bcce784ae0be..c0a9f0339d9e 100644
--- a/core/proto/android/os/batteryusagestats.proto
+++ b/core/proto/android/os/batteryusagestats.proto
@@ -62,6 +62,26 @@ message BatteryUsageStatsAtomsProto {
optional int64 duration_millis = 3;
}
repeated PowerComponentUsage power_components = 2;
+
+ // Represents a slice of power attribution, e.g. "cpu while in the background"
+ // or "wifi when running a background service". Queries that care about
+ // PowerComponentUsage slices need to be aware of all supported dimensions.
+ // There are no roll-ups included in the slices - it is up to the clients
+ // of this data to aggregate values as needed.
+ message PowerComponentUsageSlice {
+ optional PowerComponentUsage power_component = 1;
+
+ enum ProcessState {
+ UNSPECIFIED = 0;
+ FOREGROUND = 1;
+ BACKGROUND = 2;
+ FOREGROUND_SERVICE = 3;
+ }
+
+ optional ProcessState process_state = 2;
+ }
+
+ repeated PowerComponentUsageSlice slices = 3;
}
// Total power usage for the device during this session.
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index 7ff76df17615..e230a54e261f 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
import android.os.BatteryUsageStats;
+import android.os.UidBatteryConsumer;
import android.os.nano.BatteryUsageStatsAtomsProto;
import android.os.nano.BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage;
@@ -134,6 +135,43 @@ public class BatteryUsageStatsPulledTest {
componentProto.durationMillis);
}
}
+
+ for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
+ componentId++) {
+ final BatteryConsumer.Key[] keys = consumer.getKeys(componentId);
+ if (keys == null || keys.length <= 1) {
+ continue;
+ }
+
+ for (BatteryConsumer.Key key : keys) {
+ if (key.processState == 0) {
+ continue;
+ }
+
+ BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ sliceProto = null;
+ for (BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ slice : consumerProto.slices) {
+ if (slice.powerComponent.component == componentId
+ && slice.processState == key.processState) {
+ sliceProto = slice;
+ break;
+ }
+ }
+
+ final long expectedPowerDc = convertMahToDc(consumer.getConsumedPower(key));
+ final long expectedUsageDurationMillis = consumer.getUsageDurationMillis(key);
+ if (expectedPowerDc == 0 && expectedUsageDurationMillis == 0) {
+ assertThat(sliceProto).isNull();
+ } else {
+ assertThat(sliceProto).isNotNull();
+ assertThat(sliceProto.powerComponent.powerDeciCoulombs)
+ .isEqualTo(expectedPowerDc);
+ assertThat(sliceProto.powerComponent.durationMillis)
+ .isEqualTo(expectedUsageDurationMillis);
+ }
+ }
+ }
}
private void assertSameUidBatteryConsumer(
@@ -172,14 +210,17 @@ public class BatteryUsageStatsPulledTest {
final BatteryStatsImpl.Uid batteryStatsUid3 = batteryStats.getUidStatsLocked(UID_3);
final BatteryUsageStats.Builder builder =
- new BatteryUsageStats.Builder(new String[]{"CustomConsumer1", "CustomConsumer2"})
+ new BatteryUsageStats.Builder(new String[]{"CustomConsumer1", "CustomConsumer2"},
+ /* includePowerModels */ true,
+ /* includeProcessStats */true)
.setDischargePercentage(20)
.setDischargedPowerRange(1000, 2000)
.setStatsStartTimestamp(1000);
- builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid0)
+ final UidBatteryConsumer.Builder uidBuilder = builder.getOrCreateUidBatteryConsumerBuilder(
+ batteryStatsUid0)
.setPackageWithHighestDrain("myPackage0")
- .setTimeInStateMs(android.os.UidBatteryConsumer.STATE_FOREGROUND, 1000)
- .setTimeInStateMs(android.os.UidBatteryConsumer.STATE_BACKGROUND, 2000)
+ .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
+ .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_SCREEN, 300)
.setConsumedPower(
@@ -193,6 +234,20 @@ public class BatteryUsageStatsPulledTest {
.setUsageDurationForCustomComponentMillis(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + 1, 800);
+ final BatteryConsumer.Key keyFg = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND);
+ final BatteryConsumer.Key keyBg = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_BACKGROUND);
+ final BatteryConsumer.Key keyFgs = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+
+ uidBuilder.setConsumedPower(keyFg, 9100, BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+ .setUsageDurationMillis(keyFg, 8100)
+ .setConsumedPower(keyBg, 9200, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
+ .setUsageDurationMillis(keyBg, 8200)
+ .setConsumedPower(keyFgs, 9300, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
+ .setUsageDurationMillis(keyFgs, 8300);
+
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid1)
.setPackageWithHighestDrain("myPackage1")
.setTimeInStateMs(android.os.UidBatteryConsumer.STATE_FOREGROUND, 1234);