From 5f212c86a4fce26e5f87413df3dbfee181fa1ff8 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 13 Mar 2017 12:25:13 -0700 Subject: [PATCH] BatteryStats: Prevent double-detaching Counter Detaching a Counter from a TimeBase means you can't use it anymore. Only newly constructed Counters are automatically attached to a TimeBase. Bug: 34200689 Test: make FrameworkCoreTests && adb install ... && adb shell am instrument -w -e class com.android.internal.os.BatteryStatsSensorTest com.android.frameworks.coretests Change-Id: I9309000d5625aa6fe61a3c05f135e5828137d8ce --- .../android/internal/os/BatteryStatsImpl.java | 8 +++- .../internal/os/BatteryStatsSensorTest.java | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 2aeddb306c4d4..6aa77665db510 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -6027,7 +6027,8 @@ public class BatteryStatsImpl extends BatteryStats { * Clear all stats for this uid. Returns true if the uid is completely * inactive so can be dropped. */ - boolean reset() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public boolean reset() { boolean active = false; if (mWifiRunningTimer != null) { @@ -6968,7 +6969,10 @@ public class BatteryStatsImpl extends BatteryStats { boolean reset() { if (mBgCounter != null) { - mBgCounter.reset(true); + mBgCounter.reset(true /*detachIfReset*/); + // If we detach, we must null the mBgCounter reference so that it + // can be recreated and attached. + mBgCounter = null; } if (mTimer.reset(true)) { mTimer = null; diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java index e15216384ec14..4ec78ff5be7f5 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java @@ -65,4 +65,49 @@ public class BatteryStatsSensorTest extends TestCase { assertEquals(1, sensorBgCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); } + + @SmallTest + public void testNestedSensorReset() throws Exception { + final MockClocks clocks = new MockClocks(); + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + bi.mForceOnBattery = true; + clocks.realtime = 100; + clocks.uptime = 100; + bi.getOnBatteryTimeBase().setRunning(true, 100, 100); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER); + + clocks.realtime += 100; + clocks.uptime += 100; + + bi.noteStartSensorLocked(UID, SENSOR_ID); + + clocks.realtime += 100; + clocks.uptime += 100; + + // The sensor is started and the background counter has been created. + final BatteryStats.Uid uid = bi.getUidStats().get(UID); + assertNotNull(uid); + + BatteryStats.Uid.Sensor sensor = uid.getSensorStats().get(SENSOR_ID); + assertNotNull(sensor); + assertNotNull(sensor.getSensorTime()); + assertNotNull(sensor.getSensorBgCount()); + + // Reset the stats. Since the sensor is still running, we should still see the sensor + // timer. Background counter should be gone though. + bi.getUidStatsLocked(UID).reset(); + + sensor = uid.getSensorStats().get(SENSOR_ID); + assertNotNull(sensor); + assertNotNull(sensor.getSensorTime()); + assertNull(sensor.getSensorBgCount()); + + bi.noteStopSensorLocked(UID, SENSOR_ID); + + // Now the sensor timer has stopped so this reset should also take out the sensor. + bi.getUidStatsLocked(UID).reset(); + + sensor = uid.getSensorStats().get(SENSOR_ID); + assertNull(sensor); + } }