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