Merge "Add process state to BatteryUsageStats atoms"
This commit is contained in:
committed by
Android (Google) Code Review
commit
7582c4accc
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user