diff options
| author | 2021-02-14 05:08:35 +0000 | |
|---|---|---|
| committer | 2021-02-14 05:08:35 +0000 | |
| commit | ca9dfbe54ebf02d9596d8aa696a2e14e5d97c9ec (patch) | |
| tree | 8cc2c88780e060328635442179cc730fe8c1a0fd | |
| parent | d77bb6a44b00661359f1746a2f6878483e5e64fb (diff) | |
| parent | 248ade5460b0a935e5055ad6b8bbe5cdcfc8d3aa (diff) | |
Merge "Convert WakelockPowerCalculator to work with BatteryUsageStats" into sc-dev
5 files changed, 175 insertions, 33 deletions
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index ce1a16da9e14..bf229e0b24df 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -47,6 +47,7 @@ public abstract class BatteryConsumer { POWER_COMPONENT_SYSTEM_SERVICES, POWER_COMPONENT_SENSORS, POWER_COMPONENT_GNSS, + POWER_COMPONENT_WAKELOCK, POWER_COMPONENT_SCREEN, 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_SENSORS = 9; public static final int POWER_COMPONENT_GNSS = 10; + public static final int POWER_COMPONENT_WAKELOCK = 12; public static final int POWER_COMPONENT_SCREEN = 13; // Power that is re-attributed to other battery consumers. For example, for System Server // this represents the power attributed to apps requesting system services. @@ -92,6 +94,7 @@ public abstract class BatteryConsumer { TIME_COMPONENT_MOBILE_RADIO, TIME_COMPONENT_SENSORS, TIME_COMPONENT_GNSS, + TIME_COMPONENT_WAKELOCK, TIME_COMPONENT_SCREEN, }) @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_SENSORS = 9; 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_COUNT = 14; diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java index 3f68597dc1cc..0f4767b859a3 100644 --- a/core/java/com/android/internal/os/WakelockPowerCalculator.java +++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java @@ -15,7 +15,12 @@ */ package com.android.internal.os; +import android.os.BatteryConsumer; 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.util.ArrayMap; import android.util.Log; @@ -26,39 +31,93 @@ import java.util.List; public class WakelockPowerCalculator extends PowerCalculator { private static final String TAG = "WakelockPowerCalculator"; private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final double mPowerWakelock; - private long mTotalAppWakelockTimeMs = 0; + private final UsageBasedPowerEstimator mPowerEstimator; + + private static class PowerAndDuration { + public long durationMs; + public double powerMah; + } public WakelockPowerCalculator(PowerProfile profile) { - mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_IDLE); + mPowerEstimator = new UsageBasedPowerEstimator( + profile.getAveragePower(PowerProfile.POWER_CPU_IDLE)); } @Override - public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, - long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { - super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers); + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + 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 // time and application wake lock time would account for. Assign // 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; + double osPowerMah = 0; + long osDurationMs = 0; + long totalAppDurationMs = 0; for (int i = sippers.size() - 1; i >= 0; i--) { - BatterySipper app = sippers.get(i); - if (app.getUid() == 0) { - osSipper = app; - break; + final BatterySipper app = sippers.get(i); + 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; + 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) { - 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(); } } - @Override - protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { + private void calculateApp(PowerAndDuration result, BatteryStats.Uid u, long rawRealtimeUs, + int statsType) { long wakeLockTimeUs = 0; final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats(); @@ -73,34 +132,29 @@ public class WakelockPowerCalculator extends PowerCalculator { wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType); } } - app.wakeLockTimeMs = wakeLockTimeUs / 1000; // convert to millis - mTotalAppWakelockTimeMs += app.wakeLockTimeMs; + result.durationMs = wakeLockTimeUs / 1000; // convert to millis // Add cost of holding a wake lock. - app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000 * 60 * 60); - if (DEBUG && app.wakeLockPowerMah != 0) { - Log.d(TAG, "UID " + u.getUid() + ": wake " + app.wakeLockTimeMs - + " power=" + formatCharge(app.wakeLockPowerMah)); + result.powerMah = mPowerEstimator.calculatePower(result.durationMs); + if (DEBUG && result.powerMah != 0) { + Log.d(TAG, "UID " + u.getUid() + ": wake " + result.durationMs + + " power=" + formatCharge(result.powerMah)); } } - private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000; - wakeTimeMillis -= mTotalAppWakelockTimeMs - + (stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000); + private void calculateRemaining(PowerAndDuration result, BatteryStats stats, long rawRealtimeUs, + long rawUptimeUs, int statsType, double osPowerMah, long osDurationMs, + long totalAppDurationMs) { + final long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000 + - stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000 + - totalAppDurationMs; if (wakeTimeMillis > 0) { - final double power = (wakeTimeMillis * mPowerWakelock) / (1000 * 60 * 60); + final double power = mPowerEstimator.calculatePower(wakeTimeMillis); if (DEBUG) { Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power)); } - app.wakeLockTimeMs += wakeTimeMillis; - app.wakeLockPowerMah += power; + result.durationMs = osDurationMs + wakeTimeMillis; + result.powerMah = osPowerMah + power; } } - - @Override - public void reset() { - mTotalAppWakelockTimeMs = 0; - } } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java index 0fac4f79686a..2e6e0de8d0c2 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java @@ -68,6 +68,7 @@ import org.junit.runners.Suite; SystemServicePowerCalculatorTest.class, UserPowerCalculatorTest.class, VideoPowerCalculatorTest.class, + WakelockPowerCalculatorTest.class, com.android.internal.power.MeasuredEnergyStatsTest.class }) diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java index 0ddc4c0035ce..5edd58fb3eb9 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -49,6 +49,7 @@ public class BatteryUsageStatsRule implements TestRule { }; private BatteryUsageStats mBatteryUsageStats; + private boolean mScreenOn; public BatteryUsageStatsRule() { Context context = InstrumentationRegistry.getContext(); @@ -97,6 +98,11 @@ public class BatteryUsageStatsRule implements TestRule { return this; } + public BatteryUsageStatsRule startWithScreenOn(boolean screenOn) { + mScreenOn = screenOn; + return this; + } + public void setNetworkStats(NetworkStats networkStats) { mBatteryStats.setNetworkStats(networkStats); } @@ -115,6 +121,7 @@ public class BatteryUsageStatsRule implements TestRule { private void noteOnBattery() { mBatteryStats.setOnBatteryInternal(true); mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0); + mBatteryStats.getOnBatteryScreenOffTimeBase().setRunning(!mScreenOn, 0, 0); } public PowerProfile getPowerProfile() { diff --git a/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java new file mode 100644 index 000000000000..4f71b438c6fa --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java @@ -0,0 +1,76 @@ +/* + * 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); + } +} |