1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.internal.os; 17 18 import static android.os.BatteryStats.STATS_SINCE_CHARGED; 19 20 import android.app.ActivityManager; 21 import android.os.BatteryStats; 22 import android.os.WorkSource; 23 import android.support.test.filters.SmallTest; 24 import android.util.ArrayMap; 25 import android.view.Display; 26 27 import junit.framework.TestCase; 28 29 /** 30 * Test BatteryStatsImpl onBatteryBackgroundTimeBase TimeBase. 31 */ 32 public class BatteryStatsBackgroundStatsTest extends TestCase { 33 34 private static final int UID = 10500; 35 36 /** Test that BatteryStatsImpl.Uid.mOnBatteryBackgroundTimeBase works correctly. */ 37 @SmallTest 38 public void testBgTimeBase() throws Exception { 39 final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms 40 MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); 41 long cur = 0; // realtime in us 42 43 BatteryStatsImpl.TimeBase bgtb = bi.getOnBatteryBackgroundTimeBase(UID); 44 45 // Off-battery, non-existent 46 clocks.realtime = clocks.uptime = 10; 47 cur = clocks.realtime * 1000; 48 bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur); // off battery 49 assertFalse(bgtb.isRunning()); 50 assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 51 52 // Off-battery, foreground 53 clocks.realtime = clocks.uptime = 100; 54 cur = clocks.realtime * 1000; 55 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 56 assertFalse(bgtb.isRunning()); 57 assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 58 59 // Off-battery, background 60 clocks.realtime = clocks.uptime = 201; 61 cur = clocks.realtime * 1000; 62 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 63 assertFalse(bgtb.isRunning()); 64 assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 65 66 // On-battery, background 67 clocks.realtime = clocks.uptime = 303; 68 cur = clocks.realtime * 1000; 69 bi.updateTimeBasesLocked(true, Display.STATE_ON, cur, cur); // on battery 70 // still in ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND 71 assertTrue(bgtb.isRunning()); 72 assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 73 74 // On-battery, background - but change screen state 75 clocks.realtime = clocks.uptime = 409; 76 cur = clocks.realtime * 1000; 77 bi.updateTimeBasesLocked(true, Display.STATE_OFF, cur, cur); // on battery (again) 78 assertTrue(bgtb.isRunning()); 79 assertEquals(106_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 80 81 // On-battery, background - but a different background state 82 clocks.realtime = clocks.uptime = 417; 83 cur = clocks.realtime * 1000; 84 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER); // background too 85 assertTrue(bgtb.isRunning()); 86 assertEquals(114_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 87 88 // Off-battery, foreground 89 clocks.realtime = clocks.uptime = 530; 90 cur = clocks.realtime * 1000; 91 bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur); // off battery 92 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 93 assertFalse(bgtb.isRunning()); 94 assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 95 96 // Off-battery, non-existent 97 clocks.realtime = clocks.uptime = 690; 98 cur = clocks.realtime * 1000; 99 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_NONEXISTENT); 100 assertFalse(bgtb.isRunning()); 101 assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 102 } 103 104 /** Test that BatteryStatsImpl.Uid.mOnBatteryScreenOffBackgroundTimeBase works correctly. */ 105 @SmallTest 106 public void testScreenOffBgTimeBase() throws Exception { 107 final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms 108 MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); 109 long cur = 0; // realtime in us 110 111 BatteryStatsImpl.TimeBase bgtb = bi.getOnBatteryScreenOffBackgroundTimeBase(UID); 112 113 // battery=off, screen=off, background=off 114 cur = (clocks.realtime = clocks.uptime = 100) * 1000; 115 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 116 bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur); 117 assertFalse(bgtb.isRunning()); 118 119 // battery=on, screen=off, background=off 120 cur = (clocks.realtime = clocks.uptime = 200) * 1000; 121 bi.updateTimeBasesLocked(true, Display.STATE_ON, cur, cur); 122 assertFalse(bgtb.isRunning()); 123 124 // battery=on, screen=on, background=off 125 cur = (clocks.realtime = clocks.uptime = 300) * 1000; 126 bi.updateTimeBasesLocked(true, Display.STATE_OFF, cur, cur); 127 assertFalse(bgtb.isRunning()); 128 129 // battery=on, screen=on, background=on 130 // Only during this period should the timebase progress 131 cur = (clocks.realtime = clocks.uptime = 400) * 1000; 132 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 133 assertTrue(bgtb.isRunning()); 134 135 // battery=on, screen=off, background=on 136 cur = (clocks.realtime = clocks.uptime = 550) * 1000; 137 bi.updateTimeBasesLocked(true, Display.STATE_ON, cur, cur); 138 assertFalse(bgtb.isRunning()); 139 140 // battery=off, screen=off, background=on 141 cur = (clocks.realtime = clocks.uptime = 660) * 1000; 142 bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur); 143 assertFalse(bgtb.isRunning()); 144 145 // battery=off, screen=off, background=off 146 cur = (clocks.realtime = clocks.uptime = 770) * 1000; 147 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 148 assertFalse(bgtb.isRunning()); 149 150 assertEquals(150_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED)); 151 } 152 153 @SmallTest 154 public void testWifiScan() throws Exception { 155 final MockClocks clocks = new MockClocks(); 156 MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); 157 long curr = 0; // realtime in us 158 159 // On battery 160 curr = 1000 * (clocks.realtime = clocks.uptime = 100); 161 bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery 162 // App in foreground 163 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 164 165 // Start timer 166 curr = 1000 * (clocks.realtime = clocks.uptime = 202); 167 bi.noteWifiScanStartedLocked(UID); 168 169 // Move to background 170 curr = 1000 * (clocks.realtime = clocks.uptime = 254); 171 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 172 173 // Off battery 174 curr = 1000 * (clocks.realtime = clocks.uptime = 305); 175 bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery 176 177 // Stop timer 178 curr = 1000 * (clocks.realtime = clocks.uptime = 409); 179 bi.noteWifiScanStoppedLocked(UID); 180 181 // Test 182 curr = 1000 * (clocks.realtime = clocks.uptime = 657); 183 long time = bi.getUidStats().get(UID).getWifiScanTime(curr, STATS_SINCE_CHARGED); 184 int count = bi.getUidStats().get(UID).getWifiScanCount(STATS_SINCE_CHARGED); 185 int bgCount = bi.getUidStats().get(UID).getWifiScanBackgroundCount(STATS_SINCE_CHARGED); 186 long actualTime = bi.getUidStats().get(UID).getWifiScanActualTime(curr); 187 long bgTime = bi.getUidStats().get(UID).getWifiScanBackgroundTime(curr); 188 assertEquals((305 - 202) * 1000, time); 189 assertEquals(1, count); 190 assertEquals(0, bgCount); 191 assertEquals((305 - 202) * 1000, actualTime); 192 assertEquals((305 - 254) * 1000, bgTime); 193 } 194 195 @SmallTest 196 public void testAppBluetoothScan() throws Exception { 197 final MockClocks clocks = new MockClocks(); 198 MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); 199 WorkSource ws = new WorkSource(UID); // needed for bluetooth 200 long curr = 0; // realtime in us 201 202 // On battery 203 curr = 1000 * (clocks.realtime = clocks.uptime = 100); 204 bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery 205 206 // App in foreground 207 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 208 209 // Start timer (optimized) 210 curr = 1000 * (clocks.realtime = clocks.uptime = 202); 211 bi.noteBluetoothScanStartedFromSourceLocked(ws, false); 212 213 // Move to background 214 curr = 1000 * (clocks.realtime = clocks.uptime = 254); 215 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 216 217 // Off battery 218 curr = 1000 * (clocks.realtime = clocks.uptime = 305); 219 bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery 220 221 // Start timer (unoptimized) 222 curr = 1000 * (clocks.realtime = clocks.uptime = 1000); 223 bi.noteBluetoothScanStartedFromSourceLocked(ws, true); 224 225 // On battery 226 curr = 1000 * (clocks.realtime = clocks.uptime = 2001); 227 bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery 228 229 // Move to foreground 230 curr = 1000 * (clocks.realtime = clocks.uptime = 3004); 231 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP); 232 233 // Stop timer (optimized) 234 curr = 1000 * (clocks.realtime = clocks.uptime = 3409); 235 bi.noteBluetoothScanStoppedFromSourceLocked(ws, false); 236 237 // Stop timer (unoptimized) 238 curr = 1000 * (clocks.realtime = clocks.uptime = 4008); 239 bi.noteBluetoothScanStoppedFromSourceLocked(ws, true); 240 241 // Test 242 curr = 1000 * (clocks.realtime = clocks.uptime = 5000); 243 BatteryStats.Timer timer = bi.getUidStats().get(UID).getBluetoothScanTimer(); 244 BatteryStats.Timer bgTimer = bi.getUidStats().get(UID).getBluetoothScanBackgroundTimer(); 245 BatteryStats.Timer badTimer = bi.getUidStats().get(UID).getBluetoothUnoptimizedScanTimer(); 246 BatteryStats.Timer badBgTimer = bi.getUidStats().get(UID) 247 .getBluetoothUnoptimizedScanBackgroundTimer(); 248 249 long time = timer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); 250 int count = timer.getCountLocked(STATS_SINCE_CHARGED); 251 int bgCount = bgTimer.getCountLocked(STATS_SINCE_CHARGED); 252 long actualTime = timer.getTotalDurationMsLocked(clocks.realtime) * 1000; 253 long bgTime = bgTimer.getTotalDurationMsLocked(clocks.realtime) * 1000; 254 long badTime = badTimer.getTotalDurationMsLocked(clocks.realtime) * 1000; 255 long badBgTime = badBgTimer.getTotalDurationMsLocked(clocks.realtime) * 1000; 256 assertEquals((305 - 202 + 4008 - 2001) * 1000, time); 257 assertEquals(1, count); // second scan starts off-battery 258 assertEquals(0, bgCount); // first scan starts in fg, second starts off-battery 259 assertEquals((305 - 202 + 4008 - 2001) * 1000, actualTime); 260 assertEquals((305 - 254 + 3004 - 2001) * 1000, bgTime); 261 assertEquals((4008 - 2001) * 1000, badTime); 262 assertEquals((3004 - 2001) * 1000, badBgTime); 263 } 264 265 @SmallTest 266 public void testJob() throws Exception { 267 final MockClocks clocks = new MockClocks(); 268 MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); 269 final String jobName = "job_name"; 270 long curr = 0; // realtime in us 271 272 // On battery 273 curr = 1000 * (clocks.realtime = clocks.uptime = 100); 274 bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery 275 // App in foreground 276 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 277 278 // Start timer 279 curr = 1000 * (clocks.realtime = clocks.uptime = 151); 280 bi.noteJobStartLocked(jobName, UID); 281 282 // Stop timer 283 curr = 1000 * (clocks.realtime = clocks.uptime = 161); 284 bi.noteJobFinishLocked(jobName, UID, 0); 285 286 // Move to background 287 curr = 1000 * (clocks.realtime = clocks.uptime = 202); 288 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 289 290 // Start timer 291 curr = 1000 * (clocks.realtime = clocks.uptime = 254); 292 bi.noteJobStartLocked(jobName, UID); 293 294 // Off battery 295 curr = 1000 * (clocks.realtime = clocks.uptime = 305); 296 bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery 297 298 // Stop timer 299 curr = 1000 * (clocks.realtime = clocks.uptime = 409); 300 bi.noteJobFinishLocked(jobName, UID, 0); 301 302 // Test 303 curr = 1000 * (clocks.realtime = clocks.uptime = 657); 304 final ArrayMap<String, ? extends BatteryStats.Timer> jobs = 305 bi.getUidStats().get(UID).getJobStats(); 306 assertEquals(1, jobs.size()); 307 BatteryStats.Timer timer = jobs.valueAt(0); 308 BatteryStats.Timer bgTimer = timer.getSubTimer(); 309 long time = timer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); 310 int count = timer.getCountLocked(STATS_SINCE_CHARGED); 311 int bgCount = bgTimer.getCountLocked(STATS_SINCE_CHARGED); 312 long bgTime = bgTimer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); 313 assertEquals((161 - 151 + 305 - 254) * 1000, time); 314 assertEquals(2, count); 315 assertEquals(1, bgCount); 316 assertEquals((305 - 254) * 1000, bgTime); 317 318 // Test that a second job is separate. 319 curr = 1000 * (clocks.realtime = clocks.uptime = 3000); 320 final String jobName2 = "second_job"; 321 bi.noteJobStartLocked(jobName2, UID); 322 assertEquals(2, bi.getUidStats().get(UID).getJobStats().size()); 323 bi.noteJobFinishLocked(jobName2, UID, 0); 324 } 325 326 @SmallTest 327 public void testSyncs() throws Exception { 328 final MockClocks clocks = new MockClocks(); 329 MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); 330 final String syncName = "sync_name"; 331 long curr = 0; // realtime in us 332 333 // On battery 334 curr = 1000 * (clocks.realtime = clocks.uptime = 100); 335 bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery 336 // App in foreground 337 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 338 339 // Start timer 340 curr = 1000 * (clocks.realtime = clocks.uptime = 151); 341 bi.noteSyncStartLocked(syncName, UID); 342 343 // Stop timer 344 curr = 1000 * (clocks.realtime = clocks.uptime = 161); 345 bi.noteSyncFinishLocked(syncName, UID); 346 347 // Move to background 348 curr = 1000 * (clocks.realtime = clocks.uptime = 202); 349 bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); 350 351 // Start timer 352 curr = 1000 * (clocks.realtime = clocks.uptime = 254); 353 bi.noteSyncStartLocked(syncName, UID); 354 355 // Off battery 356 curr = 1000 * (clocks.realtime = clocks.uptime = 305); 357 bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery 358 359 // Stop timer 360 curr = 1000 * (clocks.realtime = clocks.uptime = 409); 361 bi.noteSyncFinishLocked(syncName, UID); 362 363 // Test 364 curr = 1000 * (clocks.realtime = clocks.uptime = 657); 365 final ArrayMap<String, ? extends BatteryStats.Timer> syncs = 366 bi.getUidStats().get(UID).getSyncStats(); 367 assertEquals(1, syncs.size()); 368 BatteryStats.Timer timer = syncs.valueAt(0); 369 BatteryStats.Timer bgTimer = timer.getSubTimer(); 370 long time = timer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); 371 int count = timer.getCountLocked(STATS_SINCE_CHARGED); 372 int bgCount = bgTimer.getCountLocked(STATS_SINCE_CHARGED); 373 long bgTime = bgTimer.getTotalTimeLocked(curr, STATS_SINCE_CHARGED); 374 assertEquals((161 - 151 + 305 - 254) * 1000, time); 375 assertEquals(2, count); 376 assertEquals(1, bgCount); 377 assertEquals((305 - 254) * 1000, bgTime); 378 379 // Test that a second sync is separate. 380 curr = 1000 * (clocks.realtime = clocks.uptime = 3000); 381 final String syncName2 = "second_sync"; 382 bi.noteSyncStartLocked(syncName2, UID); 383 assertEquals(2, bi.getUidStats().get(UID).getSyncStats().size()); 384 bi.noteSyncFinishLocked(syncName2, UID); 385 } 386 } 387