Loading core/java/android/os/BatteryConsumer.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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, }) }) Loading @@ -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. Loading Loading @@ -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) Loading @@ -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; Loading core/java/com/android/internal/os/WakelockPowerCalculator.java +87 −33 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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(); Loading @@ -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; } } } } core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -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 }) }) Loading core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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); } } Loading @@ -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() { Loading core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java 0 → 100644 +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); } } Loading
core/java/android/os/BatteryConsumer.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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, }) }) Loading @@ -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. Loading Loading @@ -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) Loading @@ -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; Loading
core/java/com/android/internal/os/WakelockPowerCalculator.java +87 −33 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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(); Loading @@ -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; } } } }
core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -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 }) }) Loading
core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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); } } Loading @@ -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() { Loading
core/tests/coretests/src/com/android/internal/os/WakelockPowerCalculatorTest.java 0 → 100644 +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); } }