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

Commit d82aa7e5 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Convert BatteryUsageStats to and from XML

Bug: 187223764
Test: atest FrameworksCoreTests:BatteryUsageStatsTest#testXml
Change-Id: I6aec09bfb87c1003ede1b24cce8cf474675d2448
Merged-In: I6aec09bfb87c1003ede1b24cce8cf474675d2448
(cherry picked from commit 4b8a26bc)
parent 36e0ae27
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -17,7 +17,13 @@
package android.os;

import android.annotation.NonNull;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;

/**
@@ -72,6 +78,43 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
        return mConsumedPowerMah;
    }

    /** Serializes this object to XML */
    void writeToXml(TypedXmlSerializer serializer,
            @BatteryUsageStats.AggregateBatteryConsumerScope int scope) throws IOException {
        serializer.startTag(null, BatteryUsageStats.XML_TAG_AGGREGATE);
        serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_SCOPE, scope);
        serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, mConsumedPowerMah);
        mPowerComponents.writeToXml(serializer);
        serializer.endTag(null, BatteryUsageStats.XML_TAG_AGGREGATE);
    }

    /** Parses an XML representation and populates the BatteryUsageStats builder */
    static void parseXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)
            throws XmlPullParserException, IOException {
        final int scope = parser.getAttributeInt(null, BatteryUsageStats.XML_ATTR_SCOPE);
        final Builder consumerBuilder = builder.getAggregateBatteryConsumerBuilder(scope);

        int eventType = parser.getEventType();
        if (eventType != XmlPullParser.START_TAG || !parser.getName().equals(
                BatteryUsageStats.XML_TAG_AGGREGATE)) {
            throw new XmlPullParserException("Invalid XML parser state");
        }

        consumerBuilder.setConsumedPower(
                parser.getAttributeDouble(null, BatteryUsageStats.XML_ATTR_POWER));

        while (!(eventType == XmlPullParser.END_TAG && parser.getName().equals(
                BatteryUsageStats.XML_TAG_AGGREGATE))
                && eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                if (parser.getName().equals(BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
                    PowerComponents.parseXml(parser, consumerBuilder.mPowerComponentsBuilder);
                }
            }
            eventType = parser.next();
        }
    }

    /**
     * Builder for DeviceBatteryConsumer.
     */
+137 −0
Original line number Diff line number Diff line
@@ -20,12 +20,18 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.util.Range;
import android.util.SparseArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;

