1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.os;
18 
19 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
20 import static android.os.BatteryStats.Uid.NUM_PROCESS_STATE;
21 import static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND;
22 import static android.os.BatteryStats.Uid.PROCESS_STATE_CACHED;
23 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
24 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
25 
26 import static org.junit.Assert.assertArrayEquals;
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.mockito.ArgumentMatchers.argThat;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.when;
33 
34 import android.os.BatteryStats;
35 import android.util.SparseArray;
36 import android.util.SparseIntArray;
37 import android.view.Display;
38 
39 import androidx.test.filters.LargeTest;
40 import androidx.test.runner.AndroidJUnit4;
41 
42 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
43 import com.android.internal.util.ArrayUtils;
44 
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.mockito.ArgumentMatcher;
49 import org.mockito.Mock;
50 import org.mockito.MockitoAnnotations;
51 
52 import java.util.Arrays;
53 
54 @LargeTest
55 @RunWith(AndroidJUnit4.class)
56 public class BatteryStatsImplTest {
57     @Mock
58     private KernelCpuUidFreqTimeReader mKernelUidCpuFreqTimeReader;
59     @Mock
60     private KernelSingleUidTimeReader mKernelSingleUidTimeReader;
61 
62     private MockBatteryStatsImpl mBatteryStatsImpl;
63 
64     @Before
setUp()65     public void setUp() {
66         MockitoAnnotations.initMocks(this);
67 
68         when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true);
69         when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true);
70         mBatteryStatsImpl = new MockBatteryStatsImpl()
71                 .setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
72                 .setKernelSingleUidTimeReader(mKernelSingleUidTimeReader);
73     }
74 
75     @Test
testUpdateProcStateCpuTimes()76     public void testUpdateProcStateCpuTimes() {
77         mBatteryStatsImpl.setOnBatteryInternal(true);
78         mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
79 
80         final int[] testUids = {10032, 10048, 10145, 10139};
81         final int[] testProcStates = {
82                 PROCESS_STATE_BACKGROUND,
83                 PROCESS_STATE_FOREGROUND_SERVICE,
84                 PROCESS_STATE_TOP,
85                 PROCESS_STATE_CACHED
86         };
87         addPendingUids(testUids, testProcStates);
88         final long[][] cpuTimes = {
89                 {349734983, 394982394832l, 909834, 348934, 9838},
90                 {7498, 1239890, 988, 13298, 98980},
91                 {989834, 384098, 98483, 23809, 4984},
92                 {4859048, 348903, 4578967, 5973894, 298549}
93         };
94         for (int i = 0; i < testUids.length; ++i) {
95             when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(cpuTimes[i]);
96 
97             // Verify there are no cpu times initially.
98             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
99             for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) {
100                 assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
101                 assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
102             }
103         }
104 
105         mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
106 
107         verifyNoPendingUids();
108         for (int i = 0; i < testUids.length; ++i) {
109             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
110             for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) {
111                 if (procState == testProcStates[i]) {
112                     assertArrayEquals("Uid=" + testUids[i], cpuTimes[i],
113                             u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
114                 } else {
115                     assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
116                 }
117                 assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
118             }
119         }
120 
121         final long[][] delta1 = {
122                 {9589, 148934, 309894, 3098493, 98754},
123                 {21983, 94983, 4983, 9878493, 84854},
124                 {945894, 9089432, 19478, 3834, 7845},
125                 {843895, 43948, 949582, 99, 384}
126         };
127         for (int i = 0; i < testUids.length; ++i) {
128             when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta1[i]);
129         }
130         addPendingUids(testUids, testProcStates);
131 
132         mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
133 
134         verifyNoPendingUids();
135         for (int i = 0; i < testUids.length; ++i) {
136             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
137             for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) {
138                 if (procState == testProcStates[i]) {
139                     long[] expectedCpuTimes = cpuTimes[i].clone();
140                     for (int j = 0; j < expectedCpuTimes.length; ++j) {
141                         expectedCpuTimes[j] += delta1[i][j];
142                     }
143                     assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes,
144                             u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
145                 } else {
146                     assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
147                 }
148                 assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
149             }
150         }
151 
152         mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
153         final long[][] delta2 = {
154                 {95932, 2943, 49834, 89034, 139},
155                 {349, 89605, 5896, 845, 98444},
156                 {678, 7498, 9843, 889, 4894},
157                 {488, 998, 8498, 394, 574}
158         };
159         for (int i = 0; i < testUids.length; ++i) {
160             when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta2[i]);
161         }
162         addPendingUids(testUids, testProcStates);
163 
164         mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
165 
166         verifyNoPendingUids();
167         for (int i = 0; i < testUids.length; ++i) {
168             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
169             for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) {
170                 if (procState == testProcStates[i]) {
171                     long[] expectedCpuTimes = cpuTimes[i].clone();
172                     for (int j = 0; j < expectedCpuTimes.length; ++j) {
173                         expectedCpuTimes[j] += delta1[i][j] + delta2[i][j];
174                     }
175                     assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes,
176                             u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
177                     assertArrayEquals("Uid=" + testUids[i], delta2[i],
178                             u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
179                 } else {
180                     assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
181                     assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
182                 }
183             }
184         }
185 
186         final long[][] delta3 = {
187                 {98545, 95768795, 76586, 548945, 57846},
188                 {788876, 586, 578459, 8776984, 9578923},
189                 {3049509483598l, 4597834, 377654, 94589035, 7854},
190                 {9493, 784, 99895, 8974893, 9879843}
191         };
192         for (int i = 0; i < testUids.length; ++i) {
193             when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(
194                     delta3[i].clone());
195         }
196         addPendingUids(testUids, testProcStates);
197         final int parentUid = testUids[1];
198         final int childUid = 99099;
199         addIsolatedUid(parentUid, childUid);
200         final long[] isolatedUidCpuTimes = {495784, 398473, 4895, 4905, 30984093};
201         when(mKernelSingleUidTimeReader.readDeltaMs(childUid)).thenReturn(isolatedUidCpuTimes);
202 
203         mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
204 
205         verifyNoPendingUids();
206         for (int i = 0; i < testUids.length; ++i) {
207             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
208             for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) {
209                 if (procState == testProcStates[i]) {
210                     long[] expectedCpuTimes = cpuTimes[i].clone();
211                     for (int j = 0; j < expectedCpuTimes.length; ++j) {
212                         expectedCpuTimes[j] += delta1[i][j] + delta2[i][j] + delta3[i][j]
213                                 + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0);
214                     }
215                     assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes,
216                             u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
217                     long[] expectedScreenOffTimes = delta2[i].clone();
218                     for (int j = 0; j < expectedScreenOffTimes.length; ++j) {
219                         expectedScreenOffTimes[j] += delta3[i][j]
220                                 + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0);
221                     }
222                     assertArrayEquals("Uid=" + testUids[i], expectedScreenOffTimes,
223                             u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
224                 } else {
225                     assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
226                     assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
227                 }
228             }
229         }
230     }
231 
232     @Test
testCopyFromAllUidsCpuTimes()233     public void testCopyFromAllUidsCpuTimes() {
234         mBatteryStatsImpl.setOnBatteryInternal(false);
235         mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
236 
237         final int[] testUids = {10032, 10048, 10145, 10139};
238         final int[] testProcStates = {
239                 PROCESS_STATE_BACKGROUND,
240                 PROCESS_STATE_FOREGROUND_SERVICE,
241                 PROCESS_STATE_TOP,
242                 PROCESS_STATE_CACHED
243         };
244         final int[] pendingUidIdx = {1, 2};
245         updateProcessStates(testUids, testProcStates, pendingUidIdx);
246 
247         final SparseArray<long[]> allUidCpuTimes = new SparseArray<>();
248         long[][] allCpuTimes = {
249                 {938483, 4985984, 439893},
250                 {499, 94904, 27694},
251                 {302949085, 39789473, 34792839},
252                 {9809485, 9083475, 347889834},
253         };
254         for (int i = 0; i < testUids.length; ++i) {
255             allUidCpuTimes.put(testUids[i], allCpuTimes[i]);
256         }
257         when(mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs()).thenReturn(allUidCpuTimes);
258         long[][] expectedCpuTimes = {
259                 {843598745, 397843, 32749, 99854},
260                 {9834, 5885, 487589, 394},
261                 {203984, 439, 9859, 30948},
262                 {9389, 858, 239, 349}
263         };
264         for (int i = 0; i < testUids.length; ++i) {
265             final int idx = i;
266             final ArgumentMatcher<long[]> matcher = times -> Arrays.equals(times, allCpuTimes[idx]);
267             when(mKernelSingleUidTimeReader.computeDelta(eq(testUids[i]), argThat(matcher)))
268                     .thenReturn(expectedCpuTimes[i]);
269         }
270 
271         mBatteryStatsImpl.copyFromAllUidsCpuTimes(true, false);
272 
273         verifyNoPendingUids();
274         for (int i = 0; i < testUids.length; ++i) {
275             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
276             for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) {
277                 if (procState == testProcStates[i]) {
278                     assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes[i],
279                             u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
280                 } else {
281                     assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState));
282                 }
283                 assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
284             }
285         }
286     }
287 
288     @Test
testAddCpuTimes()289     public void testAddCpuTimes() {
290         long[] timesA = null;
291         long[] timesB = null;
292         assertNull(mBatteryStatsImpl.addCpuTimes(timesA, timesB));
293 
294         timesA = new long[] {34, 23, 45, 24};
295         assertArrayEquals(timesA, mBatteryStatsImpl.addCpuTimes(timesA, timesB));
296 
297         timesB = timesA;
298         timesA = null;
299         assertArrayEquals(timesB, mBatteryStatsImpl.addCpuTimes(timesA, timesB));
300 
301         final long[] expected = {434, 6784, 34987, 9984};
302         timesA = new long[timesB.length];
303         for (int i = 0; i < timesA.length; ++i) {
304             timesA[i] = expected[i] - timesB[i];
305         }
306         assertArrayEquals(expected, mBatteryStatsImpl.addCpuTimes(timesA, timesB));
307     }
308 
309     @Test
testMulticastWakelockAcqRel()310     public void testMulticastWakelockAcqRel() {
311         final int testUid = 10032;
312         final int acquireTimeMs = 1000;
313         final int releaseTimeMs = 1005;
314         final int currentTimeMs = 1011;
315 
316         mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
317 
318         // Create a Uid Object
319         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
320         assertNotNull(u);
321 
322         // Acquire and release the lock
323         u.noteWifiMulticastEnabledLocked(acquireTimeMs);
324         u.noteWifiMulticastDisabledLocked(releaseTimeMs);
325 
326         // Get the total acquisition time
327         long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
328                 BatteryStats.STATS_SINCE_CHARGED);
329         assertEquals("Miscalculations of Multicast wakelock acquisition time",
330                 (releaseTimeMs - acquireTimeMs) * 1000, totalTime);
331     }
332 
333     @Test
testMulticastWakelockAcqNoRel()334     public void testMulticastWakelockAcqNoRel() {
335         final int testUid = 10032;
336         final int acquireTimeMs = 1000;
337         final int currentTimeMs = 1011;
338 
339         mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
340 
341         // Create a Uid Object
342         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
343         assertNotNull(u);
344 
345         // Acquire the lock
346         u.noteWifiMulticastEnabledLocked(acquireTimeMs);
347 
348         // Get the total acquisition time
349         long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
350                 BatteryStats.STATS_SINCE_CHARGED);
351         assertEquals("Miscalculations of Multicast wakelock acquisition time",
352                 (currentTimeMs - acquireTimeMs) * 1000, totalTime);
353     }
354 
355     @Test
testMulticastWakelockAcqAcqRelRel()356     public void testMulticastWakelockAcqAcqRelRel() {
357         final int testUid = 10032;
358         final int acquireTimeMs_1 = 1000;
359         final int acquireTimeMs_2 = 1002;
360 
361         final int releaseTimeMs_1 = 1005;
362         final int releaseTimeMs_2 = 1009;
363         final int currentTimeMs = 1011;
364 
365         mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
366 
367         // Create a Uid Object
368         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
369         assertNotNull(u);
370 
371         // Acquire and release the lock (twice in nested way)
372         u.noteWifiMulticastEnabledLocked(acquireTimeMs_1);
373         u.noteWifiMulticastEnabledLocked(acquireTimeMs_2);
374 
375         u.noteWifiMulticastDisabledLocked(releaseTimeMs_1);
376         u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
377 
378         // Get the total acquisition time
379         long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
380                 BatteryStats.STATS_SINCE_CHARGED);
381         assertEquals("Miscalculations of Multicast wakelock acquisition time",
382                 (releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime);
383     }
384 
385     @Test
testMulticastWakelockAcqRelAcqRel()386     public void testMulticastWakelockAcqRelAcqRel() {
387         final int testUid = 10032;
388         final int acquireTimeMs_1 = 1000;
389         final int acquireTimeMs_2 = 1005;
390 
391         final int releaseTimeMs_1 = 1002;
392         final int releaseTimeMs_2 = 1009;
393         final int currentTimeMs = 1011;
394 
395         mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
396 
397         // Create a Uid Object
398         final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
399         assertNotNull(u);
400 
401         // Acquire and release the lock (twice)
402         u.noteWifiMulticastEnabledLocked(acquireTimeMs_1);
403         u.noteWifiMulticastDisabledLocked(releaseTimeMs_1);
404 
405         u.noteWifiMulticastEnabledLocked(acquireTimeMs_2);
406         u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
407 
408         // Get the total acquisition time
409         long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
410                 BatteryStats.STATS_SINCE_CHARGED);
411         assertEquals("Miscalculations of Multicast wakelock acquisition time",
412                 ((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2))
413                 * 1000, totalTime);
414     }
415 
addIsolatedUid(int parentUid, int childUid)416     private void addIsolatedUid(int parentUid, int childUid) {
417         final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(parentUid);
418         u.addIsolatedUid(childUid);
419     }
420 
addPendingUids(int[] uids, int[] procStates)421     private void addPendingUids(int[] uids, int[] procStates) {
422         final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
423         for (int i = 0; i < uids.length; ++i) {
424             pendingUids.put(uids[i], procStates[i]);
425         }
426     }
427 
updateProcessStates(int[] uids, int[] procStates, int[] pendingUidsIdx)428     private void updateProcessStates(int[] uids, int[] procStates,
429             int[] pendingUidsIdx) {
430         final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
431         for (int i = 0; i < uids.length; ++i) {
432             final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uids[i]);
433             if (ArrayUtils.contains(pendingUidsIdx, i)) {
434                 u.setProcessStateForTest(PROCESS_STATE_TOP);
435                 pendingUids.put(uids[i], procStates[i]);
436             } else {
437                 u.setProcessStateForTest(procStates[i]);
438             }
439         }
440     }
441 
verifyNoPendingUids()442     private void verifyNoPendingUids() {
443         final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
444         assertEquals("There shouldn't be any pending uids left: " + pendingUids,
445                 0, pendingUids.size());
446     }
447 }
448