Home | History | Annotate | Download | only in os
      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