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

Commit 8baec905 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I504d9c65,I45abcf87 into sc-v2-dev

* changes:
  Utilize measured energy for multidisplay power attribution
  Update Screen and AmbientDisplay Power Calculators for multi-display
parents 5e30b007 3214255b
Loading
Loading
Loading
Loading
+33 −9
Original line number Diff line number Diff line
@@ -31,12 +31,15 @@ import java.util.List;
 * Estimates power consumed by the ambient display
 */
public class AmbientDisplayPowerCalculator extends PowerCalculator {
    private final UsageBasedPowerEstimator mPowerEstimator;
    private final UsageBasedPowerEstimator[] mPowerEstimators;

    public AmbientDisplayPowerCalculator(PowerProfile powerProfile) {
        // TODO(b/200239964): update to support multidisplay.
        mPowerEstimator = new UsageBasedPowerEstimator(
                powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0));
        final int numDisplays = powerProfile.getNumDisplays();
        mPowerEstimators = new UsageBasedPowerEstimator[numDisplays];
        for (int display = 0; display < numDisplays; display++) {
            mPowerEstimators[display] = new UsageBasedPowerEstimator(
                    powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, display));
        }
    }

    /**
@@ -50,8 +53,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
        final int powerModel = getPowerModel(measuredEnergyUC, query);
        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
                BatteryStats.STATS_SINCE_CHARGED);
        final double powerMah = getMeasuredOrEstimatedPower(powerModel,
                measuredEnergyUC, mPowerEstimator, durationMs);
        final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs,
                measuredEnergyUC);
        builder.getAggregateBatteryConsumerBuilder(
                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, durationMs)
@@ -71,9 +74,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
        final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
        final int powerModel = getPowerModel(measuredEnergyUC);
        final double powerMah = getMeasuredOrEstimatedPower(powerModel,
                batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(),
                mPowerEstimator, durationMs);
        final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs,
                measuredEnergyUC);
        if (powerMah > 0) {
            BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
            bs.usagePowerMah = powerMah;
@@ -86,4 +88,26 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
    private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
        return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
    }

    private double calculateTotalPower(@BatteryConsumer.PowerModel int powerModel,
            BatteryStats batteryStats, long rawRealtimeUs, long consumptionUC) {
        switch (powerModel) {
            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
                return uCtoMah(consumptionUC);
            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
            default:
                return calculateEstimatedPower(batteryStats, rawRealtimeUs);
        }
    }

    private double calculateEstimatedPower(BatteryStats batteryStats, long rawRealtimeUs) {
        final int numDisplays = mPowerEstimators.length;
        double power = 0;
        for (int display = 0; display < numDisplays; display++) {
            final long dozeTime = batteryStats.getDisplayScreenDozeTime(display, rawRealtimeUs)
                    / 1000;
            power += mPowerEstimators[display].calculatePower(dozeTime);
        }
        return power;
    }
}
+61 −15
Original line number Diff line number Diff line
@@ -903,6 +903,11 @@ public class BatteryStatsImpl extends BatteryStats {
         */
        public StopwatchTimer[] screenBrightnessTimers =
                new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
        /**
         * Per display screen state the last time {@link #updateDisplayMeasuredEnergyStatsLocked}
         * was called.
         */
        public int screenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN;
        DisplayBatteryStats(Clocks clocks, TimeBase timeBase) {
            screenOnTimer = new StopwatchTimer(clocks, null, -1, null,
@@ -929,6 +934,8 @@ public class BatteryStatsImpl extends BatteryStats {
    DisplayBatteryStats[] mPerDisplayBatteryStats;
    private int mDisplayMismatchWtfCount = 0;
    boolean mInteractive;
    StopwatchTimer mInteractiveTimer;
@@ -1073,8 +1080,6 @@ public class BatteryStatsImpl extends BatteryStats {
    @GuardedBy("this")
    @VisibleForTesting
    protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats;
    /** Last known screen state. Needed for apportioning display energy. */
    int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN;
    /** Bluetooth Power calculator for attributing measured bluetooth charge consumption to uids */
    @Nullable BluetoothPowerCalculator mBluetoothPowerCalculator = null;
    /** Cpu Power calculator for attributing measured cpu charge consumption to uids */
@@ -12924,22 +12929,43 @@ public class BatteryStatsImpl extends BatteryStats {
     * is always 0 when the screen is not "ON" and whenever the rail energy is 0 (if supported).
     * To the extent that those assumptions are violated, the algorithm will err.
     *
     * @param chargeUC amount of charge (microcoulombs) used by Display since this was last called.
     * @param screenState screen state at the time this data collection was scheduled
     * @param chargesUC amount of charge (microcoulombs) used by each Display since this was last
     *                 called.
     * @param screenStates each screen state at the time this data collection was scheduled
     */
    @GuardedBy("this")
    public void updateDisplayMeasuredEnergyStatsLocked(long chargeUC, int screenState,
    public void updateDisplayMeasuredEnergyStatsLocked(long[] chargesUC, int[] screenStates,
            long elapsedRealtimeMs) {
        if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + chargeUC);
        if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + Arrays.toString(chargesUC));
        if (mGlobalMeasuredEnergyStats == null) {
            return;
        }
        final @StandardPowerBucket int powerBucket =
                MeasuredEnergyStats.getDisplayPowerBucket(mScreenStateAtLastEnergyMeasurement);
        mScreenStateAtLastEnergyMeasurement = screenState;
        final int numDisplays;
        if (mPerDisplayBatteryStats.length == screenStates.length) {
            numDisplays = screenStates.length;
        } else {
            // if this point is reached, it will be reached every display state change.
            // Rate limit the wtf logging to once every 100 display updates.
            if (mDisplayMismatchWtfCount++ % 100 == 0) {
                Slog.wtf(TAG, "Mismatch between PowerProfile reported display count ("
                        + mPerDisplayBatteryStats.length
                        + ") and PowerStatsHal reported display count (" + screenStates.length
                        + ")");
            }
            // Keep the show going, use the shorter of the two.
            numDisplays = mPerDisplayBatteryStats.length < screenStates.length
                    ? mPerDisplayBatteryStats.length : screenStates.length;
        }
        if (!mOnBatteryInternal || chargeUC <= 0) {
        final int[] oldScreenStates = new int[numDisplays];
        for (int i = 0; i < numDisplays; i++) {
            final int screenState = screenStates[i];
            oldScreenStates[i] = mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement;
            mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState;
        }
        if (!mOnBatteryInternal) {
            // There's nothing further to update.
            return;
        }
@@ -12954,17 +12980,31 @@ public class BatteryStatsImpl extends BatteryStats {
            return;
        }
        long totalScreenOnChargeUC = 0;
        for (int i = 0; i < numDisplays; i++) {
            final long chargeUC = chargesUC[i];
            if (chargeUC <= 0) {
                // There's nothing further to update.
                continue;
            }
            final @StandardPowerBucket int powerBucket =
                    MeasuredEnergyStats.getDisplayPowerBucket(oldScreenStates[i]);
            mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC);
            if (powerBucket == MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) {
                totalScreenOnChargeUC += chargeUC;
            }
        }
        // Now we blame individual apps, but only if the display was ON.
        if (powerBucket != MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) {
        if (totalScreenOnChargeUC <= 0) {
            return;
        }
        // TODO(b/175726779): Consider unifying the code with the non-rail display power blaming.
        // NOTE: fg time is NOT pooled. If two uids are both somehow in fg, then that time is
        // 'double counted' and will simply exceed the realtime that elapsed.
        // If multidisplay becomes a reality, this is probably more reasonable than pooling.
        // TODO(b/175726779): collect per display uid visibility for display power attribution.
        // Collect total time since mark so that we can normalize power.
        final SparseDoubleArray fgTimeUsArray = new SparseDoubleArray();
@@ -12977,7 +13017,8 @@ public class BatteryStatsImpl extends BatteryStats {
            if (fgTimeUs == 0) continue;
            fgTimeUsArray.put(uid.getUid(), (double) fgTimeUs);
        }
        distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0);
        distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON,
                totalScreenOnChargeUC, fgTimeUsArray, 0);
    }
    /**
@@ -14883,7 +14924,12 @@ public class BatteryStatsImpl extends BatteryStats {
    public void initMeasuredEnergyStatsLocked(@Nullable boolean[] supportedStandardBuckets,
            String[] customBucketNames) {
        boolean supportedBucketMismatch = false;
        mScreenStateAtLastEnergyMeasurement = mScreenState;
        final int numDisplays = mPerDisplayBatteryStats.length;
        for (int i = 0; i < numDisplays; i++) {
            final int screenState = mPerDisplayBatteryStats[i].screenState;
            mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState;
        }
        if (supportedStandardBuckets == null) {
            if (mGlobalMeasuredEnergyStats != null) {
+0 −26
Original line number Diff line number Diff line
@@ -132,32 +132,6 @@ public abstract class PowerCalculator {
                : BatteryConsumer.POWER_MODEL_POWER_PROFILE;
    }

    /**
     * Returns either the measured energy converted to mAh or a usage-based estimate.
     */
    protected static double getMeasuredOrEstimatedPower(@BatteryConsumer.PowerModel int powerModel,
            long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) {
        switch (powerModel) {
            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
                return uCtoMah(measuredEnergyUC);
            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
            default:
                return powerEstimator.calculatePower(durationMs);
        }
    }

    /**
     * Returns either the measured energy converted to mAh or a usage-based estimate.
     */
    protected static double getMeasuredOrEstimatedPower(
            long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) {
        if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
            return uCtoMah(measuredEnergyUC);
        } else {
            return powerEstimator.calculatePower(durationMs);
        }
    }

    /**
     * Prints formatted amount of power in milli-amp-hours.
     */
+31 −20
Original line number Diff line number Diff line
@@ -44,8 +44,8 @@ public class ScreenPowerCalculator extends PowerCalculator {
    // Minimum amount of time the screen should be on to start smearing drain to apps
    public static final long MIN_ACTIVE_TIME_FOR_SMEARING = 10 * DateUtils.MINUTE_IN_MILLIS;

    private final UsageBasedPowerEstimator mScreenOnPowerEstimator;
    private final UsageBasedPowerEstimator mScreenFullPowerEstimator;
    private final UsageBasedPowerEstimator[] mScreenOnPowerEstimators;
    private final UsageBasedPowerEstimator[] mScreenFullPowerEstimators;

    private static class PowerAndDuration {
        public long durationMs;
@@ -53,11 +53,16 @@ public class ScreenPowerCalculator extends PowerCalculator {
    }

    public ScreenPowerCalculator(PowerProfile powerProfile) {
        // TODO(b/200239964): update to support multidisplay.
        mScreenOnPowerEstimator = new UsageBasedPowerEstimator(
                powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0));
        mScreenFullPowerEstimator = new UsageBasedPowerEstimator(
                powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0));
        final int numDisplays = powerProfile.getNumDisplays();
        mScreenOnPowerEstimators = new UsageBasedPowerEstimator[numDisplays];
        mScreenFullPowerEstimators = new UsageBasedPowerEstimator[numDisplays];
        for (int display = 0; display < numDisplays; display++) {
            mScreenOnPowerEstimators[display] = new UsageBasedPowerEstimator(
                    powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, display));
            mScreenFullPowerEstimators[display] = new UsageBasedPowerEstimator(
                    powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL,
                            display));
        }
    }

    @Override
