diff options
author | 2025-02-04 17:53:10 -0800 | |
---|---|---|
committer | 2025-02-06 10:13:19 -0800 | |
commit | e5fb4df6a9c18fc38bc7532d8a8c5b86c94c6573 (patch) | |
tree | 99ebb007e09257abb649829fde577d798f8cb357 | |
parent | 8896bc45d0ea005ff54f97a023af4d8d96f4f09d (diff) |
Fix device-wide accumulation of consumed power estimates
Bug: 382803366
Flag: EXEMPT bugfix
Test: atest PowerStatsTests; atest PowerStatsTestsRavenwood
Change-Id: If4da14840244af85e3a21387c537b59e79ae836b
9 files changed, 66 insertions, 59 deletions
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index 86b8fad16275..739908ef0dfc 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -827,12 +827,12 @@ public final class BatteryUsageStats implements Parcelable, Closeable { parser.getAttributeLong(null, XML_ATTR_DURATION)); builder.setBatteryCapacity( parser.getAttributeDouble(null, XML_ATTR_BATTERY_CAPACITY)); - builder.setDischargePercentage( + builder.addDischargePercentage( parser.getAttributeInt(null, XML_ATTR_DISCHARGE_PERCENT)); - builder.setDischargedPowerRange( + builder.addDischargedPowerRange( parser.getAttributeDouble(null, XML_ATTR_DISCHARGE_LOWER), parser.getAttributeDouble(null, XML_ATTR_DISCHARGE_UPPER)); - builder.setDischargeDurationMs( + builder.addDischargeDurationMs( parser.getAttributeLong(null, XML_ATTR_DISCHARGE_DURATION)); builder.setBatteryTimeRemainingMs( parser.getAttributeLong(null, XML_ATTR_BATTERY_REMAINING)); @@ -1044,23 +1044,22 @@ public final class BatteryUsageStats implements Parcelable, Closeable { } /** - * Sets the battery discharge amount since BatteryStats reset as percentage of the full - * charge. + * Accumulates the battery discharge amount as percentage of the full charge. Can exceed 100 */ @NonNull - public Builder setDischargePercentage(int dischargePercentage) { - mDischargePercentage = dischargePercentage; + public Builder addDischargePercentage(int dischargePercentage) { + mDischargePercentage += dischargePercentage; return this; } /** - * Sets the estimated battery discharge range. + * Accumulates the estimated battery discharge range. */ @NonNull - public Builder setDischargedPowerRange(double dischargedPowerLowerBoundMah, + public Builder addDischargedPowerRange(double dischargedPowerLowerBoundMah, double dischargedPowerUpperBoundMah) { - mDischargedPowerLowerBoundMah = dischargedPowerLowerBoundMah; - mDischargedPowerUpperBoundMah = dischargedPowerUpperBoundMah; + mDischargedPowerLowerBoundMah += dischargedPowerLowerBoundMah; + mDischargedPowerUpperBoundMah += dischargedPowerUpperBoundMah; return this; } @@ -1068,8 +1067,8 @@ public final class BatteryUsageStats implements Parcelable, Closeable { * Sets the total battery discharge time, in milliseconds. */ @NonNull - public Builder setDischargeDurationMs(long durationMs) { - mDischargeDurationMs = durationMs; + public Builder addDischargeDurationMs(long durationMs) { + mDischargeDurationMs += durationMs; return this; } diff --git a/services/core/java/com/android/server/power/stats/BatteryChargeCalculator.java b/services/core/java/com/android/server/power/stats/BatteryChargeCalculator.java index cc05630d037e..f29d5b24b929 100644 --- a/services/core/java/com/android/server/power/stats/BatteryChargeCalculator.java +++ b/services/core/java/com/android/server/power/stats/BatteryChargeCalculator.java @@ -35,7 +35,7 @@ public class BatteryChargeCalculator extends PowerCalculator { @Override public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { - builder.setDischargePercentage( + builder.addDischargePercentage( batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)); int batteryCapacityMah = batteryStats.getBatteryCapacity(); @@ -45,11 +45,9 @@ public class BatteryChargeCalculator extends PowerCalculator { batteryStats.getLowDischargeAmountSinceCharge() * batteryCapacityMah / 100.0; final double dischargedPowerUpperBoundMah = batteryStats.getHighDischargeAmountSinceCharge() * batteryCapacityMah / 100.0; - builder.setDischargePercentage( - batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)) - .setDischargedPowerRange(dischargedPowerLowerBoundMah, - dischargedPowerUpperBoundMah) - .setDischargeDurationMs(batteryStats.getBatteryRealtime(rawRealtimeUs) / 1000); + builder + .addDischargedPowerRange(dischargedPowerLowerBoundMah, dischargedPowerUpperBoundMah) + .addDischargeDurationMs(batteryStats.getBatteryRealtime(rawRealtimeUs) / 1000); final long batteryTimeRemainingMs = batteryStats.computeBatteryTimeRemaining(rawRealtimeUs); if (batteryTimeRemainingMs != -1) { diff --git a/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java index 1459ff55aceb..d24ea83540cb 100644 --- a/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java @@ -24,12 +24,12 @@ import static com.android.server.power.stats.processor.AggregatedPowerStatsConfi import android.os.BatteryConsumer; import android.os.PersistableBundle; -import android.util.SparseLongArray; import com.android.internal.os.PowerStats; import com.android.server.power.stats.format.BasePowerStatsLayout; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.DoubleSupplier; @@ -37,9 +37,9 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { private final DoubleSupplier mBatteryCapacitySupplier; private PowerEstimationPlan mPlan; private long mStartTimestamp; - private final SparseLongArray mUidStartTimestamps = new SparseLongArray(); private static final BasePowerStatsLayout sStatsLayout = new BasePowerStatsLayout(); private final PowerStats.Descriptor mPowerStatsDescriptor; + private final PowerStats mPowerStats; private final long[] mTmpUidStatsArray; private double mBatteryCapacityUah; private int mBatteryLevel; @@ -59,12 +59,12 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { sStatsLayout.getDeviceStatsArrayLength(), null, 0, sStatsLayout.getUidStatsArrayLength(), extras); mTmpUidStatsArray = new long[sStatsLayout.getUidStatsArrayLength()]; + mPowerStats = new PowerStats(mPowerStatsDescriptor); } @Override void start(PowerComponentAggregatedPowerStats stats, long timestampMs) { mStartTimestamp = timestampMs; - mUidStartTimestamps.clear(); stats.setPowerStatsDescriptor(mPowerStatsDescriptor); mBatteryCapacityUah = mBatteryCapacitySupplier.getAsDouble() * 1000; mBatteryLevel = UNSPECIFIED; @@ -73,6 +73,9 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { mCumulativeDischargeUah = 0; mCumulativeDischargePct = 0; mCumulativeDischargeDurationMs = 0; + + // Establish a baseline + stats.addProcessedPowerStats(mPowerStats, timestampMs); } @Override @@ -101,32 +104,23 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { } @Override - public void setUidState(PowerComponentAggregatedPowerStats stats, int uid, - @AggregatedPowerStatsConfig.TrackedState int stateId, int state, long timestampMs) { - super.setUidState(stats, uid, stateId, state, timestampMs); - if (stateId == STATE_PROCESS_STATE && mUidStartTimestamps.indexOfKey(uid) < 0) { - mUidStartTimestamps.put(uid, timestampMs); - } - } - - @Override void finish(PowerComponentAggregatedPowerStats stats, long timestampMs) { if (mPlan == null) { mPlan = new PowerEstimationPlan(stats.getConfig()); } - PowerStats powerStats = new PowerStats(mPowerStatsDescriptor); - sStatsLayout.setUsageDuration(powerStats.stats, timestampMs - mStartTimestamp); + sStatsLayout.setUsageDuration(mPowerStats.stats, timestampMs - mStartTimestamp); - sStatsLayout.addBatteryDischargePercent(powerStats.stats, mCumulativeDischargePct); + sStatsLayout.addBatteryDischargePercent(mPowerStats.stats, mCumulativeDischargePct); if (mCumulativeDischargeUah != 0) { - sStatsLayout.addBatteryDischargeUah(powerStats.stats, + sStatsLayout.addBatteryDischargeUah(mPowerStats.stats, mCumulativeDischargeUah); } else { - sStatsLayout.addBatteryDischargeUah(powerStats.stats, + sStatsLayout.addBatteryDischargeUah(mPowerStats.stats, (long) (mCumulativeDischargePct * mBatteryCapacityUah / 100.0)); } - sStatsLayout.addBatteryDischargeDuration(powerStats.stats, mCumulativeDischargeDurationMs); + sStatsLayout.addBatteryDischargeDuration(mPowerStats.stats, mCumulativeDischargeDurationMs); + mCumulativeDischargePct = 0; mCumulativeDischargeUah = 0; mCumulativeDischargeDurationMs = 0; @@ -134,19 +128,16 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { List<Integer> uids = new ArrayList<>(); stats.collectUids(uids); + long durationMs = timestampMs - mStartTimestamp; if (!uids.isEmpty()) { for (int i = uids.size() - 1; i >= 0; i--) { - Integer uid = uids.get(i); - long durationMs = timestampMs - mUidStartTimestamps.get(uid, mStartTimestamp); - mUidStartTimestamps.put(uid, timestampMs); - long[] uidStats = new long[sStatsLayout.getUidStatsArrayLength()]; sStatsLayout.setUidUsageDuration(uidStats, durationMs); - powerStats.uidStats.put(uid, uidStats); + mPowerStats.uidStats.put(uids.get(i), uidStats); } } - stats.addPowerStats(powerStats, timestampMs); + stats.addPowerStats(mPowerStats, timestampMs); for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) { UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i); @@ -169,5 +160,7 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { } mStartTimestamp = timestampMs; + Arrays.fill(mPowerStats.stats, 0); + mPowerStats.uidStats.clear(); } } diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java index 1b864bbe479c..8461a5442bd0 100644 --- a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java +++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java @@ -110,7 +110,8 @@ public class PowerStatsAggregator { lastTime = item.time; - if (item.batteryLevel != lastBatteryLevel) { + if (item.cmd == BatteryStats.HistoryItem.CMD_UPDATE + && item.batteryLevel != lastBatteryLevel) { mStats.noteBatteryLevel(item.batteryLevel, item.batteryChargeUah, item.time); lastBatteryLevel = item.batteryLevel; diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java index ef0e63bece90..177d12988a27 100644 --- a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java +++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java @@ -245,13 +245,13 @@ class PowerStatsExporter { private void populateBatteryLevelInfo(BatteryUsageStats.Builder builder, BatteryLevelInfo batteryLevelInfo) { - builder.setDischargePercentage((int) Math.round(batteryLevelInfo.batteryDischargePct)) - .setDischargedPowerRange(batteryLevelInfo.batteryDischargeMah, + builder.addDischargePercentage((int) Math.round(batteryLevelInfo.batteryDischargePct)) + .addDischargedPowerRange(batteryLevelInfo.batteryDischargeMah, batteryLevelInfo.batteryDischargeMah) - .setDischargeDurationMs(batteryLevelInfo.batteryDischargeDurationMs) + .addDischargeDurationMs(batteryLevelInfo.batteryDischargeDurationMs) .getAggregateBatteryConsumerBuilder( BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) - .setConsumedPower(batteryLevelInfo.batteryDischargeMah); + .addConsumedPower(batteryLevelInfo.batteryDischargeMah); } private void populateBatteryConsumers( diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java index 9da89fcf2e84..0da7184c3541 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java @@ -458,9 +458,9 @@ public class BatteryUsageStatsAtomTest { /* includeScreenStateData */ false, /* includePowerStateData */ false, /* minConsumedPowerThreshold */ 0) - .setDischargePercentage(20) - .setDischargedPowerRange(1000, 2000) - .setDischargeDurationMs(1234) + .addDischargePercentage(20) + .addDischargedPowerRange(1000, 2000) + .addDischargeDurationMs(1234) .setStatsStartTimestamp(1000) .setStatsEndTimestamp(20000) .setStatsDuration(10000); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java index 31ff50f8ca58..93fe8d330d5b 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java @@ -580,7 +580,7 @@ public class BatteryUsageStatsProviderTest { accumulateBatteryUsageStats(batteryStats, 10000000, 0); // Accumulate every 200 bytes of battery history accumulateBatteryUsageStats(batteryStats, 200, 2); - accumulateBatteryUsageStats(batteryStats, 50, 4); + accumulateBatteryUsageStats(batteryStats, 50, 5); // Accumulate on every invocation of accumulateBatteryUsageStats accumulateBatteryUsageStats(batteryStats, 0, 7); } @@ -617,6 +617,9 @@ public class BatteryUsageStatsProviderTest { assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); assertThat(stats.getStatsEndTimestamp()).isEqualTo(115 * MINUTE_IN_MS); + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .getConsumedPower()).isEqualTo(1200); // 1_200_000 uAh converted to mAh assertBatteryConsumer(stats, 360.0, 60 * MINUTE_IN_MS); assertBatteryConsumer(stats, APP_UID, 360.0, 60 * MINUTE_IN_MS); @@ -655,6 +658,9 @@ public class BatteryUsageStatsProviderTest { setTime(10 * MINUTE_IN_MS); synchronized (batteryStats) { + batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, + /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, + 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); batteryStats.noteFlashlightOnLocked(APP_UID, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); } @@ -663,6 +669,9 @@ public class BatteryUsageStatsProviderTest { setTime(20 * MINUTE_IN_MS); synchronized (batteryStats) { + batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, + /* plugType */ 0, 85, 72, 3700, 3_000_000, 4_000_000, 0, + 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); batteryStats.noteFlashlightOffLocked(APP_UID, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); } @@ -682,6 +691,9 @@ public class BatteryUsageStatsProviderTest { setTime(50 * MINUTE_IN_MS); synchronized (batteryStats) { + batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, + /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, + 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); batteryStats.noteFlashlightOffLocked(APP_UID, 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); } @@ -719,6 +731,10 @@ public class BatteryUsageStatsProviderTest { assertThat(stats.getChargeTimeRemainingMs()).isEqualTo(777); assertThat(stats.getBatteryCapacity()).isEqualTo(4000); // from PowerProfile + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .getConsumedPower()).isEqualTo(1200); // 3_600_000-2_400_000 uAh converted to mAh + // Total: 10 + 20 + 30 = 60 assertBatteryConsumer(stats, 360.0, 60 * MINUTE_IN_MS); assertBatteryConsumer(stats, APP_UID, 360.0, 60 * MINUTE_IN_MS); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java index dd50431b598e..097a60ed52c5 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java @@ -327,9 +327,9 @@ public class BatteryUsageStatsTest { new BatteryUsageStats.Builder(new String[]{"FOO"}, true, includeScreenState, includePowerState, 0) .setBatteryCapacity(4000) - .setDischargePercentage(20) - .setDischargedPowerRange(1000, 2000) - .setDischargeDurationMs(1234) + .addDischargePercentage(20) + .addDischargedPowerRange(1000, 2000) + .addDischargeDurationMs(1234) .setStatsStartTimestamp(1000) .setStatsEndTimestamp(3000); @@ -371,8 +371,8 @@ public class BatteryUsageStatsTest { final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(customPowerComponentNames, includeProcessStateData, true, true, 0); - builder.setDischargePercentage(30) - .setDischargedPowerRange(1234, 2345) + builder.addDischargePercentage(30) + .addDischargedPowerRange(1234, 2345) .setStatsStartTimestamp(2000) .setStatsEndTimestamp(5000); diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java index 6d818d7287b0..779676e4f979 100644 --- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java +++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java @@ -161,8 +161,8 @@ public class BatteryUsageStatsPerfTest { final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(new String[]{"FOO"}, false, false, false, 0) .setBatteryCapacity(4000) - .setDischargePercentage(20) - .setDischargedPowerRange(1000, 2000) + .addDischargePercentage(20) + .addDischargedPowerRange(1000, 2000) .setStatsStartTimestamp(1000) .setStatsEndTimestamp(3000); |