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 MockClocks 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 MockClocks();
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).readDelta(anyBoolean(),
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         // PRECONDITIONS
1043         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1044 
1045         final int testUserId = 11;
1046         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1047         final int[] testUids = getUids(testUserId, new int[]{
1048                 FIRST_APPLICATION_UID + 22,
1049                 FIRST_APPLICATION_UID + 27,
1050                 FIRST_APPLICATION_UID + 33
1051         });
1052         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
1053         doAnswer(invocation -> {
1054             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1055                     invocation.getArgument(1);
1056             for (int i = 0; i < testUids.length; ++i) {
1057                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1058             }
1059             return null;
1060         }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
1061                 any(KernelCpuUidActiveTimeReader.Callback.class));
1062 
1063         // RUN
1064         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1065 
1066         // VERIFY
1067         for (int i = 0; i < testUids.length; ++i) {
1068             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1069             assertNotNull("No entry for uid=" + testUids[i], u);
1070             assertEquals("Unexpected cpu active time for uid=" + testUids[i], uidTimesMs[i],
1071                     u.getCpuActiveTime());
1072         }
1073 
1074         // Repeat the test when the screen is off.
1075 
1076         // PRECONDITIONS
1077         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
1078         final long[] deltasMs = {43000, 3345000, 2143000, 123000, 4554000};
1079         doAnswer(invocation -> {
1080             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1081                     invocation.getArgument(1);
1082             for (int i = 0; i < testUids.length; ++i) {
1083                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
1084             }
1085             return null;
1086         }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
1087                 any(KernelCpuUidActiveTimeReader.Callback.class));
1088 
1089         // RUN
1090         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1091 
1092         // VERIFY
1093         for (int i = 0; i < testUids.length; ++i) {
1094             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1095             assertNotNull("No entry for uid=" + testUids[i], u);
1096             assertEquals("Unexpected cpu active time for uid=" + testUids[i],
1097                     uidTimesMs[i] + deltasMs[i], u.getCpuActiveTime());
1098         }
1099     }
1100 
1101     @Test
testReadKernelUidCpuActiveTimesLocked_invalidUid()1102     public void testReadKernelUidCpuActiveTimesLocked_invalidUid() {
1103         // PRECONDITIONS
1104         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1105 
1106         final int testUserId = 11;
1107         final int invalidUserId = 15;
1108         final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
1109         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1110         when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
1111         final int[] testUids = getUids(testUserId, new int[]{
1112                 FIRST_APPLICATION_UID + 22,
1113                 FIRST_APPLICATION_UID + 27,
1114                 FIRST_APPLICATION_UID + 33
1115         });
1116         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
1117         doAnswer(invocation -> {
1118             final KernelCpuUidActiveTimeReader.Callback<Long> callback =
1119                     invocation.getArgument(1);
1120             for (int i = 0; i < testUids.length; ++i) {
1121                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1122             }
1123             // And one for the invalid uid
1124             callback.onUidCpuTime(invalidUid, 1200L);
1125             return null;
1126         }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
1127                 any(KernelCpuUidActiveTimeReader.Callback.class));
1128 
1129         // RUN
1130         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
1131 
1132         // VERIFY
1133         for (int i = 0; i < testUids.length; ++i) {
1134             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1135             assertNotNull("No entry for uid=" + testUids[i], u);
1136             assertEquals("Unexpected cpu active time for uid=" + testUids[i], uidTimesMs[i],
1137                     u.getCpuActiveTime());
1138         }
1139         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
1140                 mBatteryStatsImpl.getUidStats().get(invalidUid));
1141     }
1142 
1143     @Test
testReadKernelUidCpuClusterTimesLocked()1144     public void testReadKernelUidCpuClusterTimesLocked() {
1145         // PRECONDITIONS
1146         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1147 
1148         final int testUserId = 11;
1149         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1150         final int[] testUids = getUids(testUserId, new int[]{
1151                 FIRST_APPLICATION_UID + 22,
1152                 FIRST_APPLICATION_UID + 27,
1153                 FIRST_APPLICATION_UID + 33
1154         });
1155         final long[][] uidTimesMs = {
1156                 {4000, 10000},
1157                 {5000, 1000},
1158                 {8000, 0}
1159         };
1160         doAnswer(invocation -> {
1161             final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
1162                     invocation.getArgument(1);
1163             for (int i = 0; i < testUids.length; ++i) {
1164                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1165             }
1166             return null;
1167         }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
1168                 any(KernelCpuUidClusterTimeReader.Callback.class));
1169 
1170         // RUN
1171         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
1172 
1173         // VERIFY
1174         for (int i = 0; i < testUids.length; ++i) {
1175             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1176             assertNotNull("No entry for uid=" + testUids[i], u);
1177             assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], uidTimesMs[i],
1178                     u.getCpuClusterTimes());
1179         }
1180 
1181         // Repeat the test when the screen is off.
1182 
1183         // PRECONDITIONS
1184         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
1185         final long[][] deltasMs = {
1186                 {3000, 12000},
1187                 {3248327490475L, 0},
1188                 {43000, 3345000}
1189         };
1190         doAnswer(invocation -> {
1191             final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
1192                     invocation.getArgument(1);
1193             for (int i = 0; i < testUids.length; ++i) {
1194                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
1195             }
1196             return null;
1197         }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
1198                 any(KernelCpuUidClusterTimeReader.Callback.class));
1199 
1200         // RUN
1201         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
1202 
1203         // VERIFY
1204         for (int i = 0; i < testUids.length; ++i) {
1205             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1206             assertNotNull("No entry for uid=" + testUids[i], u);
1207             assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i],
1208                     sum(uidTimesMs[i], deltasMs[i]),
1209                     u.getCpuClusterTimes());
1210         }
1211     }
1212 
1213     @Test
testReadKernelUidCpuClusterTimesLocked_invalidUid()1214     public void testReadKernelUidCpuClusterTimesLocked_invalidUid() {
1215         // PRECONDITIONS
1216         updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
1217 
1218         final int testUserId = 11;
1219         final int invalidUserId = 15;
1220         final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
1221         when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
1222         when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
1223         final int[] testUids = getUids(testUserId, new int[]{
1224                 FIRST_APPLICATION_UID + 22,
1225                 FIRST_APPLICATION_UID + 27,
1226                 FIRST_APPLICATION_UID + 33
1227         });
1228         final long[][] uidTimesMs = {
1229                 {4000, 10000},
1230                 {5000, 1000},
1231                 {8000, 0}
1232         };
1233         doAnswer(invocation -> {
1234             final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
1235                     invocation.getArgument(1);
1236             for (int i = 0; i < testUids.length; ++i) {
1237                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
1238             }
1239             // And one for the invalid uid
1240             callback.onUidCpuTime(invalidUid, new long[]{400, 1000});
1241             return null;
1242         }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
1243                 any(KernelCpuUidClusterTimeReader.Callback.class));
1244 
1245         // RUN
1246         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null);
1247 
1248         // VERIFY
1249         for (int i = 0; i < testUids.length; ++i) {
1250             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
1251             assertNotNull("No entry for uid=" + testUids[i], u);
1252             assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], uidTimesMs[i],
1253                     u.getCpuClusterTimes());
1254         }
1255         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
1256                 mBatteryStatsImpl.getUidStats().get(invalidUid));
1257     }
1258 
1259     @Test
testRemoveUidCpuTimes()1260     public void testRemoveUidCpuTimes() {
1261         mClocks.realtime = mClocks.uptime = 0;
1262         mBatteryStatsImpl.getPendingRemovedUids().add(
1263                 mBatteryStatsImpl.new UidToRemove(1, mClocks.elapsedRealtime()));
1264         mBatteryStatsImpl.getPendingRemovedUids().add(
1265                 mBatteryStatsImpl.new UidToRemove(5, 10, mClocks.elapsedRealtime()));
1266         mBatteryStatsImpl.clearPendingRemovedUids();
1267         assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
1268 
1269         mClocks.realtime = mClocks.uptime = 100_000;
1270         mBatteryStatsImpl.clearPendingRemovedUids();
1271         assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
1272 
1273         mClocks.realtime = mClocks.uptime = 200_000;
1274         mBatteryStatsImpl.getPendingRemovedUids().add(
1275                 mBatteryStatsImpl.new UidToRemove(100, mClocks.elapsedRealtime()));
1276         mBatteryStatsImpl.clearPendingRemovedUids();
1277         assertEquals(3, mBatteryStatsImpl.getPendingRemovedUids().size());
1278 
1279         mClocks.realtime = mClocks.uptime = 400_000;
1280         mBatteryStatsImpl.clearPendingRemovedUids();
1281         assertEquals(1, mBatteryStatsImpl.getPendingRemovedUids().size());
1282         verify(mCpuUidActiveTimeReader).removeUid(1);
1283         verify(mCpuUidActiveTimeReader).removeUidsInRange(5, 10);
1284         verify(mCpuUidClusterTimeReader).removeUid(1);
1285         verify(mCpuUidClusterTimeReader).removeUidsInRange(5, 10);
1286         verify(mCpuUidFreqTimeReader).removeUid(1);
1287         verify(mCpuUidFreqTimeReader).removeUidsInRange(5, 10);
1288         verify(mCpuUidUserSysTimeReader).removeUid(1);
1289         verify(mCpuUidUserSysTimeReader).removeUidsInRange(5, 10);
1290 
1291         mClocks.realtime = mClocks.uptime = 800_000;
1292         mBatteryStatsImpl.clearPendingRemovedUids();
1293         assertEquals(0, mBatteryStatsImpl.getPendingRemovedUids().size());
1294         verify(mCpuUidActiveTimeReader).removeUid(100);
1295         verify(mCpuUidClusterTimeReader).removeUid(100);
1296         verify(mCpuUidFreqTimeReader).removeUid(100);
1297         verify(mCpuUidUserSysTimeReader).removeUid(100);
1298 
1299         verifyNoMoreInteractions(mCpuUidActiveTimeReader, mCpuUidClusterTimeReader,
1300                 mCpuUidFreqTimeReader, mCpuUidUserSysTimeReader);
1301     }
1302 
updateTimeBasesLocked(boolean unplugged, int screenState, long upTime, long realTime)1303     private void updateTimeBasesLocked(boolean unplugged, int screenState,
1304             long upTime, long realTime) {
1305         // Set PowerProfile=null before calling updateTimeBasesLocked to avoid execution of
1306         // BatteryStatsImpl.updateCpuTimeLocked
1307         mBatteryStatsImpl.setPowerProfile(null);
1308         mBatteryStatsImpl.updateTimeBasesLocked(unplugged, screenState, upTime, realTime);
1309         mBatteryStatsImpl.setPowerProfile(mPowerProfile);
1310     }
1311 
initKernelCpuSpeedReaders(int count)1312     private void initKernelCpuSpeedReaders(int count) {
1313         mKernelCpuSpeedReaders = new KernelCpuSpeedReader[count];
1314         for (int i = 0; i < count; ++i) {
1315             mKernelCpuSpeedReaders[i] = Mockito.mock(KernelCpuSpeedReader.class);
1316         }
1317         mBatteryStatsImpl.setKernelCpuSpeedReaders(mKernelCpuSpeedReaders);
1318     }
1319 
getPartialTimers(int... uids)1320     private ArrayList<BatteryStatsImpl.StopwatchTimer> getPartialTimers(int... uids) {
1321         final ArrayList<BatteryStatsImpl.StopwatchTimer> partialTimers = new ArrayList<>();
1322         final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
1323         for (int uid : uids) {
1324             final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uid);
1325             final BatteryStatsImpl.StopwatchTimer timer = new BatteryStatsImpl.StopwatchTimer(
1326                     mClocks, u, WAKE_TYPE_PARTIAL, null, timeBase);
1327             partialTimers.add(timer);
1328         }
1329         return partialTimers;
1330     }
1331 
sum(long[] a, long[] b)1332     private long[] sum(long[] a, long[] b) {
1333         assertEquals("Arrays a: " + Arrays.toString(a) + ", b: " + Arrays.toString(b),
1334                 a.length, b.length);
1335         final long[] result = new long[a.length];
1336         for (int i = 0; i < a.length; ++i) {
1337             result[i] = a[i] + b[i];
1338         }
1339         return result;
1340     }
1341 
getUids(int userId, int[] appIds)1342     private int[] getUids(int userId, int[] appIds) {
1343         final int[] uids = new int[appIds.length];
1344         for (int i = appIds.length - 1; i >= 0; --i) {
1345             uids[i] = UserHandle.getUid(userId, appIds[i]);
1346         }
1347         return uids;
1348     }
1349 }
1350