Add process state to BatteryUsageStats atoms

Bug: 191921016
Test: atest BatteryUsageStatsProtoTests:BatteryUsageStatsPulledTest

Change-Id: Id047aa2e1fcf5318c3fd6620e6d41bcb172c6b31
This commit is contained in:
Dmitri Plotnikov
2021-11-01 10:06:24 -07:00
parent 6b93377684
commit 79978c195f
3 changed files with 141 additions and 22 deletions

View File

@@ -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;
}
if (key.processState == PROCESS_STATE_ANY) {
writePowerComponentUsage(proto,
BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS,
componentId, powerDeciCoulombs, durationMs);
} else {
writePowerUsageSlice(proto, componentId, powerDeciCoulombs, durationMs,
key.processState);
}
}
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);
}
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,

View File

@@ -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.

View File

@@ -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);