import com.android.internal.os.BatteryStatsHistory;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.PowerCalculator;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -78,6 +84,34 @@ public final class BatteryUsageStats implements Parcelable {

    private static final int STATSD_PULL_ATOM_MAX_BYTES = 45000;

    // XML tags and attributes for BatteryUsageStats persistence
    static final String XML_TAG_BATTERY_USAGE_STATS = "battery_usage_stats";
    static final String XML_TAG_AGGREGATE = "aggregate";
    static final String XML_TAG_UID = "uid";
    static final String XML_TAG_USER = "user";
    static final String XML_TAG_POWER_COMPONENTS = "power_components";
    static final String XML_TAG_COMPONENT = "component";
    static final String XML_TAG_CUSTOM_COMPONENT = "custom_component";
    static final String XML_ATTR_ID = "id";
    static final String XML_ATTR_UID = "uid";
    static final String XML_ATTR_USER_ID = "user_id";
    static final String XML_ATTR_SCOPE = "scope";
    static final String XML_ATTR_PREFIX_CUSTOM_COMPONENT = "custom_component_";
    static final String XML_ATTR_START_TIMESTAMP = "start_timestamp";
    static final String XML_ATTR_END_TIMESTAMP = "end_timestamp";
    static final String XML_ATTR_POWER = "power";
    static final String XML_ATTR_DURATION = "duration";
    static final String XML_ATTR_MODEL = "model";
    static final String XML_ATTR_BATTERY_CAPACITY = "battery_capacity";
    static final String XML_ATTR_DISCHARGE_PERCENT = "discharge_pct";
    static final String XML_ATTR_DISCHARGE_LOWER = "discharge_lower";
    static final String XML_ATTR_DISCHARGE_UPPER = "discharge_upper";
    static final String XML_ATTR_BATTERY_REMAINING = "battery_remaining";
    static final String XML_ATTR_CHARGE_REMAINING = "charge_remaining";
    static final String XML_ATTR_HIGHEST_DRAIN_PACKAGE = "highest_drain_package";
    static final String XML_ATTR_TIME_IN_FOREGROUND = "time_in_foreground";
    static final String XML_ATTR_TIME_IN_BACKGROUND = "time_in_background";

    private final int mDischargePercentage;
    private final double mBatteryCapacityMah;
    private final long mStatsStartTimestampMs;
@@ -576,6 +610,109 @@ public final class BatteryUsageStats implements Parcelable {
        }
    }

    /** Serializes this object to XML */
    public void writeXml(TypedXmlSerializer serializer) throws IOException {
        serializer.startTag(null, XML_TAG_BATTERY_USAGE_STATS);

        for (int i = 0; i < mCustomPowerComponentNames.length; i++) {
            serializer.attribute(null, XML_ATTR_PREFIX_CUSTOM_COMPONENT + i,
                    mCustomPowerComponentNames[i]);
        }

        serializer.attributeLong(null, XML_ATTR_START_TIMESTAMP, mStatsStartTimestampMs);
        serializer.attributeLong(null, XML_ATTR_END_TIMESTAMP, mStatsEndTimestampMs);
        serializer.attributeLong(null, XML_ATTR_DURATION, mStatsDurationMs);
        serializer.attributeDouble(null, XML_ATTR_BATTERY_CAPACITY, mBatteryCapacityMah);
        serializer.attributeInt(null, XML_ATTR_DISCHARGE_PERCENT, mDischargePercentage);
        serializer.attributeDouble(null, XML_ATTR_DISCHARGE_LOWER, mDischargedPowerLowerBound);
        serializer.attributeDouble(null, XML_ATTR_DISCHARGE_UPPER, mDischargedPowerUpperBound);
        serializer.attributeLong(null, XML_ATTR_BATTERY_REMAINING, mBatteryTimeRemainingMs);
        serializer.attributeLong(null, XML_ATTR_CHARGE_REMAINING, mChargeTimeRemainingMs);

        for (int scope = 0; scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT;
                scope++) {
            mAggregateBatteryConsumers[scope].writeToXml(serializer, scope);
        }
        for (UidBatteryConsumer consumer : mUidBatteryConsumers) {
            consumer.writeToXml(serializer);
        }
        for (UserBatteryConsumer consumer : mUserBatteryConsumers) {
            consumer.writeToXml(serializer);
        }
        serializer.endTag(null, XML_TAG_BATTERY_USAGE_STATS);
    }

    /** Parses an XML representation of BatteryUsageStats */
    public static BatteryUsageStats createFromXml(TypedXmlPullParser parser)
            throws XmlPullParserException, IOException {
        Builder builder = null;
        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG
                    && parser.getName().equals(XML_TAG_BATTERY_USAGE_STATS)) {
                List<String> customComponentNames = new ArrayList<>();
                int i = 0;
                while (true) {
                    int index = parser.getAttributeIndex(null,
                            XML_ATTR_PREFIX_CUSTOM_COMPONENT + i);
                    if (index == -1) {
                        break;
                    }
                    customComponentNames.add(parser.getAttributeValue(index));
                    i++;
                }

                builder = new Builder(
                        customComponentNames.toArray(new String[0]), true);

                builder.setStatsStartTimestamp(
                        parser.getAttributeLong(null, XML_ATTR_START_TIMESTAMP));
                builder.setStatsEndTimestamp(
                        parser.getAttributeLong(null, XML_ATTR_END_TIMESTAMP));
                builder.setStatsDuration(
                        parser.getAttributeLong(null, XML_ATTR_DURATION));
                builder.setBatteryCapacity(
                        parser.getAttributeDouble(null, XML_ATTR_BATTERY_CAPACITY));
                builder.setDischargePercentage(
                        parser.getAttributeInt(null, XML_ATTR_DISCHARGE_PERCENT));
                builder.setDischargedPowerRange(
                        parser.getAttributeDouble(null, XML_ATTR_DISCHARGE_LOWER),
                        parser.getAttributeDouble(null, XML_ATTR_DISCHARGE_UPPER));
                builder.setBatteryTimeRemainingMs(
                        parser.getAttributeLong(null, XML_ATTR_BATTERY_REMAINING));
                builder.setChargeTimeRemainingMs(
                        parser.getAttributeLong(null, XML_ATTR_CHARGE_REMAINING));

                eventType = parser.next();
                break;
            }
            eventType = parser.next();
        }

        if (builder == null) {
            throw new XmlPullParserException("No root element");
        }

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                switch (parser.getName()) {
                    case XML_TAG_AGGREGATE:
                        AggregateBatteryConsumer.parseXml(parser, builder);
                        break;
                    case XML_TAG_UID:
                        UidBatteryConsumer.createFromXml(parser, builder);
                        break;
                    case XML_TAG_USER:
                        UserBatteryConsumer.createFromXml(parser, builder);
                        break;
                }
            }
            eventType = parser.next();
        }

        return builder.build();
    }

    /**
     * Builder for BatteryUsageStats.
     */
