Merge "Add Power Model info to the BatteryUsageStats atom"

This commit is contained in:
Michael Wachenschwanz
2022-08-10 23:10:52 +00:00
committed by Android (Google) Code Review
6 changed files with 98 additions and 7 deletions

View File

@@ -19,6 +19,7 @@ package android.os;
import android.annotation.NonNull;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -97,6 +98,19 @@ public final class AggregateBatteryConsumer extends BatteryConsumer {
}
}
void writePowerComponentModelProto(@NonNull ProtoOutputStream proto) {
for (int i = 0; i < POWER_COMPONENT_COUNT; i++) {
final int powerModel = getPowerModel(i);
if (powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) continue;
final long token = proto.start(BatteryUsageStatsAtomsProto.COMPONENT_MODELS);
proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.COMPONENT, i);
proto.write(BatteryUsageStatsAtomsProto.PowerComponentModel.POWER_MODEL,
powerModelToProtoEnum(powerModel));
proto.end(token);
}
}
/**
* Builder for DeviceBatteryConsumer.
*/

View File

@@ -478,6 +478,21 @@ public abstract class BatteryConsumer {
}
}
/**
* Returns the equivalent PowerModel enum for the specified power model.
* {@see BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage.PowerModel}
*/
public static int powerModelToProtoEnum(@BatteryConsumer.PowerModel int powerModel) {
switch (powerModel) {
case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
return BatteryUsageStatsAtomsProto.PowerComponentModel.MEASURED_ENERGY;
case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
return BatteryUsageStatsAtomsProto.PowerComponentModel.POWER_PROFILE;
default:
return BatteryUsageStatsAtomsProto.PowerComponentModel.UNDEFINED;
}
}
/**
* Returns the name of the specified process state. Intended for logging and debugging.
*/

View File

@@ -276,7 +276,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
/**
* Returns a battery consumer for the specified battery consumer type.
*/
public BatteryConsumer getAggregateBatteryConsumer(
public AggregateBatteryConsumer getAggregateBatteryConsumer(
@AggregateBatteryConsumerScope int scope) {
return mAggregateBatteryConsumers[scope];
}
@@ -450,7 +450,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
@NonNull
private void writeStatsProto(ProtoOutputStream proto, int maxRawSize) {
final BatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
final AggregateBatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, getStatsStartTimestamp());
@@ -462,6 +462,9 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
getDischargeDurationMs());
deviceBatteryConsumer.writeStatsProto(proto,
BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER);
if (mIncludesPowerModels) {
deviceBatteryConsumer.writePowerComponentModelProto(proto);
}
writeUidBatteryConsumersProto(proto, maxRawSize);
}

View File

@@ -102,4 +102,21 @@ message BatteryUsageStatsAtomsProto {
// Total amount of time battery was discharging during the reported session
optional int64 discharge_duration_millis = 7;
// Notes the power model used for a power component.
message PowerComponentModel {
// Holds android.os.PowerComponentEnum, or custom component value between 1000 and 9999.
optional int32 component = 1;
enum PowerModel {
UNDEFINED = 0;
POWER_PROFILE = 1;
MEASURED_ENERGY = 2;
}
optional PowerModel power_model = 2;
}
// The power model used for each power component.
repeated PowerComponentModel component_models = 8;
}

View File

@@ -24,6 +24,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import android.os.AggregateBatteryConsumer;
import android.os.BatteryConsumer;
import android.os.BatteryUsageStats;
import android.os.UidBatteryConsumer;
@@ -69,10 +70,17 @@ public class BatteryUsageStatsPulledTest {
assertEquals(bus.getDischargeDurationMs(), proto.dischargeDurationMillis);
assertEquals(3, proto.deviceBatteryConsumer.powerComponents.length); // Only 3 are non-empty
final AggregateBatteryConsumer abc = bus.getAggregateBatteryConsumer(
AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
assertSameBatteryConsumer("For deviceBatteryConsumer",
bus.getAggregateBatteryConsumer(AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE),
proto.deviceBatteryConsumer);
for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) {
assertPowerComponentModel(i, abc.getPowerModel(i), proto);
}
// Now for the UidBatteryConsumers.
final List<android.os.UidBatteryConsumer> uidConsumers = bus.getUidBatteryConsumers();
uidConsumers.sort((a, b) -> a.getUid() - b.getUid());
@@ -196,6 +204,34 @@ public class BatteryUsageStatsPulledTest {
}
}
/**
* Validates the PowerComponentModel object that matches powerComponent.
*/
private void assertPowerComponentModel(int powerComponent,
@BatteryConsumer.PowerModel int powerModel, BatteryUsageStatsAtomsProto proto) {
boolean found = false;
for (BatteryUsageStatsAtomsProto.PowerComponentModel powerComponentModel :
proto.componentModels) {
if (powerComponentModel.component == powerComponent) {
if (found) {
fail("Power component " + BatteryConsumer.powerComponentIdToString(
powerComponent) + " found multiple times in the proto");
}
found = true;
final int expectedPowerModel = BatteryConsumer.powerModelToProtoEnum(powerModel);
assertEquals(expectedPowerModel, powerComponentModel.powerModel);
}
}
if (!found) {
final int model = BatteryConsumer.powerModelToProtoEnum(powerModel);
assertEquals(
"Power component " + BatteryConsumer.powerComponentIdToString(powerComponent)
+ " was not found in the proto but has a defined power model.",
BatteryUsageStatsAtomsProto.PowerComponentModel.UNDEFINED,
model);
}
}
/** Converts charge from milliamp hours (mAh) to decicoulombs (dC). */
private long convertMahToDc(double powerMah) {
return (long) (powerMah * 36 + 0.5);
@@ -259,11 +295,14 @@ public class BatteryUsageStatsPulledTest {
builder.getAggregateBatteryConsumerBuilder(AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
.setConsumedPower(30000)
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_CPU, 20100)
BatteryConsumer.POWER_COMPONENT_CPU, 20100,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_AUDIO, 0) // Empty
BatteryConsumer.POWER_COMPONENT_AUDIO, 0,
BatteryConsumer.POWER_MODEL_POWER_PROFILE) // Empty
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_CAMERA, 20150)
BatteryConsumer.POWER_COMPONENT_CAMERA, 20150,
BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
.setConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20200)
.setUsageDurationMillis(
@@ -275,7 +314,8 @@ public class BatteryUsageStatsPulledTest {
builder.getAggregateBatteryConsumerBuilder(
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_CPU, 10100)
BatteryConsumer.POWER_COMPONENT_CPU, 10100,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
.setConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
@@ -285,7 +325,7 @@ public class BatteryUsageStatsPulledTest {
@Test
public void testLargeAtomTruncated() {
final BatteryUsageStats.Builder builder =
new BatteryUsageStats.Builder(new String[0]);
new BatteryUsageStats.Builder(new String[0], true, false);
// If not truncated, this BatteryUsageStats object would generate a proto buffer
// significantly larger than 50 Kb
for (int i = 0; i < 3000; i++) {

View File

@@ -758,6 +758,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
.setMaxStatsAgeMs(0)
.includeProcessStateData()
.includeVirtualUids()
.includePowerModels()
.build();
bus = getBatteryUsageStats(List.of(querySinceReset)).get(0);
break;
@@ -768,6 +769,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
.includeProcessStateData()
.includeVirtualUids()
.powerProfileModeledOnly()
.includePowerModels()
.build();
bus = getBatteryUsageStats(List.of(queryPowerProfile)).get(0);
break;