Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb02f0d9 authored by Michael Wachenschwanz's avatar Michael Wachenschwanz
Browse files

Add Power Model info to the BatteryUsageStats atom

Test: atest BatteryUsageStatsPulledTest
Fixes: 241575236
Change-Id: I8dc3df7ed70914db99581cb8a2f616bb2cd9ea8e
parent 1d6ee308
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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.
     */
+15 −0
Original line number Diff line number Diff line
@@ -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.
     */
+5 −2
Original line number Diff line number Diff line
@@ -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);
    }

+17 −0
Original line number Diff line number Diff line
@@ -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;
}
+45 −5
Original line number Diff line number Diff line
@@ -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++) {
Loading