summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dmitri Plotnikov <dplotnikov@google.com> 2025-02-04 17:53:10 -0800
committer Dmitri Plotnikov <dplotnikov@google.com> 2025-02-06 10:13:19 -0800
commite5fb4df6a9c18fc38bc7532d8a8c5b86c94c6573 (patch)
tree99ebb007e09257abb649829fde577d798f8cb357
parent8896bc45d0ea005ff54f97a023af4d8d96f4f09d (diff)
Fix device-wide accumulation of consumed power estimates
Bug: 382803366 Flag: EXEMPT bugfix Test: atest PowerStatsTests; atest PowerStatsTestsRavenwood Change-Id: If4da14840244af85e3a21387c537b59e79ae836b
-rw-r--r--core/java/android/os/BatteryUsageStats.java25
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryChargeCalculator.java10
-rw-r--r--services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java41
-rw-r--r--services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java3
-rw-r--r--services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java8
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java6
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java18
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java10
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java4
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);