OSDN Git Service

BatteryStats: Prevent double-detaching Counter
authorAdam Lesinski <adamlesinski@google.com>
Mon, 13 Mar 2017 19:25:13 +0000 (12:25 -0700)
committerAdam Lesinski <adamlesinski@google.com>
Mon, 13 Mar 2017 22:39:24 +0000 (22:39 +0000)
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

core/java/com/android/internal/os/BatteryStatsImpl.java
core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java

index 2aeddb3..6aa7766 100644 (file)
@@ -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;
index e152163..4ec78ff 100644 (file)
@@ -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);
+    }
 }