| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.android.internal.os; |
| |
| import android.app.ActivityManager; |
| import android.os.BatteryStats; |
| import android.support.test.filters.SmallTest; |
| |
| import junit.framework.TestCase; |
| |
| /** |
| * Test BatteryStatsImpl Sensor Timers. |
| */ |
| public class BatteryStatsSensorTest extends TestCase { |
| |
| private static final int UID = 10500; |
| private static final int SENSOR_ID = -10000; |
| |
| @SmallTest |
| public void testSensorStartStop() 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_000, 100_000); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| clocks.realtime = 200; |
| clocks.uptime = 200; |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| clocks.realtime = 400; |
| clocks.uptime = 400; |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| BatteryStats.Timer sensorBgTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorBackgroundTime(); |
| |
| assertEquals(2, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(300_000, sensorTimer.getTotalTimeLocked( |
| clocks.realtime * 1000, BatteryStats.STATS_SINCE_CHARGED)); |
| |
| assertEquals(1, sensorBgTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(200_000, sensorBgTimer.getTotalTimeLocked( |
| clocks.realtime * 1000, BatteryStats.STATS_SINCE_CHARGED)); |
| } |
| |
| @SmallTest |
| public void testCountingWhileOffBattery() throws Exception { |
| final MockClocks clocks = new MockClocks(); |
| MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); |
| long curr = 0; // realtime in us |
| |
| // Plugged-in (battery=off, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 100); |
| bi.updateTimeBasesLocked(false, false, curr, curr); |
| |
| |
| // Start sensor (battery=off, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 200); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 215); |
| BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| assertEquals(0, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| |
| // Stop sensor (battery=off, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 550); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| // Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 678); |
| sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| assertEquals(0, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| } |
| |
| @SmallTest |
| public void testCountingWhileOnBattery() throws Exception { |
| final MockClocks clocks = new MockClocks(); |
| MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); |
| long curr = 0; // realtime in us |
| |
| // Unplugged (battery=on, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 100); |
| bi.updateTimeBasesLocked(true, false, curr, curr); |
| |
| // Start sensor (battery=on, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 200); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 215); |
| BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| assertEquals((215-200)*1000, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| |
| // Stop sensor (battery=on, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 550); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| // Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 678); |
| sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| assertEquals((550-200)*1000, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| } |
| |
| @SmallTest |
| public void testBatteryStatusOnToOff() throws Exception { |
| final MockClocks clocks = new MockClocks(); |
| MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); |
| long curr = 0; // realtime in us |
| |
| // On battery (battery=on, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 100); |
| bi.updateTimeBasesLocked(true, false, curr, curr); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); |
| |
| // Start sensor (battery=on, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 202); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // Off battery (battery=off, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 305); |
| bi.updateTimeBasesLocked(false, false, curr, curr); |
| |
| // Stop sensor while off battery (battery=off, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 409); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| // Start sensor while off battery (battery=off, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 519); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // Test while still running (but off battery) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 657); |
| BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals((305-202)*1000, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| |
| // Now stop running (still off battery) (battery=off, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 693); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| assertEquals(1, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals((305-202)*1000, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| } |
| |
| @SmallTest |
| public void testBatteryStatusOffToOn() throws Exception { |
| final MockClocks clocks = new MockClocks(); |
| MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); |
| long curr = 0; // realtime in us |
| |
| // Plugged-in (battery=off, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 100); |
| bi.updateTimeBasesLocked(false, false, curr, curr); |
| |
| // Start sensor (battery=off, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 200); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 215); |
| BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| // Time was entirely off battery, so time=0. |
| assertEquals(0, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| // Acquired off battery, so count=0. |
| assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| |
| // Unplug (battery=on, sensor=on) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 305); |
| bi.updateTimeBasesLocked(true, false, curr, curr); |
| |
| //Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 410); |
| sensorTimer = bi.getUidStats().get(UID).getSensorStats().get(SENSOR_ID).getSensorTime(); |
| // Part of the time it was on battery. |
| assertEquals((410-305)*1000, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| // Only ever acquired off battery, so count=0. |
| assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| |
| // Stop sensor (battery=on, sensor=off) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 550); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| // Test situation |
| curr = 1000 * (clocks.realtime = clocks.uptime = 678); |
| sensorTimer = bi.getUidStats().get(UID).getSensorStats().get(SENSOR_ID).getSensorTime(); |
| // Part of the time it was on battery. |
| assertEquals((550-305)*1000, |
| sensorTimer.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| // Only ever acquired off battery, so count=0. |
| assertEquals(0, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| } |
| |
| @SmallTest |
| public void testPooledBackgroundUsage() throws Exception { |
| final int UID_2 = 20000; // second uid for testing pool usage |
| final MockClocks clocks = new MockClocks(); |
| MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); |
| bi.mForceOnBattery = true; |
| long curr = 0; // realtime in us |
| // Entire test is on-battery |
| curr = 1000 * (clocks.realtime = clocks.uptime = 1000); |
| bi.updateTimeBasesLocked(true, false, curr, curr); |
| |
| // See below for a diagram of events. |
| |
| // UID in foreground |
| curr = 1000 * (clocks.realtime = clocks.uptime = 2002); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); |
| |
| // UID starts the sensor (foreground) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 3004); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // UID_2 in background |
| curr = 1000 * (clocks.realtime = clocks.uptime = 4008); |
| bi.noteUidProcessStateLocked(UID_2, ActivityManager.PROCESS_STATE_RECEIVER); // background |
| |
| // UID_2 starts the sensor (background) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 5016); |
| bi.noteStartSensorLocked(UID_2, SENSOR_ID); |
| |
| // UID enters background |
| curr = 1000 * (clocks.realtime = clocks.uptime = 6032); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); |
| |
| // UID enters background again (from a different background state) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 7004); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_LAST_ACTIVITY); |
| |
| // UID_2 stops the sensor (background), then starts it again, then stops again |
| curr = 1000 * (clocks.realtime = clocks.uptime = 8064); |
| bi.noteStopSensorLocked(UID_2, SENSOR_ID); |
| curr = 1000 * (clocks.realtime = clocks.uptime = 9128); |
| bi.noteStartSensorLocked(UID_2, SENSOR_ID); |
| curr = 1000 * (clocks.realtime = clocks.uptime = 10256); |
| bi.noteStopSensorLocked(UID_2, SENSOR_ID); |
| |
| // UID re-enters foreground |
| curr = 1000 * (clocks.realtime = clocks.uptime = 11512); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); |
| |
| // UID starts the sensor a second time (foreground) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 12000); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // UID re-enters background |
| curr = 1000 * (clocks.realtime = clocks.uptime = 13002); |
| bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); |
| |
| // UID stops the sensor completely (background) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 14004); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| curr = 1000 * (clocks.realtime = clocks.uptime = 14024); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| // UID starts the sensor anew (background) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 15010); |
| bi.noteStartSensorLocked(UID, SENSOR_ID); |
| |
| // UID stops the sensor (background) |
| curr = 1000 * (clocks.realtime = clocks.uptime = 16020); |
| bi.noteStopSensorLocked(UID, SENSOR_ID); |
| |
| // Summary |
| // UID |
| // foreground: 2002---6032, 11512---13002 |
| // background: 6032---------------11512, 13002-------------------------- |
| // sensor running: 3004-----------------------------14024, 15010-16020 |
| // |
| // UID2 |
| // foreground: |
| // background: 4008------------------------------------------------------- |
| // sensor running: 5016--8064, 9128-10256 |
| |
| BatteryStats.Timer timer1 = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| BatteryStats.Timer bgTimer1 = bi.getUidStats().get(UID).getSensorStats() |
| .get(SENSOR_ID).getSensorBackgroundTime(); |
| |
| BatteryStats.Timer timer2 = bi.getUidStats().get(UID_2).getSensorStats() |
| .get(SENSOR_ID).getSensorTime(); |
| BatteryStats.Timer bgTimer2 = bi.getUidStats().get(UID_2).getSensorStats() |
| .get(SENSOR_ID).getSensorBackgroundTime(); |
| |
| // Expected values |
| long expActualTime1 = (14024 - 3004) + (16020 - 15010); |
| long expBgTime1 = (11512 - 6032) + (14024 - 13002) + (16020 - 15010); |
| |
| long expActualTime2 = (8064 - 5016) + (10256 - 9128); |
| long expBgTime2 = (8064 - 5016) + (10256 - 9128); |
| |
| long expBlamedTime1 = (5016 - 3004) + (8064 - 5016)/2 + (9128 - 8064) + (10256 - 9128)/2 |
| + (14024 - 10256) + (16020 - 15010); |
| long expBlamedTime2 = (8064 - 5016)/2 + (10256 - 9128)/2; |
| |
| // Test: UID - blamed time |
| assertEquals(expBlamedTime1 * 1000, |
| timer1.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| // Test: UID - actual time |
| assertEquals(expActualTime1 * 1000, |
| timer1.getTotalDurationMsLocked(clocks.realtime) * 1000 ); |
| // Test: UID - background time |
| // bg timer ignores pools, so both totalTime and totalDuration should give the same result |
| assertEquals(expBgTime1 * 1000, |
| bgTimer1.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(expBgTime1 * 1000, |
| bgTimer1.getTotalDurationMsLocked(clocks.realtime) * 1000 ); |
| // Test: UID - count |
| assertEquals(2, timer1.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| // Test: UID - background count |
| assertEquals(1, bgTimer1.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| |
| // Test: UID_2 - blamed time |
| assertEquals(expBlamedTime2 * 1000, |
| timer2.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| // Test: UID_2 - actual time |
| assertEquals(expActualTime2 * 1000, |
| timer2.getTotalDurationMsLocked(clocks.realtime) * 1000); |
| // Test: UID_2 - background time |
| // bg timer ignores pools, so both totalTime and totalDuration should give the same result |
| assertEquals(expBgTime2 * 1000, |
| bgTimer2.getTotalTimeLocked(curr, BatteryStats.STATS_SINCE_CHARGED)); |
| assertEquals(expBgTime2 * 1000, |
| bgTimer2.getTotalDurationMsLocked(clocks.realtime) * 1000 ); |
| // Test: UID_2 - count |
| assertEquals(2, timer2.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| // Test: UID_2 - background count |
| assertEquals(2, bgTimer2.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); |
| } |
| |
| @SmallTest |
| public void testSensorReset() 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_000, 100_000); |
| 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 timer 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.getSensorBackgroundTime()); |
| |
| // Reset the stats. Since the sensor is still running, we should still see the timer |
| bi.getUidStatsLocked(UID).reset(); |
| |
| sensor = uid.getSensorStats().get(SENSOR_ID); |
| assertNotNull(sensor); |
| assertNotNull(sensor.getSensorTime()); |
| assertNotNull(sensor.getSensorBackgroundTime()); |
| |
| 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); |
| } |
| } |