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