+122 −0
Original line number Diff line number Diff line
@@ -19,10 +19,16 @@ import static android.os.BatteryConsumer.convertMahToDeciCoulombs;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;

import com.android.internal.os.PowerCalculator;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

@@ -302,6 +308,122 @@ class PowerComponents {
        return interestingData;
    }

    void writeToXml(TypedXmlSerializer serializer) throws IOException {
        serializer.startTag(null, BatteryUsageStats.XML_TAG_POWER_COMPONENTS);
        for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
                componentId++) {
            final double powerMah = getConsumedPower(componentId);
            final long durationMs = getUsageDurationMillis(componentId);
            if (powerMah == 0 && durationMs == 0) {
                continue;
            }

            serializer.startTag(null, BatteryUsageStats.XML_TAG_COMPONENT);
            serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_ID, componentId);
            if (powerMah != 0) {
                serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, powerMah);
            }
            if (durationMs != 0) {
                serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs);
            }
            if (mPowerModels != null) {
                serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_MODEL,
                        mPowerModels[componentId]);
            }
            serializer.endTag(null, BatteryUsageStats.XML_TAG_COMPONENT);
        }

        final int customComponentEnd =
                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + mCustomPowerComponentCount;
        for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
                componentId < customComponentEnd;
                componentId++) {
            final double powerMah = getConsumedPowerForCustomComponent(componentId);
            final long durationMs = getUsageDurationForCustomComponentMillis(componentId);
            if (powerMah == 0 && durationMs == 0) {
                continue;
            }

            serializer.startTag(null, BatteryUsageStats.XML_TAG_CUSTOM_COMPONENT);
            serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_ID, componentId);
            if (powerMah != 0) {
                serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, powerMah);
            }
            if (durationMs != 0) {
                serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs);
            }
            serializer.endTag(null, BatteryUsageStats.XML_TAG_CUSTOM_COMPONENT);
        }

        serializer.endTag(null, BatteryUsageStats.XML_TAG_POWER_COMPONENTS);
    }


    static void parseXml(TypedXmlPullParser parser, PowerComponents.Builder builder)
            throws XmlPullParserException, IOException {
        int eventType = parser.getEventType();
        if (eventType != XmlPullParser.START_TAG || !parser.getName().equals(
                BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
            throw new XmlPullParserException("Invalid XML parser state");
        }

        while (!(eventType == XmlPullParser.END_TAG && parser.getName().equals(
                BatteryUsageStats.XML_TAG_POWER_COMPONENTS))
                && eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                switch (parser.getName()) {
                    case BatteryUsageStats.XML_TAG_COMPONENT: {
                        int componentId = -1;
                        double powerMah = 0;
                        long durationMs = 0;
                        int model = BatteryConsumer.POWER_MODEL_UNDEFINED;
                        for (int i = 0; i < parser.getAttributeCount(); i++) {
                            switch (parser.getAttributeName(i)) {
                                case BatteryUsageStats.XML_ATTR_ID:
                                    componentId = parser.getAttributeInt(i);
                                    break;
                                case BatteryUsageStats.XML_ATTR_POWER:
                                    powerMah = parser.getAttributeDouble(i);
                                    break;
                                case BatteryUsageStats.XML_ATTR_DURATION:
                                    durationMs = parser.getAttributeLong(i);
                                    break;
                                case BatteryUsageStats.XML_ATTR_MODEL:
                                    model = parser.getAttributeInt(i);
                                    break;
                            }
                        }
                        builder.setConsumedPower(componentId, powerMah, model);
                        builder.setUsageDurationMillis(componentId, durationMs);
                        break;
                    }
                    case BatteryUsageStats.XML_TAG_CUSTOM_COMPONENT: {
                        int componentId = -1;
                        double powerMah = 0;
                        long durationMs = 0;
                        for (int i = 0; i < parser.getAttributeCount(); i++) {
                            switch (parser.getAttributeName(i)) {
                                case BatteryUsageStats.XML_ATTR_ID:
                                    componentId = parser.getAttributeInt(i);
                                    break;
                                case BatteryUsageStats.XML_ATTR_POWER:
                                    powerMah = parser.getAttributeDouble(i);
                                    break;
                                case BatteryUsageStats.XML_ATTR_DURATION:
                                    durationMs = parser.getAttributeLong(i);
                                    break;
                            }
                        }
                        builder.setConsumedPowerForCustomComponent(componentId, powerMah);
                        builder.setUsageDurationForCustomComponentMillis(componentId, durationMs);
                        break;
                    }
                }
            }
            eventType = parser.next();
        }
    }

    /**
     * Builder for PowerComponents.
     */
