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

Commit 248ade54 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Convert WakelockPowerCalculator to work with BatteryUsageStats

Test: atest FrameworksCoreTests:com.android.internal.os.WakelockPowerCalculatorTest

Bug: 158137862
Change-Id: I485bdb1f7dc6622fdf30ddae6d6872f2455f36ad
parent 4c4fc216
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ public abstract class BatteryConsumer {
            POWER_COMPONENT_SYSTEM_SERVICES,
            POWER_COMPONENT_SYSTEM_SERVICES,
            POWER_COMPONENT_SENSORS,
            POWER_COMPONENT_SENSORS,
            POWER_COMPONENT_GNSS,
            POWER_COMPONENT_GNSS,
            POWER_COMPONENT_WAKELOCK,
            POWER_COMPONENT_SCREEN,
            POWER_COMPONENT_SCREEN,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
@@ -64,6 +65,7 @@ public abstract class BatteryConsumer {
    public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
    public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
    public static final int POWER_COMPONENT_SENSORS = 9;
    public static final int POWER_COMPONENT_SENSORS = 9;
    public static final int POWER_COMPONENT_GNSS = 10;
    public static final int POWER_COMPONENT_GNSS = 10;
    public static final int POWER_COMPONENT_WAKELOCK = 12;
    public static final int POWER_COMPONENT_SCREEN = 13;
    public static final int POWER_COMPONENT_SCREEN = 13;


    public static final int POWER_COMPONENT_COUNT = 14;
    public static final int POWER_COMPONENT_COUNT = 14;
@@ -87,6 +89,7 @@ public abstract class BatteryConsumer {
            TIME_COMPONENT_MOBILE_RADIO,
            TIME_COMPONENT_MOBILE_RADIO,
            TIME_COMPONENT_SENSORS,
            TIME_COMPONENT_SENSORS,
            TIME_COMPONENT_GNSS,
            TIME_COMPONENT_GNSS,
            TIME_COMPONENT_WAKELOCK,
            TIME_COMPONENT_SCREEN,
            TIME_COMPONENT_SCREEN,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
@@ -104,6 +107,7 @@ public abstract class BatteryConsumer {
    public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
    public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
    public static final int TIME_COMPONENT_SENSORS = 9;
    public static final int TIME_COMPONENT_SENSORS = 9;
    public static final int TIME_COMPONENT_GNSS = 10;
    public static final int TIME_COMPONENT_GNSS = 10;
    public static final int TIME_COMPONENT_WAKELOCK = 12;
    public static final int TIME_COMPONENT_SCREEN = 13;
    public static final int TIME_COMPONENT_SCREEN = 13;


    public static final int TIME_COMPONENT_COUNT = 14;
    public static final int TIME_COMPONENT_COUNT = 14;
+87 −33
Original line number Original line Diff line number Diff line
@@ -15,7 +15,12 @@
 */
 */
package com.android.internal.os;
package com.android.internal.os;


import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;
@@ -26,39 +31,93 @@ import java.util.List;
public class WakelockPowerCalculator extends PowerCalculator {
public class WakelockPowerCalculator extends PowerCalculator {
    private static final String TAG = "WakelockPowerCalculator";
    private static final String TAG = "WakelockPowerCalculator";
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private final double mPowerWakelock;
    private final UsageBasedPowerEstimator mPowerEstimator;
    private long mTotalAppWakelockTimeMs = 0;

    private static class PowerAndDuration {
        public long durationMs;
        public double powerMah;
    }


    public WakelockPowerCalculator(PowerProfile profile) {
    public WakelockPowerCalculator(PowerProfile profile) {
        mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
        mPowerEstimator = new UsageBasedPowerEstimator(
                profile.getAveragePower(PowerProfile.POWER_CPU_IDLE));
    }
    }


    @Override
    @Override
    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
        super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
        final PowerAndDuration result = new PowerAndDuration();
        UidBatteryConsumer.Builder osBatteryConsumer = null;
        double osPowerMah = 0;
        long osDurationMs = 0;
        long totalAppDurationMs = 0;
        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
                builder.getUidBatteryConsumerBuilders();
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
            calculateApp(result, app.getBatteryStatsUid(), rawRealtimeUs,
                    BatteryStats.STATS_SINCE_CHARGED);
            app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK, result.durationMs)
                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
            totalAppDurationMs += result.durationMs;

            if (app.getUid() == Process.ROOT_UID) {
                osBatteryConsumer = app;
                osDurationMs = result.durationMs;
                osPowerMah = result.powerMah;
            }
        }


        // The device has probably been awake for longer than the screen on
        // The device has probably been awake for longer than the screen on
        // time and application wake lock time would account for.  Assign
        // time and application wake lock time would account for.  Assign
        // this remainder to the OS, if possible.
        // this remainder to the OS, if possible.
        if (osBatteryConsumer != null) {
            calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs,
                    BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs);
            osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK,
                    result.durationMs)
                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
        }
    }

    @Override
    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
        final PowerAndDuration result = new PowerAndDuration();
        BatterySipper osSipper = null;
        BatterySipper osSipper = null;
        double osPowerMah = 0;
        long osDurationMs = 0;
        long totalAppDurationMs = 0;
        for (int i = sippers.size() - 1; i >= 0; i--) {
        for (int i = sippers.size() - 1; i >= 0; i--) {
            BatterySipper app = sippers.get(i);
            final BatterySipper app = sippers.get(i);
            if (app.getUid() == 0) {
            if (app.drainType == BatterySipper.DrainType.APP) {
                calculateApp(result, app.uidObj, rawRealtimeUs, statsType);
                app.wakeLockTimeMs = result.durationMs;
                app.wakeLockPowerMah = result.powerMah;
                totalAppDurationMs += result.durationMs;

                if (app.getUid() == Process.ROOT_UID) {
                    osSipper = app;
                    osSipper = app;
                break;
                    osPowerMah = result.powerMah;
                    osDurationMs = result.durationMs;
                }
            }
            }
        }
        }


        // The device has probably been awake for longer than the screen on
        // time and application wake lock time would account for.  Assign
        // this remainder to the OS, if possible.
        if (osSipper != null) {
        if (osSipper != null) {
            calculateRemaining(osSipper, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
            calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, statsType,
                    osPowerMah, osDurationMs, totalAppDurationMs);
            osSipper.wakeLockTimeMs = result.durationMs;
            osSipper.wakeLockPowerMah = result.powerMah;
            osSipper.sumPower();
            osSipper.sumPower();
        }
        }
    }
    }


    @Override
    private void calculateApp(PowerAndDuration result, BatteryStats.Uid u, long rawRealtimeUs,
    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
            int statsType) {
            long rawUptimeUs, int statsType) {
        long wakeLockTimeUs = 0;
        long wakeLockTimeUs = 0;
        final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
        final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
                u.getWakelockStats();
                u.getWakelockStats();
@@ -73,34 +132,29 @@ public class WakelockPowerCalculator extends PowerCalculator {
                wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType);
                wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType);
            }
            }
        }
        }
        app.wakeLockTimeMs = wakeLockTimeUs / 1000; // convert to millis
        result.durationMs = wakeLockTimeUs / 1000; // convert to millis
        mTotalAppWakelockTimeMs += app.wakeLockTimeMs;


        // Add cost of holding a wake lock.
        // Add cost of holding a wake lock.
        app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000 * 60 * 60);
        result.powerMah = mPowerEstimator.calculatePower(result.durationMs);
        if (DEBUG && app.wakeLockPowerMah != 0) {
        if (DEBUG && result.powerMah != 0) {
            Log.d(TAG, "UID " + u.getUid() + ": wake " + app.wakeLockTimeMs
            Log.d(TAG, "UID " + u.getUid() + ": wake " + result.durationMs
                    + " power=" + formatCharge(app.wakeLockPowerMah));
                    + " power=" + formatCharge(result.powerMah));
        }
        }
    }
    }


    private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
    private void calculateRemaining(PowerAndDuration result, BatteryStats stats, long rawRealtimeUs,
            long rawUptimeUs, int statsType) {
            long rawUptimeUs, int statsType, double osPowerMah, long osDurationMs,
        long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000;
            long totalAppDurationMs) {
        wakeTimeMillis -= mTotalAppWakelockTimeMs
        final long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000
                + (stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000);
                - stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000
                - totalAppDurationMs;
        if (wakeTimeMillis > 0) {
        if (wakeTimeMillis > 0) {
            final double power = (wakeTimeMillis * mPowerWakelock) / (1000 * 60 * 60);
            final double power = mPowerEstimator.calculatePower(wakeTimeMillis);
            if (DEBUG) {
            if (DEBUG) {
                Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
                Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
            }
            }
            app.wakeLockTimeMs += wakeTimeMillis;
            result.durationMs = osDurationMs + wakeTimeMillis;
            app.wakeLockPowerMah += power;
            result.powerMah = osPowerMah + power;
        }
        }
        }

    @Override
    public void reset() {
        mTotalAppWakelockTimeMs = 0;
    }
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ import org.junit.runners.Suite;
        SystemServicePowerCalculatorTest.class,
        SystemServicePowerCalculatorTest.class,
        UserPowerCalculatorTest.class,
        UserPowerCalculatorTest.class,
        VideoPowerCalculatorTest.class,
        VideoPowerCalculatorTest.class,
        WakelockPowerCalculatorTest.class,


        com.android.internal.power.MeasuredEnergyStatsTest.class
        com.android.internal.power.MeasuredEnergyStatsTest.class
    })
    })