@@ -172,7 +177,7 @@ public class ScreenPowerCalculator extends PowerCalculator {
            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
            default:
                totalPowerAndDuration.powerMah = calculateTotalPowerFromBrightness(batteryStats,
                        rawRealtimeUs, statsType, totalPowerAndDuration.durationMs);
                        rawRealtimeUs);
        }
    }

@@ -194,20 +199,26 @@ public class ScreenPowerCalculator extends PowerCalculator {
        return batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000;
    }

    private double calculateTotalPowerFromBrightness(BatteryStats batteryStats, long rawRealtimeUs,
            int statsType, long durationMs) {
        double power = mScreenOnPowerEstimator.calculatePower(durationMs);
        for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
            final long brightnessTime =
                    batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000;
            final double binPowerMah = mScreenFullPowerEstimator.calculatePower(brightnessTime)
                    * (i + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
    private double calculateTotalPowerFromBrightness(BatteryStats batteryStats,
            long rawRealtimeUs) {
        final int numDisplays = mScreenOnPowerEstimators.length;
        double power = 0;
        for (int display = 0; display < numDisplays; display++) {
            final long displayTime = batteryStats.getDisplayScreenOnTime(display, rawRealtimeUs)
                    / 1000;
            power += mScreenOnPowerEstimators[display].calculatePower(displayTime);
            for (int bin = 0; bin < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; bin++) {
                final long brightnessTime = batteryStats.getDisplayScreenBrightnessTime(display,
                        bin, rawRealtimeUs) / 1000;
                final double binPowerMah = mScreenFullPowerEstimators[display].calculatePower(
                        brightnessTime) * (bin + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
                if (DEBUG && binPowerMah != 0) {
                Slog.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
                    Slog.d(TAG, "Screen bin #" + bin + ": time=" + brightnessTime
                            + " power=" + formatCharge(binPowerMah));
                }
                power += binPowerMah;
            }
        }
        return power;
    }

+101 −6
Original line number Diff line number Diff line
@@ -38,26 +38,28 @@ public class AmbientDisplayPowerCalculatorTest {

    @Rule
    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
            .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0, 10.0);
            .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0, 10.0)
            .setNumDisplays(1);

    @Test
    public void testMeasuredEnergyBasedModel() {
        mStatsRule.initMeasuredEnergyStatsLocked();
        BatteryStatsImpl stats = mStatsRule.getBatteryStats();

        stats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, 0);
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{300_000_000},
                new int[]{Display.STATE_ON}, 0);

        stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
                30 * MINUTE_IN_MS);

        stats.updateDisplayMeasuredEnergyStatsLocked(200_000_000, Display.STATE_DOZE,
                30 * MINUTE_IN_MS);
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{200_000_000},
                new int[]{Display.STATE_DOZE}, 30 * MINUTE_IN_MS);

        stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
                120 * MINUTE_IN_MS);

        stats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_OFF,
                120 * MINUTE_IN_MS);
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100_000_000},
                new int[]{Display.STATE_OFF}, 120 * MINUTE_IN_MS);

        AmbientDisplayPowerCalculator calculator =
                new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
