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

Commit ca9dfbe5 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Convert WakelockPowerCalculator to work with BatteryUsageStats" into sc-dev

parents d77bb6a4 248ade54
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,
            POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
            POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
    })
    })
@@ -65,6 +66,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;
    // Power that is re-attributed to other battery consumers. For example, for System Server
    // Power that is re-attributed to other battery consumers. For example, for System Server
    // this represents the power attributed to apps requesting system services.
    // this represents the power attributed to apps requesting system services.
@@ -92,6 +94,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)
@@ -109,6 +112,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);
    }
}