+7 −0
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@ public class BatteryUsageStatsRule implements TestRule {
    };
    };


    private BatteryUsageStats mBatteryUsageStats;
    private BatteryUsageStats mBatteryUsageStats;
    private boolean mScreenOn;


    public BatteryUsageStatsRule() {
    public BatteryUsageStatsRule() {
        Context context = InstrumentationRegistry.getContext();
        Context context = InstrumentationRegistry.getContext();
@@ -97,6 +98,11 @@ public class BatteryUsageStatsRule implements TestRule {
        return this;
        return this;
    }
    }


    public BatteryUsageStatsRule startWithScreenOn(boolean screenOn) {
        mScreenOn = screenOn;
        return this;
    }

    public void setNetworkStats(NetworkStats networkStats) {
    public void setNetworkStats(NetworkStats networkStats) {
        mBatteryStats.setNetworkStats(networkStats);
        mBatteryStats.setNetworkStats(networkStats);
    }
    }
@@ -115,6 +121,7 @@ public class BatteryUsageStatsRule implements TestRule {
    private void noteOnBattery() {
    private void noteOnBattery() {
        mBatteryStats.setOnBatteryInternal(true);
        mBatteryStats.setOnBatteryInternal(true);
        mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
        mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
        mBatteryStats.getOnBatteryScreenOffTimeBase().setRunning(!mScreenOn, 0, 0);
    }
    }


    public PowerProfile getPowerProfile() {
    public PowerProfile getPowerProfile() {
+76 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.os;

import static com.google.common.truth.Truth.assertThat;

import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.os.WorkSource;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class WakelockPowerCalculatorTest {
    private static final double PRECISION = 0.00001;

    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
    private static final int APP_PID = 3145;

    @Rule
    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
            .setAveragePower(PowerProfile.POWER_CPU_IDLE, 360.0);

    @Test
    public void testTimerBasedModel() {
        mStatsRule.getUidStats(Process.ROOT_UID);

        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();

        batteryStats.noteStartWakeFromSourceLocked(new WorkSource(APP_UID), APP_PID, "awake", "",
                BatteryStats.WAKE_TYPE_PARTIAL, true, 1000, 1000);
        batteryStats.noteStopWakeFromSourceLocked(new WorkSource(APP_UID), APP_PID, "awake", "",
                BatteryStats.WAKE_TYPE_PARTIAL, 2000, 2000);

        mStatsRule.setTime(10_000_000, 6_000_000);

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

        mStatsRule.apply(calculator);

        UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK))
                .isEqualTo(1000);
        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
                .isWithin(PRECISION).of(0.1);

        UidBatteryConsumer osConsumer = mStatsRule.getUidBatteryConsumer(Process.ROOT_UID);
        assertThat(osConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WAKELOCK))
                .isEqualTo(5000);
        assertThat(osConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK))
                .isWithin(PRECISION).of(0.5);
    }
}