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

Commit 1f00a91b authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Introduce PowerStatsCollector/Processor for custom EnergyConsumers

Bug: 333941740
Test: atest PowerStatsTests; atest PowerStatsTestsRavenwood
Flag: com.android.server.power.optimization.streamlined_misc_battery_stats

Change-Id: Ic6d2da35249c04c98fd88fdfb0d059ca44ad3675
parent e8c2428c
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -888,6 +888,13 @@ public abstract class BatteryConsumer {
            return (T) this;
        }

        @SuppressWarnings("unchecked")
        @NonNull
        public T addConsumedPowerForCustomComponent(int componentId, double componentPower) {
            mPowerComponentsBuilder.addConsumedPowerForCustomComponent(componentId, componentPower);
            return (T) this;
        }

        /**
         * Sets the amount of time used by the specified component, e.g. CPU, WiFi etc.
         *
+13 −0
Original line number Diff line number Diff line
@@ -515,6 +515,19 @@ class PowerComponents {
            return this;
        }

        @NonNull
        public Builder addConsumedPowerForCustomComponent(int componentId, double componentPower) {
            final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
            if (index < 0 || index >= mData.layout.customPowerComponentCount) {
                throw new IllegalArgumentException(
                        "Unsupported custom power component ID: " + componentId);
            }
            mData.putDouble(mData.layout.firstCustomConsumedPowerColumn + index,
                    mData.getDouble(mData.layout.firstCustomConsumedPowerColumn + index)
                            + componentPower);
            return this;
        }

        @NonNull
        public Builder setUsageDurationMillis(BatteryConsumer.Key key,
                long componentUsageDurationMillis) {
+14 −0
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ import com.android.server.power.stats.BatteryUsageStatsProvider;
import com.android.server.power.stats.BluetoothPowerStatsProcessor;
import com.android.server.power.stats.CameraPowerStatsProcessor;
import com.android.server.power.stats.CpuPowerStatsProcessor;
import com.android.server.power.stats.CustomEnergyConsumerPowerStatsProcessor;
import com.android.server.power.stats.FlashlightPowerStatsProcessor;
import com.android.server.power.stats.GnssPowerStatsProcessor;
import com.android.server.power.stats.MobileRadioPowerStatsProcessor;
@@ -574,6 +575,15 @@ public final class BatteryStatsService extends IBatteryStats.Stub
                        AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
                .setProcessor(
                        new GnssPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));

        config.trackCustomPowerComponents(CustomEnergyConsumerPowerStatsProcessor::new)
                .trackDeviceStates(
                        AggregatedPowerStatsConfig.STATE_POWER,
                        AggregatedPowerStatsConfig.STATE_SCREEN)
                .trackUidStates(
                        AggregatedPowerStatsConfig.STATE_POWER,
                        AggregatedPowerStatsConfig.STATE_SCREEN,
                        AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
        return config;
    }

@@ -665,6 +675,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
                BatteryConsumer.POWER_COMPONENT_CAMERA,
                Flags.streamlinedMiscBatteryStats());

        // By convention POWER_COMPONENT_ANY represents custom Energy Consumers
        mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_ANY,
                Flags.streamlinedMiscBatteryStats());

        mWorker.systemServicesReady();
        mStats.systemServicesReady(mContext);
        mCpuWakeupStats.systemServicesReady();
+116 −45
Original line number Diff line number Diff line
@@ -19,16 +19,20 @@ package com.android.server.power.stats;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;

import com.android.internal.os.PowerStats;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.power.stats.AggregatedPowerStatsConfig.PowerComponent;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -53,11 +57,14 @@ class AggregatedPowerStats {
    private static final int MAX_CLOCK_UPDATES = 100;
    private static final String XML_TAG_AGGREGATED_POWER_STATS = "agg-power-stats";

    private final PowerComponentAggregatedPowerStats[] mPowerComponentStats;
    private final AggregatedPowerStatsConfig mConfig;
    private final SparseArray<PowerComponentAggregatedPowerStats> mPowerComponentStats;
    private final PowerComponentAggregatedPowerStats mGenericPowerComponent;

    static class ClockUpdate {
        public long monotonicTime;
        @CurrentTimeMillisLong public long currentTime;
        @CurrentTimeMillisLong
        public long currentTime;
    }

    private final List<ClockUpdate> mClockUpdates = new ArrayList<>();
@@ -65,13 +72,35 @@ class AggregatedPowerStats {
    @DurationMillisLong
    private long mDurationMs;

    AggregatedPowerStats(AggregatedPowerStatsConfig aggregatedPowerStatsConfig) {
        List<AggregatedPowerStatsConfig.PowerComponent> configs =
    AggregatedPowerStats(@NonNull AggregatedPowerStatsConfig aggregatedPowerStatsConfig) {
        mConfig = aggregatedPowerStatsConfig;
        List<PowerComponent> configs =
                aggregatedPowerStatsConfig.getPowerComponentsAggregatedStatsConfigs();
        mPowerComponentStats = new PowerComponentAggregatedPowerStats[configs.size()];
        mPowerComponentStats = new SparseArray<>(configs.size());
        for (int i = 0; i < configs.size(); i++) {
            mPowerComponentStats[i] = new PowerComponentAggregatedPowerStats(this, configs.get(i));
        }
            PowerComponent powerComponent = configs.get(i);
            mPowerComponentStats.put(powerComponent.getPowerComponentId(),
                    new PowerComponentAggregatedPowerStats(this, powerComponent));
        }
        mGenericPowerComponent = createGenericPowerComponent();
        mPowerComponentStats.put(BatteryConsumer.POWER_COMPONENT_ANY, mGenericPowerComponent);
    }

    private PowerComponentAggregatedPowerStats createGenericPowerComponent() {
        PowerComponent config = new PowerComponent(BatteryConsumer.POWER_COMPONENT_ANY);
        config.trackDeviceStates(
                        AggregatedPowerStatsConfig.STATE_POWER,
                        AggregatedPowerStatsConfig.STATE_SCREEN)
                .trackUidStates(
                        AggregatedPowerStatsConfig.STATE_POWER,
                        AggregatedPowerStatsConfig.STATE_SCREEN,
                        AggregatedPowerStatsConfig.STATE_PROCESS_STATE);
        PowerComponentAggregatedPowerStats stats =
                new PowerComponentAggregatedPowerStats(this, config);
        stats.setPowerStatsDescriptor(
                new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_ANY, 0, null, 0, 0,
                        new PersistableBundle()));
        return stats;
    }

    /**
@@ -119,67 +148,98 @@ class AggregatedPowerStats {
        return mDurationMs;
    }

    List<PowerComponentAggregatedPowerStats> getPowerComponentStats() {
        List<PowerComponentAggregatedPowerStats> list = new ArrayList<>(
                mPowerComponentStats.size());
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            PowerComponentAggregatedPowerStats stats = mPowerComponentStats.valueAt(i);
            if (stats != mGenericPowerComponent) {
                list.add(stats);
            }
        }
        return list;
    }

    PowerComponentAggregatedPowerStats getPowerComponentStats(int powerComponentId) {
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            if (stats.powerComponentId == powerComponentId) {
                return stats;
        return mPowerComponentStats.get(powerComponentId);
    }

    void start(long timestampMs) {
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            PowerComponentAggregatedPowerStats component = mPowerComponentStats.valueAt(i);
            component.getConfig().getProcessor().start(component, timestampMs);
        }
        return null;
    }

    void setDeviceState(@AggregatedPowerStatsConfig.TrackedState int stateId, int state,
            long time) {
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            stats.setState(stateId, state, time);
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            mPowerComponentStats.valueAt(i).setState(stateId, state, time);
        }
    }

    void setUidState(int uid, @AggregatedPowerStatsConfig.TrackedState int stateId, int state,
            long time) {
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            stats.setUidState(uid, stateId, state, time);
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            mPowerComponentStats.valueAt(i).setUidState(uid, stateId, state, time);
        }
    }

    boolean isCompatible(PowerStats powerStats) {
        int powerComponentId = powerStats.descriptor.powerComponentId;
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            if (stats.powerComponentId == powerComponentId && !stats.isCompatible(powerStats)) {
                return false;
            }
        }
        return true;
        PowerComponentAggregatedPowerStats stats = mPowerComponentStats.get(powerComponentId);
        return stats != null && stats.isCompatible(powerStats);
    }

    void addPowerStats(PowerStats powerStats, long time) {
        int powerComponentId = powerStats.descriptor.powerComponentId;
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            if (stats.powerComponentId == powerComponentId) {
                stats.getConfig().getProcessor().addPowerStats(stats, powerStats, time);
        PowerComponentAggregatedPowerStats stats = mPowerComponentStats.get(powerComponentId);
        if (stats == null) {
            PowerComponent powerComponent = mConfig.createPowerComponent(powerComponentId);
            if (powerComponent == null) {
                return;
            }

            stats = new PowerComponentAggregatedPowerStats(this, powerComponent);
            stats.setPowerStatsDescriptor(powerStats.descriptor);
            stats.copyStatesFrom(mGenericPowerComponent);
            mPowerComponentStats.put(powerComponentId, stats);
        }

        PowerStatsProcessor processor = stats.getConfig().getProcessor();
        processor.addPowerStats(stats, powerStats, time);
    }

    public void noteStateChange(BatteryStats.HistoryItem item) {
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            PowerComponentAggregatedPowerStats stats = mPowerComponentStats.valueAt(i);
            stats.getConfig().getProcessor().noteStateChange(stats, item);
        }
    }

    void finish(long timestampMs) {
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            PowerComponentAggregatedPowerStats component = mPowerComponentStats.valueAt(i);
            component.getConfig().getProcessor().finish(component, timestampMs);
        }
    }

    void reset() {
        mClockUpdates.clear();
        mDurationMs = 0;
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            stats.reset();
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            mPowerComponentStats.valueAt(i).reset();
        }
    }

    public void writeXml(TypedXmlSerializer serializer) throws IOException {
        serializer.startTag(null, XML_TAG_AGGREGATED_POWER_STATS);
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            PowerComponentAggregatedPowerStats stats = mPowerComponentStats.valueAt(i);
            if (stats != mGenericPowerComponent) {
                stats.writeXml(serializer);
            }
        }
        serializer.endTag(null, XML_TAG_AGGREGATED_POWER_STATS);
        serializer.flush();
    }
@@ -200,25 +260,36 @@ class AggregatedPowerStats {
                    case XML_TAG_AGGREGATED_POWER_STATS:
                        inElement = true;
                        break;
                    case PowerComponentAggregatedPowerStats.XML_TAG_POWER_COMPONENT:
                    case PowerComponentAggregatedPowerStats.XML_TAG_POWER_COMPONENT: {
                        if (!inElement) {
                            break;
                        }

                        int powerComponentId = parser.getAttributeInt(null,
                                PowerComponentAggregatedPowerStats.XML_ATTR_ID);
                        for (PowerComponentAggregatedPowerStats powerComponent :
                                stats.mPowerComponentStats) {
                            if (powerComponent.powerComponentId == powerComponentId) {
                                if (!powerComponent.readFromXml(parser)) {

                        PowerComponentAggregatedPowerStats powerComponentStats =
                                stats.getPowerComponentStats(powerComponentId);
                        if (powerComponentStats == null) {
                            PowerComponent powerComponent =
                                    aggregatedPowerStatsConfig.createPowerComponent(
                                            powerComponentId);
                            if (powerComponent != null) {
                                powerComponentStats = new PowerComponentAggregatedPowerStats(stats,
                                        powerComponent);
                                stats.mPowerComponentStats.put(powerComponentId,
                                        powerComponentStats);
                            }
                        }
                        if (powerComponentStats != null) {
                            if (!powerComponentStats.readFromXml(parser)) {
                                skipToEnd = true;
                            }
                                break;
                            }
                        }
                        break;
                    }
                }
            }
            eventType = parser.next();
        }
        return stats;
@@ -254,14 +325,14 @@ class AggregatedPowerStats {

        ipw.println("Device");
        ipw.increaseIndent();
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            stats.dumpDevice(ipw);
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            mPowerComponentStats.valueAt(i).dumpDevice(ipw);
        }
        ipw.decreaseIndent();

        Set<Integer> uids = new HashSet<>();
        for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
            stats.collectUids(uids);
        for (int i = 0; i < mPowerComponentStats.size(); i++) {
            mPowerComponentStats.valueAt(i).collectUids(uids);
        }

        Integer[] allUids = uids.toArray(new Integer[uids.size()]);
@@ -269,8 +340,8 @@ class AggregatedPowerStats {
        for (int uid : allUids) {
            ipw.println(UserHandle.formatUid(uid));
            ipw.increaseIndent();
            for (PowerComponentAggregatedPowerStats stats : mPowerComponentStats) {
                stats.dumpUid(ipw, uid);
            for (int i = 0; i < mPowerComponentStats.size(); i++) {
                mPowerComponentStats.valueAt(i).dumpUid(ipw, uid);
            }
            ipw.decreaseIndent();
        }
+40 −1
Original line number Diff line number Diff line
@@ -17,12 +17,14 @@ package com.android.server.power.stats;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.BatteryConsumer;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * Configuration that controls how power stats are aggregated.  It determines which state changes
@@ -140,7 +142,7 @@ public class AggregatedPowerStatsConfig {
        }

        @NonNull
        public PowerStatsProcessor getProcessor() {
        PowerStatsProcessor getProcessor() {
            return mProcessor;
        }

@@ -160,6 +162,8 @@ public class AggregatedPowerStatsConfig {
    }

    private final List<PowerComponent> mPowerComponents = new ArrayList<>();
    private PowerComponent mCustomPowerComponent;
    private Supplier<PowerStatsProcessor> mCustomPowerStatsProcessorFactory;

    /**
     * Creates a configuration for the specified power component, which may be one of the
@@ -199,10 +203,45 @@ public class AggregatedPowerStatsConfig {
        return powerComponent;
    }

    /**
     * Creates a configuration for custom power components, which are yet to be discovered
     * dynamically through the integration with PowerStatsService.
     */
    public PowerComponent trackCustomPowerComponents(
            Supplier<PowerStatsProcessor> processorFactory) {
        mCustomPowerStatsProcessorFactory = processorFactory;
        mCustomPowerComponent = new PowerComponent(BatteryConsumer.POWER_COMPONENT_ANY);
        return mCustomPowerComponent;
    }

    /**
     * Returns configurations for all registered or dynamically discovered power components.
     */
    public List<PowerComponent> getPowerComponentsAggregatedStatsConfigs() {
        return mPowerComponents;
    }

    /**
     * Creates a configuration for a custom power component discovered dynamically through the
     * integration with PowerStatsService.
     */
    @Nullable
    public PowerComponent createPowerComponent(int powerComponentId) {
        if (mCustomPowerComponent == null) {
            return null;
        }

        PowerComponent powerComponent = new PowerComponent(powerComponentId);
        powerComponent.trackDeviceStates(mCustomPowerComponent.mTrackedDeviceStates);
        powerComponent.trackUidStates(mCustomPowerComponent.mTrackedUidStates);

        if (mCustomPowerStatsProcessorFactory != null) {
            powerComponent.setProcessor(mCustomPowerStatsProcessorFactory.get());
        }

        return powerComponent;
    }

    private static final PowerStatsProcessor NO_OP_PROCESSOR = new PowerStatsProcessor() {
        @Override
        void finish(PowerComponentAggregatedPowerStats stats, long timestampMs) {
Loading