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