From fa2a4f44bdda2b3c8a889a38385a6ac2de1796eb Mon Sep 17 00:00:00 2001 From: Michael Wachenschwanz Date: Wed, 28 Apr 2021 21:17:34 -0700 Subject: [PATCH] Wipe BatteryStats on Custom Power Bucket change If the supported OTHER EnergyConsumers change after a reboot, the MeasuredEnergyStats from the reboot can no longer be considered valid. Bug: 178504428 Test: atest FrameworksCoreTests:com.android.internal.power.MeasuredEnergyStatsTest Change-Id: I2561c459c0b2a881661bd2913f9413a2cbd96abb --- .../internal/power/MeasuredEnergyStats.java | 24 ++++-- .../power/MeasuredEnergyStatsTest.java | 80 +++++++++++++++++++ 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java index 42fb3f4529492..72b57ab1d468c 100644 --- a/core/java/com/android/internal/power/MeasuredEnergyStats.java +++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java @@ -33,6 +33,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; /** * Tracks the measured charge consumption of various subsystems according to their @@ -96,8 +97,10 @@ public class MeasuredEnergyStats { * supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_POWER_BUCKETS}. * numCustomBuckets >= 0 is the number of (non-standard) custom power buckets on the device. */ - public MeasuredEnergyStats(boolean[] supportedStandardBuckets, String[] customBucketNames) { - final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length; + public MeasuredEnergyStats(@NonNull boolean[] supportedStandardBuckets, + @Nullable String[] customBucketNames) { + mCustomBucketNames = customBucketNames == null ? new String[0] : customBucketNames; + final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + mCustomBucketNames.length; mAccumulatedChargeMicroCoulomb = new long[numTotalBuckets]; // Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE. // All custom buckets are, by definition, supported, so their values stay at 0. @@ -106,7 +109,6 @@ public class MeasuredEnergyStats { mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE; } } - mCustomBucketNames = customBucketNames; } /** @@ -431,14 +433,22 @@ public class MeasuredEnergyStats { /** Check if the supported power buckets are precisely those given. */ public boolean isSupportEqualTo( - @NonNull boolean[] queriedStandardBuckets, String[] customBucketNames) { + @NonNull boolean[] queriedStandardBuckets, @Nullable String[] customBucketNames) { + if (customBucketNames == null) { + //In practice customBucketNames should never be null, but sanitize it just to be sure. + customBucketNames = new String[0]; + } final int numBuckets = getNumberOfIndices(); - // TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just - // quantitatively, and treat as mismatch if so. - if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length) { + final int numCustomBuckets = customBucketNames == null ? 0 : customBucketNames.length; + if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets) { return false; } + + if (!Arrays.equals(mCustomBucketNames, customBucketNames)) { + return false; + } + for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) { if (isStandardBucketSupported(stdBucket) != queriedStandardBuckets[stdBucket]) { return false; diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java index 2d894f59ee42f..a70033bf3e1f8 100644 --- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java @@ -499,4 +499,84 @@ public class MeasuredEnergyStatsTest { assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE)); assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE_SUSPEND)); } + + /** Test MeasuredEnergyStats#isSupportEqualTo */ + @Test + public void testIsSupportEqualTo() { + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; + Arrays.fill(supportedStandardBuckets, true); + final String[] customBucketNames = {"A", "B"}; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets.clone(), + customBucketNames.clone()); + + assertTrue( + "All standard and custom bucket supports match", + stats.isSupportEqualTo(supportedStandardBuckets, customBucketNames)); + + boolean[] differentSupportedStandardBuckets = supportedStandardBuckets.clone(); + differentSupportedStandardBuckets[0] = !differentSupportedStandardBuckets[0]; + assertFalse( + "Standard bucket support mismatch", + stats.isSupportEqualTo(differentSupportedStandardBuckets, customBucketNames)); + + assertFalse( + "Custom bucket support mismatch", + stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"C", "B"})); + + assertFalse( + "Fewer custom buckets supported", + stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A"})); + + assertFalse( + "More custom bucket supported", + stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A", "B", "C"})); + + assertFalse( + "Custom bucket support order changed", + stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"B", "A"})); + } + + /** Test MeasuredEnergyStats#isSupportEqualTo when holding a null array of custom buckets */ + @Test + public void testIsSupportEqualTo_nullCustomBuckets() { + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets.clone(), null); + + assertTrue( + "Null custom bucket name lists should match", + stats.isSupportEqualTo(supportedStandardBuckets, null)); + + assertTrue( + "Null and empty custom buckets should match", + stats.isSupportEqualTo(supportedStandardBuckets, new String[0])); + + assertFalse( + "Null custom buckets should not match populated list", + stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A", "B"})); + } + + /** Test MeasuredEnergyStats#isSupportEqualTo when holding an empty array of custom buckets */ + @Test + public void testIsSupportEqualTo_emptyCustomBuckets() { + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets.clone(), new String[0]); + + assertTrue( + "Empty custom buckets should match", + stats.isSupportEqualTo(supportedStandardBuckets, new String[0])); + + assertTrue( + "Empty and null custom buckets should match", + stats.isSupportEqualTo(supportedStandardBuckets, null)); + + assertFalse( + "Empty custom buckets should not match populated list", + stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A", "B"})); + } }