@@ -74,6 +76,67 @@ public class AmbientDisplayPowerCalculatorTest {
                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
    }

    @Test
    public void testMeasuredEnergyBasedModel_multiDisplay() {
        mStatsRule.initMeasuredEnergyStatsLocked()
                .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 1, 20.0)
                .setNumDisplays(2);
        BatteryStatsImpl stats = mStatsRule.getBatteryStats();


        final int[] screenStates = new int[] {Display.STATE_OFF, Display.STATE_OFF};

        stats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0);
        stats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0);
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{300, 400}, screenStates, 0);

        // Switch display0 to doze
        screenStates[0] = Display.STATE_DOZE;
        stats.noteScreenStateLocked(0, screenStates[0], 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
                30 * MINUTE_IN_MS);
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{200, 300},
                screenStates, 30 * MINUTE_IN_MS);

        // Switch display1 to doze
        screenStates[1] = Display.STATE_DOZE;
        stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS,
                90 * MINUTE_IN_MS);
        // 100,000,000 uC should be attributed to display 0 doze here.
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100_000_000, 700_000_000},
                screenStates, 90 * MINUTE_IN_MS);

        // Switch display0 to off
        screenStates[0] = Display.STATE_OFF;
        stats.noteScreenStateLocked(0, screenStates[0], 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
                120 * MINUTE_IN_MS);
        // 40,000,000 and 70,000,000 uC should be attributed to display 0 and 1 doze here.
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{40_000_000, 70_000_000},
                screenStates, 120 * MINUTE_IN_MS);

        // Switch display1 to off
        screenStates[1] = Display.STATE_OFF;
        stats.noteScreenStateLocked(1, screenStates[1], 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS,
                150 * MINUTE_IN_MS);
        stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100, 90_000_000}, screenStates,
                150 * MINUTE_IN_MS);
        // 90,000,000 uC should be attributed to display 1 doze here.

        AmbientDisplayPowerCalculator calculator =
                new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());

        mStatsRule.apply(calculator);

        BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer();
        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isEqualTo(120 * MINUTE_IN_MS);
        // 100,000,000 + 40,000,000 + 70,000,000 + 90,000,000 uC / 1000 (micro-/milli-) / 3600
        // (seconds/hour) = 27.777778 mAh
        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isWithin(PRECISION).of(83.33333);
        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
    }

    @Test
    public void testPowerProfileBasedModel() {
        BatteryStatsImpl stats = mStatsRule.getBatteryStats();
@@ -96,4 +159,36 @@ public class AmbientDisplayPowerCalculatorTest {
        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
    }

    @Test
    public void testPowerProfileBasedModel_multiDisplay() {
        mStatsRule.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 1, 20.0)
                .setNumDisplays(2);

        BatteryStatsImpl stats = mStatsRule.getBatteryStats();

        stats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0);
        stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
                30 * MINUTE_IN_MS);
        stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS,
                90 * MINUTE_IN_MS);
        stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
                120 * MINUTE_IN_MS);
        stats.noteScreenStateLocked(1, Display.STATE_OFF, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS,
                150 * MINUTE_IN_MS);

        AmbientDisplayPowerCalculator calculator =
                new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());

        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);

        BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer();
        // Duration should only be the union of
        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isEqualTo(120 * MINUTE_IN_MS);
        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isWithin(PRECISION).of(35.0);
        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY))
                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
    }
}
Loading