+57 −0
Original line number Diff line number Diff line
@@ -20,9 +20,15 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;

import com.android.internal.os.PowerCalculator;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -144,6 +150,57 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
        return 0;
    }

    /** Serializes this object to XML */
    void writeToXml(TypedXmlSerializer serializer) throws IOException {
        if (getConsumedPower() == 0) {
            return;
        }

        serializer.startTag(null, BatteryUsageStats.XML_TAG_UID);
        serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_UID, getUid());
        if (!TextUtils.isEmpty(mPackageWithHighestDrain)) {
            serializer.attribute(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE,
                    mPackageWithHighestDrain);
        }
        serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND,
                mTimeInForegroundMs);
        serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND,
                mTimeInBackgroundMs);
        mPowerComponents.writeToXml(serializer);
        serializer.endTag(null, BatteryUsageStats.XML_TAG_UID);
    }

    /** Parses an XML representation and populates the BatteryUsageStats builder */
    static void createFromXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)
            throws XmlPullParserException, IOException {
        final int uid = parser.getAttributeInt(null, BatteryUsageStats.XML_ATTR_UID);
        final UidBatteryConsumer.Builder consumerBuilder =
                builder.getOrCreateUidBatteryConsumerBuilder(uid);

        int eventType = parser.getEventType();
        if (eventType != XmlPullParser.START_TAG
                || !parser.getName().equals(BatteryUsageStats.XML_TAG_UID)) {
            throw new XmlPullParserException("Invalid XML parser state");
        }

        consumerBuilder.setPackageWithHighestDrain(
                parser.getAttributeValue(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE));
        consumerBuilder.setTimeInStateMs(STATE_FOREGROUND,
                parser.getAttributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND));
        consumerBuilder.setTimeInStateMs(STATE_BACKGROUND,
                parser.getAttributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND));
        while (!(eventType == XmlPullParser.END_TAG
                && parser.getName().equals(BatteryUsageStats.XML_TAG_UID))
                && eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                if (parser.getName().equals(BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
                    PowerComponents.parseXml(parser, consumerBuilder.mPowerComponentsBuilder);
                }
            }
            eventType = parser.next();
        }
    }

    /**
     * Builder for UidBatteryConsumer.
     */
+42 −0
Original line number Diff line number Diff line
@@ -17,9 +17,15 @@
package android.os;

import android.annotation.NonNull;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;

import com.android.internal.os.PowerCalculator;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -85,6 +91,42 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
        return 0;
    }

    /** Serializes this object to XML */
    void writeToXml(TypedXmlSerializer serializer) throws IOException {
        if (getConsumedPower() == 0) {
            return;
        }

        serializer.startTag(null, BatteryUsageStats.XML_TAG_USER);
        serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_USER_ID, getUserId());
        mPowerComponents.writeToXml(serializer);
        serializer.endTag(null, BatteryUsageStats.XML_TAG_USER);
    }

    /** Parses an XML representation and populates the BatteryUsageStats builder */
    static void createFromXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)
            throws XmlPullParserException, IOException {
        final int userId = parser.getAttributeInt(null, BatteryUsageStats.XML_ATTR_USER_ID);
        final UserBatteryConsumer.Builder consumerBuilder =
                builder.getOrCreateUserBatteryConsumerBuilder(userId);

        int eventType = parser.getEventType();
        if (eventType != XmlPullParser.START_TAG
                || !parser.getName().equals(BatteryUsageStats.XML_TAG_USER)) {
            throw new XmlPullParserException("Invalid XML parser state");
        }
        while (!(eventType == XmlPullParser.END_TAG
                && parser.getName().equals(BatteryUsageStats.XML_TAG_USER))
                && eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                if (parser.getName().equals(BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
                    PowerComponents.parseXml(parser, consumerBuilder.mPowerComponentsBuilder);
                }
            }
            eventType = parser.next();
        }
    }

    /**
     * Builder for UserBatteryConsumer.
     */
Loading