• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.WAKE_TYPE_PARTIAL;
21 import static android.os.Process.FIRST_APPLICATION_UID;
22 import static android.os.Process.FIRST_ISOLATED_UID;
23 
24 import static com.android.internal.os.BatteryStatsImpl.WAKE_LOCK_WEIGHT;
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.junit.Assert.assertTrue;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.anyBoolean;
33 import static org.mockito.ArgumentMatchers.isNull;
34 import static org.mockito.Mockito.doAnswer;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.verifyNoMoreInteractions;
38 import static org.mockito.Mockito.when;
39 
40 import android.os.BatteryStats;
41 import android.os.UserHandle;
42 import android.util.SparseLongArray;
43 import android.view.Display;
44 
45 import androidx.test.filters.SmallTest;
46 import androidx.test.runner.AndroidJUnit4;
47 
48 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
49 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
50 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
51 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
52 import com.android.internal.util.ArrayUtils;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.Mock;
58 import org.mockito.Mockito;
59 import org.mockito.MockitoAnnotations;
60 
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 
64 /**
65  * To run the tests, use
66  *
67  * runtest -c com.android.internal.os.BatteryStatsCpuTimesTest frameworks-core
68  *
69  * or
70  *
71  * Build: m FrameworksCoreTests
72  * Install: adb install -r \
73  * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
74  * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsCpuTimesTest -w \
75  * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
76  *
77  * or
78  *
79  * atest FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
80  */
81 @SmallTest
82 @RunWith(AndroidJUnit4.class)
83 public class BatteryStatsCpuTimesTest {
84     @Mock
85     KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
86     @Mock
87     KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader;
88     @Mock
89     KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader;
90     @Mock
91     KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
92     @Mock
93     SystemServerCpuThreadReader mSystemServerCpuThreadReader;
94     @Mock
95     BatteryStatsImpl.UserInfoProvider mUserInfoProvider;
96     @Mock
97     PowerProfile mPowerProfile;
98 
99     private MockClock mClocks;
100     private MockBatteryStatsImpl mBatteryStatsImpl;
101     private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
102 
103     @Before
setUp()104     public void setUp() {
105         MockitoAnnotations.initMocks(this);
106 
107         mClocks = new MockClock();
108         mBatteryStatsImpl = new MockBatteryStatsImpl(mClocks)
109                 .setKernelCpuUidUserSysTimeReader(mCpuUidUserSysTimeReader)
110                 .setKernelCpuUidFreqTimeReader(mCpuUidFreqTimeReader)
111                 .setKernelCpuUidActiveTimeReader(mCpuUidActiveTimeReader)
112                 .setKernelCpuUidClusterTimeReader(mCpuUidClusterTimeReader)
113                 .setSystemServerCpuThreadReader(mSystemServerCpuThreadReader)
114                 .setUserInfoProvider(mUserInfoProvider);
115     }
116 
117     @Test
testUpdateCpuTimeLocked()118     public void testUpdateCpuTimeLocked() {
119         // PRECONDITIONS
120         mBatteryStatsImpl.setPowerProfile(mPowerProfile);
121         mBatteryStatsImpl.setOnBatteryInternal(false);
122         final int numClusters = 3;
123         initKernelCpuSpeedReaders(numClusters);
124         final long[] freqs = {1, 12, 123, 12, 1234};
125         when(mCpuUidFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
126 
127         // RUN
128         mBatteryStatsImpl.updateCpuTimeLocked(false, false, null);
129 
130         // VERIFY
131         assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
132         verify(mCpuUidUserSysTimeReader).readDelta(anyBoolean(), isNull());
133         verify(mCpuUidFreqTimeReader).readDelta(anyBoolean(), isNull());
134         for (int i = 0; i < numClusters; ++i) {
135             verify(mKernelCpuSpeedReaders[i]).readDelta();
136         }
137 
138         // Prepare for next test
139         Mockito.reset(mUserInfoProvider, mCpuUidFreqTimeReader, mCpuUidUserSysTimeReader);
140         for (int i = 0; i < numClusters; ++i) {
141             Mockito.reset(mKernelCpuSpeedReaders[i]);
142         }
143 
144         // PRECONDITIONS
145         mBatteryStatsImpl.setOnBatteryInternal(true);
146 
147         // RUN
148         mBatteryStatsImpl.updateCpuTimeLocked(true, false, null);
149 
150         // VERIFY
151         verify(mUserInfoProvider).refreshUserIds();
152         verify(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
153                 any(KernelCpuUidUserSysTimeReader.Callback.class));
154         // perClusterTimesAvailable is called twice, once in updateCpuTimeLocked() and the other
155         // in readKernelUidCpuFreqTimesLocked.
156         verify(mCpuUidFreqTimeReader, times(2)).perClusterTimesAvailable();
157         verify(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
158                 any(KernelCpuUidFreqTimeReader.Callback.class));
159         verify(mCpuUidActiveTimeReader).readAbsolute(
160                 any(KernelCpuUidActiveTimeReader.Callback.class));
161         verify(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
162                 any(KernelCpuUidClusterTimeReader.Callback.class));
163         verifyNoMoreInteractions(mCpuUidFreqTimeReader);
164         for (int i = 0; i < numClusters; ++i) {
165             verify(mKernelCpuSpeedReaders[i]).readDelta();
166         }
167     }
168 
169     @Test
testMarkPartialTimersAsEligible()170     public void testMarkPartialTimersAsEligible() {
171         // PRECONDITIONS
172         final ArrayList<BatteryStatsImpl.StopwatchTimer> partialTimers = getPartialTimers(
173                 10032, 10042, 10052);
174         final ArrayList<BatteryStatsImpl.StopwatchTimer> lastPartialTimers
175                 = new ArrayList<>(partialTimers);
176         mBatteryStatsImpl.setPartialTimers(partialTimers);
177         mBatteryStatsImpl.setLastPartialTimers(lastPartialTimers);
178         final boolean[] inList = {false, true, false};
179         for (int i = 0; i < partialTimers.size(); ++i) {
180             partialTimers.get(i).mInList = inList[i];
181         }
182 
183         // RUN
184         mBatteryStatsImpl.markPartialTimersAsEligible();
185 
186         // VERIFY
187         assertTrue(ArrayUtils.referenceEquals(partialTimers, lastPartialTimers));
188         for (int i = 0; i < partialTimers.size(); ++i) {
189             assertTrue("Timer id=" + i, partialTimers.get(i).mInList);
190         }
191 
192         // PRECONDITIONS
193         partialTimers.addAll(getPartialTimers(10077, 10099));
194         partialTimers.remove(1 /* index */);
195 
196         // RUN
197         mBatteryStatsImpl.markPartialTimersAsEligible();
198 
199         // VERIFY
200         assertTrue(ArrayUtils.referenceEquals(partialTimers, lastPartialTimers));
201         for (int i = 0; i < partialTimers.size(); ++i) {
202             assertTrue("Timer id=" + i, partialTimers.get(i).mInList);
203         }
204     }
205 
206     @Test
testUpdateClusterSpeedTimes()207     public void testUpdateClusterSpeedTimes() {
208         // PRECONDITIONS
209         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
210         final long[][] clusterSpeedTimesMs = {{20, 30}, {40, 50, 60}};
211         initKernelCpuSpeedReaders(clusterSpeedTimesMs.length);
212         for (int i = 0; i < clusterSpeedTimesMs.length; ++i) {
213             when(mKernelCpuSpeedReaders[i].readDelta()).thenReturn(clusterSpeedTimesMs[i]);
214         }
215         when(mPowerProfile.getNumCpuClusters()).thenReturn(clusterSpeedTimesMs.length);
216         for (int i = 0; i < clusterSpeedTimesMs.length; ++i) {
217             when(mPowerProfile.getNumSpeedStepsInCpuCluster(i))
218                     .thenReturn(clusterSpeedTimesMs[i].length);
219         }
220         final SparseLongArray updatedUids = new SparseLongArray();
221         final int[] testUids = {10012, 10014, 10016};
222         final int[] cpuTimeUs = {89, 31, 43};
223         for (int i = 0; i < testUids.length; ++i) {
224             updatedUids.put(testUids[i], cpuTimeUs[i]);
225         }
226 
227         // RUN
228         mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true, null);
229 
230         // VERIFY
231         int totalClustersTimeMs = 0;
232         for (int i = 0; i < clusterSpeedTimesMs.length; ++i) {
233             for (int j = 0; j < clusterSpeedTimesMs[i].length; ++j) {
234                 totalClustersTimeMs += clusterSpeedTimesMs[i][j];
235             }
236         }
237         for (int i = 0; i < testUids.length; ++i) {
238             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
239             assertNotNull("No entry for uid=" + testUids[i], u);
240             for (int cluster = 0; cluster < clusterSpeedTimesMs.length; ++cluster) {
241                 for (int speed = 0; speed < clusterSpeedTimesMs[cluster].length; ++speed) {
242                     assertEquals("Uid=" + testUids[i] + ", cluster=" + cluster + ", speed=" + speed,
243                             cpuTimeUs[i] * clusterSpeedTimesMs[cluster][speed]
244                                     / totalClustersTimeMs,
245                             u.getTimeAtCpuSpeed(cluster, speed, STATS_SINCE_CHARGED));
246                 }
247             }
248         }
249     }
250 
251     @Test
testReadKernelUidCpuTimesLocked()252     public void testReadKernelUidCpuTimesLocked() {
253         //PRECONDITIONS
254         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
255         final int testUserId = 11;
256         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
257         final int[] testUids = getUids(testUserId, new int[]{
258                 FIRST_APPLICATION_UID + 22,
259                 FIRST_APPLICATION_UID + 27,
260                 FIRST_APPLICATION_UID + 33
261         });
262         final long[][] uidTimesUs = {
263                 {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
264         };
265         doAnswer(invocation -> {
266             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
267                     invocation.getArgument(1);
268             for (int i = 0; i < testUids.length; ++i) {
269                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
270             }
271             return null;
272         }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
273                 any(KernelCpuUidUserSysTimeReader.Callback.class));
274 
275         // RUN
276         final SparseLongArray updatedUids = new SparseLongArray();
277         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids, true);
278 
279         // VERIFY
280         for (int i = 0; i < testUids.length; ++i) {
281             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
282             assertNotNull("No entry for uid=" + testUids[i], u);
283             assertEquals("Unexpected user cpu time for uid=" + testUids[i],
284                     uidTimesUs[i][0], u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
285             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
286                     uidTimesUs[i][1], u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
287 
288             assertEquals("Unexpected entry in updated uids for uid=" + testUids[i],
289                     uidTimesUs[i][0] + uidTimesUs[i][1], updatedUids.get(testUids[i]));
290             updatedUids.delete(testUids[i]);
291         }
292         assertEquals("Updated uids: " + updatedUids, 0, updatedUids.size());
293 
294         // Repeat the test with a null updatedUids
295 
296         // PRECONDITIONS
297         final long[][] deltasUs = {
298                 {9379, 3332409833484L}, {493247, 723234}, {3247819, 123348}
299         };
300         doAnswer(invocation -> {
301             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
302                     invocation.getArgument(1);
303             for (int i = 0; i < testUids.length; ++i) {
304                 callback.onUidCpuTime(testUids[i], deltasUs[i]);
305             }
306             return null;
307         }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
308                 any(KernelCpuUidUserSysTimeReader.Callback.class));
309 
310         // RUN
311         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
312 
313         // VERIFY
314         for (int i = 0; i < testUids.length; ++i) {
315             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
316             assertNotNull("No entry for uid=" + testUids[i], u);
317             assertEquals("Unexpected user cpu time for uid=" + testUids[i],
318                     uidTimesUs[i][0] + deltasUs[i][0], u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
319             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
320                     uidTimesUs[i][1] + deltasUs[i][1], u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
321         }
322     }
323 
324     @Test
testReadKernelUidCpuTimesLocked_isolatedUid()325     public void testReadKernelUidCpuTimesLocked_isolatedUid() {
326         //PRECONDITIONS
327         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
328         final int testUserId = 11;
329         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
330         final int isolatedAppId = FIRST_ISOLATED_UID + 27;
331         final int isolatedUid = UserHandle.getUid(testUserId, isolatedAppId);
332         final int[] testUids = getUids(testUserId, new int[]{
333                 FIRST_APPLICATION_UID + 22,
334                 isolatedAppId,
335                 FIRST_APPLICATION_UID + 33
336         });
337         final long[][] uidTimesUs = {
338                 {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
339         };
340         doAnswer(invocation -> {
341             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
342                     invocation.getArgument(1);
343             for (int i = 0; i < testUids.length; ++i) {
344                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
345             }
346             return null;
347         }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
348                 any(KernelCpuUidUserSysTimeReader.Callback.class));
349 
350         // RUN
351         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
352 
353         // VERIFY
354         for (int i = 0; i < testUids.length; ++i) {
355             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
356             if (UserHandle.isIsolated(testUids[i])) {
357                 assertNull("There shouldn't be an entry for isolated uid=" + testUids[i], u);
358                 continue;
359             }
360             assertNotNull("No entry for uid=" + testUids[i], u);
361             assertEquals("Unexpected user cpu time for uid=" + testUids[i],
362                     uidTimesUs[i][0], u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
363             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
364                     uidTimesUs[i][1], u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
365         }
366 
367         // Add an isolated uid mapping and repeat the test.
368 
369         // PRECONDITIONS
370         final int ownerUid = UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 42);
371         mBatteryStatsImpl.addIsolatedUidLocked(isolatedUid, ownerUid);
372         final long[][] deltasUs = {
373                 {9379, 3332409833484L}, {493247, 723234}, {3247819, 123348}
374         };
375         doAnswer(invocation -> {
376             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
377                     invocation.getArgument(1);
378             for (int i = 0; i < testUids.length; ++i) {
379                 callback.onUidCpuTime(testUids[i], deltasUs[i]);
380             }
381             return null;
382         }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
383                 any(KernelCpuUidUserSysTimeReader.Callback.class));
384 
385         // RUN
386         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
387 
388         // VERIFY
389         for (int i = 0; i < testUids.length; ++i) {
390             BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
391             final long expectedUserTimeUs;
392             final long expectedSystemTimeUs;
393             if (UserHandle.isIsolated(testUids[i])) {
394                 assertNull("There shouldn't be an entry for isolated uid=" + testUids[i], u);
395                 // Since we added a mapping, an entry should've been created for owner uid.
396                 u = mBatteryStatsImpl.getUidStats().get(ownerUid);
397                 expectedUserTimeUs = deltasUs[i][0];
398                 expectedSystemTimeUs = deltasUs[i][1];
399                 assertNotNull("No entry for owner uid=" + ownerUid, u);
400             } else {
401                 assertNotNull("No entry for uid=" + testUids[i], u);
402                 expectedUserTimeUs = uidTimesUs[i][0] + deltasUs[i][0];
403                 expectedSystemTimeUs = uidTimesUs[i][1] + deltasUs[i][1];
404             }
405             assertEquals("Unexpected user cpu time for uid=" + testUids[i],
406                     expectedUserTimeUs, u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
407             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
408                     expectedSystemTimeUs, u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
409         }
410     }
411 
412     @Test
testReadKernelUidCpuTimesLocked_invalidUid()413     public void testReadKernelUidCpuTimesLocked_invalidUid() {
414         //PRECONDITIONS
415         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
416         final int testUserId = 11;
417         final int invalidUserId = 15;
418         final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
419         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
420         when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
421         final int[] testUids = getUids(testUserId, new int[]{
422                 FIRST_APPLICATION_UID + 22,
423                 FIRST_APPLICATION_UID + 27,
424                 FIRST_APPLICATION_UID + 33
425         });
426         final long[][] uidTimesUs = {
427                 {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
428         };
429         doAnswer(invocation -> {
430             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
431                     invocation.getArgument(1);
432             for (int i = 0; i < testUids.length; ++i) {
433                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
434             }
435             // And one for the invalid uid
436             callback.onUidCpuTime(invalidUid, new long[]{3879, 239});
437             return null;
438         }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
439                 any(KernelCpuUidUserSysTimeReader.Callback.class));
440 
441         // RUN
442         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
443 
444         // VERIFY
445         for (int i = 0; i < testUids.length; ++i) {
446             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
447             assertNotNull("No entry for uid=" + testUids[i], u);
448             assertEquals("Unexpected user cpu time for uid=" + testUids[i],
449                     uidTimesUs[i][0], u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
450             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
451                     uidTimesUs[i][1], u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
452         }
453         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
454                 mBatteryStatsImpl.getUidStats().get(invalidUid));
455     }
456 
457     @Test
testReadKernelUidCpuTimesLocked_withPartialTimers()458     public void testReadKernelUidCpuTimesLocked_withPartialTimers() {
459         //PRECONDITIONS
460         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
461         final int testUserId = 11;
462         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
463         final int[] testUids = getUids(testUserId, new int[]{
464                 FIRST_APPLICATION_UID + 22,
465                 FIRST_APPLICATION_UID + 27,
466                 FIRST_APPLICATION_UID + 33
467         });
468         final int[] partialTimerUids = {
469                 UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 48),
470                 UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 10)
471         };
472         final ArrayList<BatteryStatsImpl.StopwatchTimer> partialTimers
473                 = getPartialTimers(partialTimerUids);
474         final long[][] uidTimesUs = {
475                 {12, 34}, {3394, 3123}, {7977, 80434}
476         };
477         doAnswer(invocation -> {
478             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
479                     invocation.getArgument(1);
480             for (int i = 0; i < testUids.length; ++i) {
481                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
482             }
483             return null;
484         }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
485                 any(KernelCpuUidUserSysTimeReader.Callback.class));
486 
487         // RUN
488         final SparseLongArray updatedUids = new SparseLongArray();
489         mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids, true);
490 
491         // VERIFY
492         long totalUserTimeUs = 0;
493         long totalSystemTimeUs = 0;
494         for (int i = 0; i < testUids.length; ++i) {
495             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
496             assertNotNull("No entry for uid=" + testUids[i], u);
497             final long expectedUserTimeUs = uidTimesUs[i][0] * WAKE_LOCK_WEIGHT / 100;
498             final long expectedSystemTimeUs = uidTimesUs[i][1] * WAKE_LOCK_WEIGHT / 100;
499             assertEquals("Unexpected user cpu time for uid=" + testUids[i],
500                     expectedUserTimeUs, u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
501             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
502                     expectedSystemTimeUs, u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
503             assertEquals("Unexpected entry in updated uids for uid=" + testUids[i],
504                     expectedUserTimeUs + expectedSystemTimeUs, updatedUids.get(testUids[i]));
505             updatedUids.delete(testUids[i]);
506             totalUserTimeUs += uidTimesUs[i][0];
507             totalSystemTimeUs += uidTimesUs[i][1];
508         }
509 
510         totalUserTimeUs = totalUserTimeUs * (100 - WAKE_LOCK_WEIGHT) / 100;
511         totalSystemTimeUs = totalSystemTimeUs * (100 - WAKE_LOCK_WEIGHT) / 100;
512         for (int i = 0; i < partialTimerUids.length; ++i) {
513             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(partialTimerUids[i]);
514             assertNotNull("No entry for partial timer uid=" + partialTimerUids[i], u);
515             final long expectedUserTimeUs = totalUserTimeUs / (partialTimerUids.length - i);
516             final long expectedSystemTimeUs = totalSystemTimeUs / (partialTimerUids.length - i);
517             assertEquals("Unexpected user cpu time for partial timer uid=" + partialTimerUids[i],
518                     expectedUserTimeUs, u.getUserCpuTimeUs(STATS_SINCE_CHARGED));
519             assertEquals("Unexpected system cpu time for partial timer uid=" + partialTimerUids[i],
520                     expectedSystemTimeUs, u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
521             assertEquals("Unexpected entry in updated uids for partial timer uid="
522                             + partialTimerUids[i],
523                     expectedUserTimeUs + expectedSystemTimeUs,
524                     updatedUids.get(partialTimerUids[i]));
525             updatedUids.delete(partialTimerUids[i]);
526             totalUserTimeUs -= expectedUserTimeUs;
527             totalSystemTimeUs -= expectedSystemTimeUs;
528 
529             final BatteryStats.Uid.Proc proc = u.getProcessStats().get("*wakelock*");
530             assertEquals("Unexpected user cpu time for *wakelock* in uid=" + partialTimerUids[i],
531                     expectedUserTimeUs / 1000, proc.getUserTime(STATS_SINCE_CHARGED));
532             assertEquals("Unexpected system cpu time for *wakelock* in uid=" + partialTimerUids[i],
533                     expectedSystemTimeUs / 1000, proc.getSystemTime(STATS_SINCE_CHARGED));
534         }
535         assertEquals(0, totalUserTimeUs);
536         assertEquals(0, totalSystemTimeUs);
537         assertEquals("Updated uids: " + updatedUids, 0, updatedUids.size());
538     }
539 
540     @Test
testReadKernelUidCpuFreqTimesLocked()541     public void testReadKernelUidCpuFreqTimesLocked() {
542         // PRECONDITIONS
543         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
544 
545         final int testUserId = 11;
546         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
547         final int[] testUids = getUids(testUserId, new int[]{
548                 FIRST_APPLICATION_UID + 22,
549                 FIRST_APPLICATION_UID + 27,
550                 FIRST_APPLICATION_UID + 33
551         });
552         final long[][] uidTimesMs = {
553                 {4, 10, 5, 9, 4},
554                 {5, 1, 12, 2, 10},
555                 {8, 25, 3, 0, 42}
556         };
557         doAnswer(invocation -> {
558             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
559                     invocation.getArgument(1);
560             for (int i = 0; i < testUids.length; ++i) {
561                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
562             }
563             return null;
564         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
565                 any(KernelCpuUidFreqTimeReader.Callback.class));
566 
567         // RUN
568         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
569 
570         // VERIFY
571         for (int i = 0; i < testUids.length; ++i) {
572             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
573             assertNotNull("No entry for uid=" + testUids[i], u);
574 
575             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
576                     uidTimesMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
577             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
578                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
579         }
580 
581         // Repeat the test when the screen is off.
582 
583         // PRECONDITIONS
584         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
585         final long[][] deltasMs = {
586                 {3, 12, 55, 100, 32},
587                 {3248327490475L, 232349349845043L, 123, 2398, 0},
588                 {43, 3345, 2143, 123, 4554}
589         };
590         doAnswer(invocation -> {
591             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
592                     invocation.getArgument(1);
593             for (int i = 0; i < testUids.length; ++i) {
594                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
595             }
596             return null;
597         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
598                 any(KernelCpuUidFreqTimeReader.Callback.class));
599 
600         // RUN
601         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
602 
603         // VERIFY
604         for (int i = 0; i < testUids.length; ++i) {
605             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
606             assertNotNull("No entry for uid=" + testUids[i], u);
607 
608             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
609                     sum(uidTimesMs[i], deltasMs[i]), u.getCpuFreqTimes(STATS_SINCE_CHARGED));
610             assertArrayEquals("Unexpected screen-off cpu times for uid=" + testUids[i],
611                     deltasMs[i], u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
612         }
613     }
614 
615     @Test
testReadKernelUidCpuFreqTimesLocked_perClusterTimesAvailable()616     public void testReadKernelUidCpuFreqTimesLocked_perClusterTimesAvailable() {
617         // PRECONDITIONS
618         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
619 
620         final int testUserId = 11;
621         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
622         final int[] testUids = getUids(testUserId, new int[]{
623                 FIRST_APPLICATION_UID + 22,
624                 FIRST_APPLICATION_UID + 27,
625                 FIRST_APPLICATION_UID + 33
626         });
627         final long[] freqs = {1, 12, 123, 12, 1234};
628         // Derived from freqs above, 2 clusters with {3, 2} freqs in each of them.
629         final int[] clusterFreqs = {3, 2};
630         when(mPowerProfile.getNumCpuClusters()).thenReturn(clusterFreqs.length);
631         for (int i = 0; i < clusterFreqs.length; ++i) {
632             when(mPowerProfile.getNumSpeedStepsInCpuCluster(i))
633                     .thenReturn(clusterFreqs[i]);
634         }
635         final long[][] uidTimesMs = {
636                 {4, 10, 5, 9, 4},
637                 {5, 1, 12, 2, 10},
638                 {8, 25, 3, 0, 42}
639         };
640         doAnswer(invocation -> {
641             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
642                     invocation.getArgument(1);
643             for (int i = 0; i < testUids.length; ++i) {
644                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
645             }
646             return null;
647         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
648                 any(KernelCpuUidFreqTimeReader.Callback.class));
649         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
650 
651         // RUN
652         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
653 
654         // VERIFY
655         for (int i = 0; i < testUids.length; ++i) {
656             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
657             assertNotNull("No entry for uid=" + testUids[i], u);
658 
659             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
660                     uidTimesMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
661             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
662                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
663 
664             int idx = 0;
665             for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
666                 for (int speed = 0; speed < clusterFreqs[cluster]; ++speed) {
667                     assertEquals("Unexpected time at cluster=" + cluster + ", speed=" + speed,
668                             uidTimesMs[i][idx] * 1000,
669                             u.getTimeAtCpuSpeed(cluster, speed, STATS_SINCE_CHARGED));
670                     idx++;
671                 }
672             }
673         }
674 
675         // Repeat the test when the screen is off.
676 
677         // PRECONDITIONS
678         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
679         final long[][] deltasMs = {
680                 {3, 12, 55, 100, 32},
681                 {3248327490475L, 232349349845043L, 123, 2398, 0},
682                 {43, 3345, 2143, 123, 4554}
683         };
684         doAnswer(invocation -> {
685             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
686                     invocation.getArgument(1);
687             for (int i = 0; i < testUids.length; ++i) {
688                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
689             }
690             return null;
691         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
692                 any(KernelCpuUidFreqTimeReader.Callback.class));
693 
694         // RUN
695         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
696 
697         // VERIFY
698         for (int i = 0; i < testUids.length; ++i) {
699             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
700             assertNotNull("No entry for uid=" + testUids[i], u);
701 
702             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
703                     sum(uidTimesMs[i], deltasMs[i]), u.getCpuFreqTimes(STATS_SINCE_CHARGED));
704             assertArrayEquals("Unexpected screen-off cpu times for uid=" + testUids[i],
705                     deltasMs[i], u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
706 
707             int idx = 0;
708             for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
709                 for (int speed = 0; speed < clusterFreqs[cluster]; ++speed) {
710                     assertEquals("Unexpected time at cluster=" + cluster + ", speed=" + speed,
711                             (uidTimesMs[i][idx] + deltasMs[i][idx]) * 1000,
712                             u.getTimeAtCpuSpeed(cluster, speed, STATS_SINCE_CHARGED));
713                     idx++;
714                 }
715             }
716         }
717     }
718 
719     @Test
testReadKernelUidCpuFreqTimesLocked_partialTimers()720     public void testReadKernelUidCpuFreqTimesLocked_partialTimers() {
721         // PRECONDITIONS
722         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
723 
724         final int testUserId = 11;
725         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
726         final int[] testUids = getUids(testUserId, new int[]{
727                 FIRST_APPLICATION_UID + 22,
728                 FIRST_APPLICATION_UID + 27,
729                 FIRST_APPLICATION_UID + 33
730         });
731         final int[] partialTimerUids = {
732                 UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 48),
733                 UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 10)
734         };
735         final ArrayList<BatteryStatsImpl.StopwatchTimer> partialTimers
736                 = getPartialTimers(partialTimerUids);
737         final long[] freqs = {1, 12, 123, 12, 1234};
738         // Derived from freqs above, 2 clusters with {3, 2} freqs in each of them.
739         final int[] clusterFreqs = {3, 2};
740         when(mPowerProfile.getNumCpuClusters()).thenReturn(clusterFreqs.length);
741         for (int i = 0; i < clusterFreqs.length; ++i) {
742             when(mPowerProfile.getNumSpeedStepsInCpuCluster(i))
743                     .thenReturn(clusterFreqs[i]);
744         }
745         final long[][] uidTimesMs = {
746                 {4, 10, 5, 9, 4},
747                 {5, 1, 12, 2, 10},
748                 {8, 25, 3, 0, 42}
749         };
750         doAnswer(invocation -> {
751             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
752                     invocation.getArgument(1);
753             for (int i = 0; i < testUids.length; ++i) {
754                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
755             }
756             return null;
757         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
758                 any(KernelCpuUidFreqTimeReader.Callback.class));
759         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
760 
761         // RUN
762         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false, null);
763 
764         // VERIFY
765         final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][];
766         for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
767             expectedWakeLockUidTimesUs[cluster] = new long[clusterFreqs[cluster]];
768         }
769         for (int i = 0; i < testUids.length; ++i) {
770             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
771             assertNotNull("No entry for uid=" + testUids[i], u);
772 
773             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
774                     uidTimesMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
775             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
776                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
777 
778             int idx = 0;
779             for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
780                 for (int speed = 0; speed < clusterFreqs[cluster]; ++speed) {
781                     final long expectedTimeUs =
782                             (uidTimesMs[i][idx] * 1000 * WAKE_LOCK_WEIGHT) / 100;
783                     expectedWakeLockUidTimesUs[cluster][speed] += expectedTimeUs;
784                     assertEquals("Unexpected time for uid= " + testUids[i]
785                                     + " at cluster=" + cluster + ", speed=" + speed,
786                             expectedTimeUs,
787                             u.getTimeAtCpuSpeed(cluster, speed, STATS_SINCE_CHARGED));
788                     idx++;
789                 }
790             }
791         }
792         for (int i = 0; i < partialTimerUids.length; ++i) {
793             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(partialTimerUids[i]);
794             assertNotNull("No entry for partial timer uid=" + partialTimerUids[i], u);
795 
796             assertNull("Unexpected cpu times for partial timer uid=" + partialTimerUids[i],
797                     u.getCpuFreqTimes(STATS_SINCE_CHARGED));
798             assertNull("Unexpected screen-off cpu times for partial timer uid="
799                             + partialTimerUids[i],
800                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
801 
802             for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
803                 for (int speed = 0; speed < clusterFreqs[cluster]; ++speed) {
804                     final long expectedTimeUs = expectedWakeLockUidTimesUs[cluster][speed]
805                             / (partialTimerUids.length - i);
806                     assertEquals("Unexpected time for partial timer uid= " + partialTimerUids[i]
807                                     + " at cluster=" + cluster + ", speed=" + speed,
808                             expectedTimeUs,
809                             u.getTimeAtCpuSpeed(cluster, speed, STATS_SINCE_CHARGED));
810                     expectedWakeLockUidTimesUs[cluster][speed] -= expectedTimeUs;
811                 }
812             }
813         }
814         for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
815             for (int speed = 0; speed < clusterFreqs[cluster]; ++speed) {
816                 assertEquals("There shouldn't be any left-overs: "
817                                 + Arrays.deepToString(expectedWakeLockUidTimesUs),
818                         0, expectedWakeLockUidTimesUs[cluster][speed]);
819             }
820         }
821     }
822 
823     @Test
testReadKernelUidCpuFreqTimesLocked_freqsChanged()824     public void testReadKernelUidCpuFreqTimesLocked_freqsChanged() {
825         // PRECONDITIONS
826         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
827 
828         final int testUserId = 11;
829         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
830         final int[] testUids = getUids(testUserId, new int[]{
831                 FIRST_APPLICATION_UID + 22,
832                 FIRST_APPLICATION_UID + 27,
833                 FIRST_APPLICATION_UID + 33
834         });
835         final long[][] uidTimesMs = {
836                 {4, 10, 5, 9, 4},
837                 {5, 1, 12, 2, 10},
838                 {8, 25, 3, 0, 42}
839         };
840         doAnswer(invocation -> {
841             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
842                     invocation.getArgument(1);
843             for (int i = 0; i < testUids.length; ++i) {
844                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
845             }
846             return null;
847         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
848                 any(KernelCpuUidFreqTimeReader.Callback.class));
849 
850         // RUN
851         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
852 
853         // VERIFY
854         for (int i = 0; i < testUids.length; ++i) {
855             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
856             assertNotNull("No entry for uid=" + testUids[i], u);
857 
858             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
859                     uidTimesMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
860             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
861                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
862         }
863 
864         // Repeat the test with the freqs from proc file changed.
865 
866         // PRECONDITIONS
867         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
868         final long[][] deltasMs = {
869                 {3, 12, 55, 100, 32, 34984, 27983},
870                 {3248327490475L, 232349349845043L, 123, 2398, 0, 398, 0},
871                 {43, 3345, 2143, 123, 4554, 9374983794839L, 979875}
872         };
873         doAnswer(invocation -> {
874             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
875                     invocation.getArgument(1);
876             for (int i = 0; i < testUids.length; ++i) {
877                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
878             }
879             return null;
880         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
881                 any(KernelCpuUidFreqTimeReader.Callback.class));
882 
883         // RUN
884         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null);
885 
886         // VERIFY
887         for (int i = 0; i < testUids.length; ++i) {
888             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
889             assertNotNull("No entry for uid=" + testUids[i], u);
890 
891             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
892                     deltasMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
893             assertArrayEquals("Unexpected screen-off cpu times for uid=" + testUids[i],
894                     deltasMs[i], u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
895         }
896     }
897 
898     @Test
testReadKernelUidCpuFreqTimesLocked_isolatedUid()899     public void testReadKernelUidCpuFreqTimesLocked_isolatedUid() {
900         // PRECONDITIONS
901         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
902 
903         final int testUserId = 11;
904         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
905         final int isolatedAppId = FIRST_ISOLATED_UID + 27;
906         final int isolatedUid = UserHandle.getUid(testUserId, isolatedAppId);
907         final int[] testUids = getUids(testUserId, new int[]{
908                 FIRST_APPLICATION_UID + 22,
909                 isolatedAppId,
910                 FIRST_APPLICATION_UID + 33
911         });
912         final long[][] uidTimesMs = {
913                 {4, 10, 5, 9, 4},
914                 {5, 1, 12, 2, 10},
915                 {8, 25, 3, 0, 42}
916         };
917         doAnswer(invocation -> {
918             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
919                     invocation.getArgument(1);
920             for (int i = 0; i < testUids.length; ++i) {
921                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
922             }
923             return null;
924         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
925                 any(KernelCpuUidFreqTimeReader.Callback.class));
926 
927         // RUN
928         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
929 
930         // VERIFY
931         for (int i = 0; i < testUids.length; ++i) {
932             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
933             if (UserHandle.isIsolated(testUids[i])) {
934                 assertNull("There shouldn't be an entry for isolated uid=" + testUids[i], u);
935                 continue;
936             }
937             assertNotNull("No entry for uid=" + testUids[i], u);
938 
939             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
940                     uidTimesMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
941             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
942                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
943         }
944 
945 
946         // Add an isolated uid mapping and repeat the test.
947 
948         // PRECONDITIONS
949         final int ownerUid = UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 42);
950         mBatteryStatsImpl.addIsolatedUidLocked(isolatedUid, ownerUid);
951         final long[][] deltasMs = {
952                 {3, 12, 55, 100, 32},
953                 {32483274, 232349349, 123, 2398, 0},
954                 {43, 3345, 2143, 123, 4554}
955         };
956         doAnswer(invocation -> {
957             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
958                     invocation.getArgument(1);
959             for (int i = 0; i < testUids.length; ++i) {
960                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
961             }
962             return null;
963         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
964                 any(KernelCpuUidFreqTimeReader.Callback.class));
965 
966         // RUN
967         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
968 
969         // VERIFY
970         for (int i = 0; i < testUids.length; ++i) {
971             BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
972             final long[] expectedTimes;
973             if (UserHandle.isIsolated(testUids[i])) {
974                 assertNull("There shouldn't be an entry for isolated uid=" + testUids[i], u);
975                 // Since we added a mapping, an entry should've been created for owner uid.
976                 u = mBatteryStatsImpl.getUidStats().get(ownerUid);
977                 expectedTimes = deltasMs[i];
978                 assertNotNull("No entry for owner uid=" + ownerUid, u);
979             } else {
980                 assertNotNull("No entry for uid=" + testUids[i], u);
981                 expectedTimes = sum(uidTimesMs[i], deltasMs[i]);
982             }
983 
984             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
985                     expectedTimes, u.getCpuFreqTimes(STATS_SINCE_CHARGED));
986             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
987                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
988         }
989     }
990 
991     @Test
testReadKernelUidCpuFreqTimesLocked_invalidUid()992     public void testReadKernelUidCpuFreqTimesLocked_invalidUid() {
993         // PRECONDITIONS
994         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
995 
996         final int testUserId = 11;
997         final int invalidUserId = 15;
998         final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
999         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1000         when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
1001         final int[] testUids = getUids(testUserId, new int[]{
1002                 FIRST_APPLICATION_UID + 22,
1003                 FIRST_APPLICATION_UID + 27,
1004                 FIRST_APPLICATION_UID + 33
1005         });
1006         final long[][] uidTimesMs = {
1007                 {4, 10, 5, 9, 4},
1008                 {5, 1, 12, 2, 10},
1009                 {8, 25, 3, 0, 42}
1010         };
1011         doAnswer(invocation -> {
1012             final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
1013                     invocation.getArgument(1);
1014             for (int i = 0; i < testUids.length; ++i) {
1015                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1016             }
1017             // And one for the invalid uid
1018             callback.onUidCpuTime(invalidUid, new long[]{12, 839, 32, 34, 21});
1019             return null;
1020         }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
1021                 any(KernelCpuUidFreqTimeReader.Callback.class));
1022 
1023         // RUN
1024         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null);
1025 
1026         // VERIFY
1027         for (int i = 0; i < testUids.length; ++i) {
1028             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1029             assertNotNull("No entry for uid=" + testUids[i], u);
1030 
1031             assertArrayEquals("Unexpected cpu times for uid=" + testUids[i],
1032                     uidTimesMs[i], u.getCpuFreqTimes(STATS_SINCE_CHARGED));
1033             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
1034                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
1035         }
1036         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
1037                 mBatteryStatsImpl.getUidStats().get(invalidUid));
1038     }
1039 
1040     @Test
testReadKernelUidCpuActiveTimesLocked()1041     public void testReadKernelUidCpuActiveTimesLocked() {
1042         mClocks.realtime = 1000;
1043 
1044         // PRECONDITIONS
1045         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1046 
1047         final int testUserId = 11;
1048         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1049         final int[] testUids = getUids(testUserId, new int[]{
1050                 FIRST_APPLICATION_UID + 22,
1051                 FIRST_APPLICATION_UID + 27,
1052                 FIRST_APPLICATION_UID + 33
1053         });
1054         final long[] initialTimesMs = {8000, 25000, 3000, 0, 42000};
1055         doAnswer(invocation -> {
1056             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1057                     invocation.getArgument(0);
1058             for (int i = 0; i < testUids.length; ++i) {
1059                 callback.onUidCpuTime(testUids[i], initialTimesMs[i]);
1060             }
1061             return null;
1062         }).when(mCpuUidActiveTimeReader).readAbsolute(
1063                 any(KernelCpuUidActiveTimeReader.Callback.class));
1064 
1065         // RUN
1066         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1067 
1068         // VERIFY
1069         for (int i = 0; i < testUids.length; ++i) {
1070             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1071             assertNotNull("No entry for uid=" + testUids[i], u);
1072             assertEquals("Unexpected cpu active time for uid=" + testUids[i], 0,
1073                     u.getCpuActiveTime());
1074         }
1075 
1076         // Some time passes
1077         mClocks.realtime = 2000;
1078 
1079         // PRECONDITIONS
1080         final long[] cpuTimesAt2000 = {43000, 3345000, 2143000, 123000, 4554000};
1081         doAnswer(invocation -> {
1082             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1083                     invocation.getArgument(0);
1084             for (int i = 0; i < testUids.length; ++i) {
1085                 callback.onUidCpuTime(testUids[i], cpuTimesAt2000[i]);
1086             }
1087             return null;
1088         }).when(mCpuUidActiveTimeReader).readAbsolute(
1089                 any(KernelCpuUidActiveTimeReader.Callback.class));
1090 
1091         // RUN
1092         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1093 
1094         // VERIFY
1095         for (int i = 0; i < testUids.length; ++i) {
1096             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1097             assertNotNull("No entry for uid=" + testUids[i], u);
1098             assertEquals("Unexpected cpu active time for uid=" + testUids[i],
1099                     cpuTimesAt2000[i] - initialTimesMs[i], u.getCpuActiveTime());
1100         }
1101 
1102         // Give it another second
1103         mClocks.realtime = 3000;
1104 
1105         // Repeat the test when the screen is off.
1106 
1107         // PRECONDITIONS
1108         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
1109         final long[] cpuTimesAt3000 = {63000, 7345000, 8143000, 923000, 5554000};
1110         doAnswer(invocation -> {
1111             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1112                     invocation.getArgument(0);
1113             for (int i = 0; i < testUids.length; ++i) {
1114                 callback.onUidCpuTime(testUids[i], cpuTimesAt3000[i]);
1115             }
1116             return null;
1117         }).when(mCpuUidActiveTimeReader).readAbsolute(
1118                 any(KernelCpuUidActiveTimeReader.Callback.class));
1119 
1120         // RUN
1121         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1122 
1123         // VERIFY
1124         for (int i = 0; i < testUids.length; ++i) {
1125             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1126             assertNotNull("No entry for uid=" + testUids[i], u);
1127             assertEquals("Unexpected cpu active time for uid=" + testUids[i],
1128                     cpuTimesAt3000[i] - initialTimesMs[i], u.getCpuActiveTime());
1129         }
1130     }
1131 
1132     @Test
testReadKernelUidCpuActiveTimesLocked_invalidUid()1133     public void testReadKernelUidCpuActiveTimesLocked_invalidUid() {
1134         mClocks.realtime = 1000;
1135 
1136         // PRECONDITIONS
1137         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1138 
1139         final int testUserId = 11;
1140         final int invalidUserId = 15;
1141         final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
1142         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1143         when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
1144         final int[] testUids = getUids(testUserId, new int[]{
1145                 FIRST_APPLICATION_UID + 22,
1146                 FIRST_APPLICATION_UID + 27,
1147                 FIRST_APPLICATION_UID + 33
1148         });
1149         final long[] cpuTimesAt1000 = {8000, 25000, 3000, 0, 42000};
1150         doAnswer(invocation -> {
1151             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1152                     invocation.getArgument(0);
1153             for (int i = 0; i < testUids.length; ++i) {
1154                 callback.onUidCpuTime(testUids[i], cpuTimesAt1000[i]);
1155             }
1156             // And one for the invalid uid
1157             callback.onUidCpuTime(invalidUid, 1200L);
1158             return null;
1159         }).when(mCpuUidActiveTimeReader).readAbsolute(
1160                 any(KernelCpuUidActiveTimeReader.Callback.class));
1161 
1162         // RUN
1163         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1164 
1165         // Some time passes
1166         mClocks.realtime = 2000;
1167 
1168         // Run again to compute the delta
1169         final long[] cpuTimesAt2000 = {18000, 225000, 33000, 40, 542000};
1170         doAnswer(invocation -> {
1171             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1172                     invocation.getArgument(0);
1173             for (int i = 0; i < testUids.length; ++i) {
1174                 callback.onUidCpuTime(testUids[i], cpuTimesAt2000[i]);
1175             }
1176             // And one for the invalid uid
1177             callback.onUidCpuTime(invalidUid, 1200L);
1178             return null;
1179         }).when(mCpuUidActiveTimeReader).readAbsolute(
1180                 any(KernelCpuUidActiveTimeReader.Callback.class));
1181 
1182         // RUN
1183         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1184 
1185         // VERIFY
1186         for (int i = 0; i < testUids.length; ++i) {
1187             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1188             assertNotNull("No entry for uid=" + testUids[i], u);
1189             assertEquals("Unexpected cpu active time for uid=" + testUids[i],
1190                     cpuTimesAt2000[i] - cpuTimesAt1000[i], u.getCpuActiveTime());
1191         }
1192         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
1193                 mBatteryStatsImpl.getUidStats().get(invalidUid));
1194     }
1195 
1196     @Test
testReadKernelUidCpuClusterTimesLocked()1197     public void testReadKernelUidCpuClusterTimesLocked() {
1198         // PRECONDITIONS
1199         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1200 
1201         final int testUserId = 11;
1202         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1203         final int[] testUids = getUids(testUserId, new int[]{
1204                 FIRST_APPLICATION_UID + 22,
1205                 FIRST_APPLICATION_UID + 27,
1206                 FIRST_APPLICATION_UID + 33
1207         });
1208         final long[][] uidTimesMs = {
1209                 {4000, 10000},
1210                 {5000, 1000},
1211                 {8000, 0}
1212         };
1213         doAnswer(invocation -> {
1214             final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
1215                     invocation.getArgument(1);
1216             for (int i = 0; i < testUids.length; ++i) {
1217                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1218             }
1219             return null;
1220         }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
1221                 any(KernelCpuUidClusterTimeReader.Callback.class));
1222 
1223         // RUN
1224         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
1225 
1226         // VERIFY
1227         for (int i = 0; i < testUids.length; ++i) {
1228             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1229             assertNotNull("No entry for uid=" + testUids[i], u);
1230             assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], uidTimesMs[i],
1231                     u.getCpuClusterTimes());
1232         }
1233 
1234         // Repeat the test when the screen is off.
1235 
1236         // PRECONDITIONS
1237         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
1238         final long[][] deltasMs = {
1239                 {3000, 12000},
1240                 {3248327490475L, 0},
1241                 {43000, 3345000}
1242         };
1243         doAnswer(invocation -> {
1244             final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
1245                     invocation.getArgument(1);
1246             for (int i = 0; i < testUids.length; ++i) {
1247                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
1248             }
1249             return null;
1250         }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
1251                 any(KernelCpuUidClusterTimeReader.Callback.class));
1252 
1253         // RUN
1254         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
1255 
1256         // VERIFY
1257         for (int i = 0; i < testUids.length; ++i) {
1258             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1259             assertNotNull("No entry for uid=" + testUids[i], u);
1260             assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i],
1261                     sum(uidTimesMs[i], deltasMs[i]),
1262                     u.getCpuClusterTimes());
1263         }
1264     }
1265 
1266     @Test
testReadKernelUidCpuClusterTimesLocked_invalidUid()1267     public void testReadKernelUidCpuClusterTimesLocked_invalidUid() {
1268         // PRECONDITIONS
1269         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1270 
1271         final int testUserId = 11;
1272         final int invalidUserId = 15;
1273         final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
1274         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1275         when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
1276         final int[] testUids = getUids(testUserId, new int[]{
1277                 FIRST_APPLICATION_UID + 22,
1278                 FIRST_APPLICATION_UID + 27,
1279                 FIRST_APPLICATION_UID + 33
1280         });
1281         final long[][] uidTimesMs = {
1282                 {4000, 10000},
1283                 {5000, 1000},
1284                 {8000, 0}
1285         };
1286         doAnswer(invocation -> {
1287             final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
1288                     invocation.getArgument(1);
1289             for (int i = 0; i < testUids.length; ++i) {
1290                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1291             }
1292             // And one for the invalid uid
1293             callback.onUidCpuTime(invalidUid, new long[]{400, 1000});
1294             return null;
1295         }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
1296                 any(KernelCpuUidClusterTimeReader.Callback.class));
1297 
1298         // RUN
1299         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
1300 
1301         // VERIFY
1302         for (int i = 0; i < testUids.length; ++i) {
1303             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1304             assertNotNull("No entry for uid=" + testUids[i], u);
1305             assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], uidTimesMs[i],
1306                     u.getCpuClusterTimes());
1307         }
1308         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
1309                 mBatteryStatsImpl.getUidStats().get(invalidUid));
1310     }
1311 
1312     @Test
testRemoveUidCpuTimes()1313     public void testRemoveUidCpuTimes() {
1314         mClocks.realtime = mClocks.uptime = 0;
1315         mBatteryStatsImpl.getPendingRemovedUids().add(
1316                 mBatteryStatsImpl.new UidToRemove(1, mClocks.elapsedRealtime()));
1317         mBatteryStatsImpl.getPendingRemovedUids().add(
1318                 mBatteryStatsImpl.new UidToRemove(5, 10, mClocks.elapsedRealtime()));
1319         mBatteryStatsImpl.clearPendingRemovedUidsLocked();
1320         assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
1321 
1322         mClocks.realtime = mClocks.uptime = 100_000;
1323         mBatteryStatsImpl.clearPendingRemovedUidsLocked();
1324         assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
1325 
1326         mClocks.realtime = mClocks.uptime = 200_000;
1327         mBatteryStatsImpl.getPendingRemovedUids().add(
1328                 mBatteryStatsImpl.new UidToRemove(100, mClocks.elapsedRealtime()));
1329         mBatteryStatsImpl.clearPendingRemovedUidsLocked();
1330         assertEquals(3, mBatteryStatsImpl.getPendingRemovedUids().size());
1331 
1332         mClocks.realtime = mClocks.uptime = 400_000;
1333         mBatteryStatsImpl.clearPendingRemovedUidsLocked();
1334         assertEquals(1, mBatteryStatsImpl.getPendingRemovedUids().size());
1335         verify(mCpuUidActiveTimeReader).removeUid(1);
1336         verify(mCpuUidActiveTimeReader).removeUidsInRange(5, 10);
1337         verify(mCpuUidClusterTimeReader).removeUid(1);
1338         verify(mCpuUidClusterTimeReader).removeUidsInRange(5, 10);
1339         verify(mCpuUidFreqTimeReader).removeUid(1);
1340         verify(mCpuUidFreqTimeReader).removeUidsInRange(5, 10);
1341         verify(mCpuUidUserSysTimeReader).removeUid(1);
1342         verify(mCpuUidUserSysTimeReader).removeUidsInRange(5, 10);
1343 
1344         mClocks.realtime = mClocks.uptime = 800_000;
1345         mBatteryStatsImpl.clearPendingRemovedUidsLocked();
1346         assertEquals(0, mBatteryStatsImpl.getPendingRemovedUids().size());
1347         verify(mCpuUidActiveTimeReader).removeUid(100);
1348         verify(mCpuUidClusterTimeReader).removeUid(100);
1349         verify(mCpuUidFreqTimeReader).removeUid(100);
1350         verify(mCpuUidUserSysTimeReader).removeUid(100);
1351 
1352         verifyNoMoreInteractions(mCpuUidActiveTimeReader, mCpuUidClusterTimeReader,
1353                 mCpuUidFreqTimeReader, mCpuUidUserSysTimeReader);
1354     }
1355 
updateTimeBasesLocked(boolean unplugged, int screenState, long upTime, long realTime)1356     private void updateTimeBasesLocked(boolean unplugged, int screenState,
1357             long upTime, long realTime) {
1358         // Set PowerProfile=null before calling updateTimeBasesLocked to avoid execution of
1359         // BatteryStatsImpl.updateCpuTimeLocked
1360         mBatteryStatsImpl.setPowerProfile(null);
1361         mBatteryStatsImpl.updateTimeBasesLocked(unplugged, screenState, upTime, realTime);
1362         mBatteryStatsImpl.setPowerProfile(mPowerProfile);
1363     }
1364 
initKernelCpuSpeedReaders(int count)1365     private void initKernelCpuSpeedReaders(int count) {
1366         mKernelCpuSpeedReaders = new KernelCpuSpeedReader[count];
1367         for (int i = 0; i < count; ++i) {
1368             mKernelCpuSpeedReaders[i] = Mockito.mock(KernelCpuSpeedReader.class);
1369         }
1370         mBatteryStatsImpl.setKernelCpuSpeedReaders(mKernelCpuSpeedReaders);
1371     }
1372 
getPartialTimers(int... uids)1373     private ArrayList<BatteryStatsImpl.StopwatchTimer> getPartialTimers(int... uids) {
1374         final ArrayList<BatteryStatsImpl.StopwatchTimer> partialTimers = new ArrayList<>();
1375         final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
1376         for (int uid : uids) {
1377             final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uid);
1378             final BatteryStatsImpl.StopwatchTimer timer = new BatteryStatsImpl.StopwatchTimer(
1379                     mClocks, u, WAKE_TYPE_PARTIAL, null, timeBase);
1380             partialTimers.add(timer);
1381         }
1382         return partialTimers;
1383     }
1384 
sum(long[] a, long[] b)1385     private long[] sum(long[] a, long[] b) {
1386         assertEquals("Arrays a: " + Arrays.toString(a) + ", b: " + Arrays.toString(b),
1387                 a.length, b.length);
1388         final long[] result = new long[a.length];
1389         for (int i = 0; i < a.length; ++i) {
1390             result[i] = a[i] + b[i];
1391         }
1392         return result;
1393     }
1394 
getUids(int userId, int[] appIds)1395     private int[] getUids(int userId, int[] appIds) {
1396         final int[] uids = new int[appIds.length];
1397         for (int i = appIds.length - 1; i >= 0; --i) {
1398             uids[i] = UserHandle.getUid(userId, appIds[i]);
1399         }
1400         return uids;
1401     }
1402 }
1403