Sudheer Shanka | b2f83c1 | 2017-11-13 19:25:01 -0800 | [diff] [blame] | 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 | package com.android.internal.os; |
| 17 | |
| 18 | import static android.os.BatteryStats.STATS_SINCE_CHARGED; |
| 19 | import static android.os.BatteryStats.Uid.NUM_PROCESS_STATE; |
| 20 | import static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND; |
| 21 | import static android.os.BatteryStats.Uid.PROCESS_STATE_CACHED; |
| 22 | import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE; |
| 23 | import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; |
| 24 | |
| 25 | import static org.junit.Assert.assertArrayEquals; |
| 26 | import static org.junit.Assert.assertEquals; |
| 27 | import static org.junit.Assert.assertNull; |
| 28 | import static org.mockito.ArgumentMatchers.argThat; |
| 29 | import static org.mockito.ArgumentMatchers.eq; |
| 30 | import static org.mockito.Mockito.when; |
| 31 | |
| 32 | import android.os.BatteryStats; |
| 33 | import android.support.test.filters.LargeTest; |
| 34 | import android.support.test.runner.AndroidJUnit4; |
| 35 | import android.util.SparseArray; |
| 36 | import android.util.SparseIntArray; |
| 37 | import android.view.Display; |
| 38 | |
| 39 | import com.android.internal.util.ArrayUtils; |
| 40 | |
| 41 | import org.junit.Before; |
| 42 | import org.junit.Test; |
| 43 | import org.junit.runner.RunWith; |
| 44 | import org.mockito.ArgumentMatcher; |
| 45 | import org.mockito.Mock; |
| 46 | import org.mockito.MockitoAnnotations; |
| 47 | |
| 48 | import java.util.Arrays; |
| 49 | |
| 50 | @LargeTest |
| 51 | @RunWith(AndroidJUnit4.class) |
| 52 | public class BatteryStatsImplTest { |
| 53 | @Mock |
| 54 | private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader; |
| 55 | @Mock |
| 56 | private KernelSingleUidTimeReader mKernelSingleUidTimeReader; |
| 57 | |
| 58 | private MockBatteryStatsImpl mBatteryStatsImpl; |
| 59 | |
| 60 | @Before |
| 61 | public void setUp() { |
| 62 | MockitoAnnotations.initMocks(this); |
| 63 | |
| 64 | when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true); |
| 65 | when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true); |
| 66 | mBatteryStatsImpl = new MockBatteryStatsImpl() |
| 67 | .setKernelUidCpuFreqTimeReader(mKernelUidCpuFreqTimeReader) |
| 68 | .setKernelSingleUidTimeReader(mKernelSingleUidTimeReader); |
| 69 | } |
| 70 | |
| 71 | @Test |
| 72 | public void testUpdateProcStateCpuTimes() { |
| 73 | mBatteryStatsImpl.setOnBatteryInternal(true); |
| 74 | mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0); |
| 75 | |
| 76 | final int[] testUids = {10032, 10048, 10145, 10139}; |
| 77 | final int[] testProcStates = { |
| 78 | PROCESS_STATE_BACKGROUND, |
| 79 | PROCESS_STATE_FOREGROUND_SERVICE, |
| 80 | PROCESS_STATE_TOP, |
| 81 | PROCESS_STATE_CACHED |
| 82 | }; |
| 83 | addPendingUids(testUids, testProcStates); |
| 84 | final long[][] cpuTimes = { |
| 85 | {349734983, 394982394832l, 909834, 348934, 9838}, |
| 86 | {7498, 1239890, 988, 13298, 98980}, |
| 87 | {989834, 384098, 98483, 23809, 4984}, |
| 88 | {4859048, 348903, 4578967, 5973894, 298549} |
| 89 | }; |
| 90 | for (int i = 0; i < testUids.length; ++i) { |
| 91 | when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(cpuTimes[i]); |
| 92 | |
| 93 | // Verify there are no cpu times initially. |
| 94 | final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]); |
| 95 | for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { |
| 96 | assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 97 | assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | mBatteryStatsImpl.updateProcStateCpuTimes(); |
| 102 | |
| 103 | verifyNoPendingUids(); |
| 104 | for (int i = 0; i < testUids.length; ++i) { |
| 105 | final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); |
| 106 | for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { |
| 107 | if (procState == testProcStates[i]) { |
| 108 | assertArrayEquals("Uid=" + testUids[i], cpuTimes[i], |
| 109 | u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 110 | } else { |
| 111 | assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 112 | } |
| 113 | assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | final long[][] delta1 = { |
| 118 | {9589, 148934, 309894, 3098493, 98754}, |
| 119 | {21983, 94983, 4983, 9878493, 84854}, |
| 120 | {945894, 9089432, 19478, 3834, 7845}, |
| 121 | {843895, 43948, 949582, 99, 384} |
| 122 | }; |
| 123 | for (int i = 0; i < testUids.length; ++i) { |
| 124 | when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta1[i]); |
| 125 | } |
| 126 | addPendingUids(testUids, testProcStates); |
| 127 | |
| 128 | mBatteryStatsImpl.updateProcStateCpuTimes(); |
| 129 | |
| 130 | verifyNoPendingUids(); |
| 131 | for (int i = 0; i < testUids.length; ++i) { |
| 132 | final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); |
| 133 | for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { |
| 134 | if (procState == testProcStates[i]) { |
| 135 | long[] expectedCpuTimes = cpuTimes[i].clone(); |
| 136 | for (int j = 0; j < expectedCpuTimes.length; ++j) { |
| 137 | expectedCpuTimes[j] += delta1[i][j]; |
| 138 | } |
| 139 | assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, |
| 140 | u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 141 | } else { |
| 142 | assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 143 | } |
| 144 | assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); |
| 149 | final long[][] delta2 = { |
| 150 | {95932, 2943, 49834, 89034, 139}, |
| 151 | {349, 89605, 5896, 845, 98444}, |
| 152 | {678, 7498, 9843, 889, 4894}, |
| 153 | {488, 998, 8498, 394, 574} |
| 154 | }; |
| 155 | for (int i = 0; i < testUids.length; ++i) { |
| 156 | when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta2[i]); |
| 157 | } |
| 158 | addPendingUids(testUids, testProcStates); |
| 159 | |
| 160 | mBatteryStatsImpl.updateProcStateCpuTimes(); |
| 161 | |
| 162 | verifyNoPendingUids(); |
| 163 | for (int i = 0; i < testUids.length; ++i) { |
| 164 | final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); |
| 165 | for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { |
| 166 | if (procState == testProcStates[i]) { |
| 167 | long[] expectedCpuTimes = cpuTimes[i].clone(); |
| 168 | for (int j = 0; j < expectedCpuTimes.length; ++j) { |
| 169 | expectedCpuTimes[j] += delta1[i][j] + delta2[i][j]; |
| 170 | } |
| 171 | assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, |
| 172 | u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 173 | assertArrayEquals("Uid=" + testUids[i], delta2[i], |
| 174 | u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 175 | } else { |
| 176 | assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 177 | assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 178 | } |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | final long[][] delta3 = { |
| 183 | {98545, 95768795, 76586, 548945, 57846}, |
| 184 | {788876, 586, 578459, 8776984, 9578923}, |
| 185 | {3049509483598l, 4597834, 377654, 94589035, 7854}, |
| 186 | {9493, 784, 99895, 8974893, 9879843} |
| 187 | }; |
| 188 | for (int i = 0; i < testUids.length; ++i) { |
| 189 | when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn( |
| 190 | delta3[i].clone()); |
| 191 | } |
| 192 | addPendingUids(testUids, testProcStates); |
| 193 | final int parentUid = testUids[1]; |
| 194 | final int childUid = 99099; |
| 195 | addIsolatedUid(parentUid, childUid); |
| 196 | final long[] isolatedUidCpuTimes = {495784, 398473, 4895, 4905, 30984093}; |
| 197 | when(mKernelSingleUidTimeReader.readDeltaMs(childUid)).thenReturn(isolatedUidCpuTimes); |
| 198 | |
| 199 | mBatteryStatsImpl.updateProcStateCpuTimes(); |
| 200 | |
| 201 | verifyNoPendingUids(); |
| 202 | for (int i = 0; i < testUids.length; ++i) { |
| 203 | final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); |
| 204 | for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { |
| 205 | if (procState == testProcStates[i]) { |
| 206 | long[] expectedCpuTimes = cpuTimes[i].clone(); |
| 207 | for (int j = 0; j < expectedCpuTimes.length; ++j) { |
| 208 | expectedCpuTimes[j] += delta1[i][j] + delta2[i][j] + delta3[i][j] |
| 209 | + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0); |
| 210 | } |
| 211 | assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes, |
| 212 | u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 213 | long[] expectedScreenOffTimes = delta2[i].clone(); |
| 214 | for (int j = 0; j < expectedScreenOffTimes.length; ++j) { |
| 215 | expectedScreenOffTimes[j] += delta3[i][j] |
| 216 | + (testUids[i] == parentUid ? isolatedUidCpuTimes[j] : 0); |
| 217 | } |
| 218 | assertArrayEquals("Uid=" + testUids[i], expectedScreenOffTimes, |
| 219 | u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 220 | } else { |
| 221 | assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 222 | assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | @Test |
| 229 | public void testCopyFromAllUidsCpuTimes() { |
| 230 | mBatteryStatsImpl.setOnBatteryInternal(true); |
| 231 | mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0); |
| 232 | |
| 233 | final int[] testUids = {10032, 10048, 10145, 10139}; |
| 234 | final int[] testProcStates = { |
| 235 | PROCESS_STATE_BACKGROUND, |
| 236 | PROCESS_STATE_FOREGROUND_SERVICE, |
| 237 | PROCESS_STATE_TOP, |
| 238 | PROCESS_STATE_CACHED |
| 239 | }; |
| 240 | final int[] pendingUidIdx = {1, 2}; |
| 241 | updateProcessStates(testUids, testProcStates, pendingUidIdx); |
| 242 | |
| 243 | final SparseArray<long[]> allUidCpuTimes = new SparseArray<>(); |
| 244 | long[][] allCpuTimes = { |
| 245 | {938483, 4985984, 439893}, |
| 246 | {499, 94904, 27694}, |
| 247 | {302949085, 39789473, 34792839}, |
| 248 | {9809485, 9083475, 347889834}, |
| 249 | }; |
| 250 | for (int i = 0; i < testUids.length; ++i) { |
| 251 | allUidCpuTimes.put(testUids[i], allCpuTimes[i]); |
| 252 | } |
| 253 | when(mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs()).thenReturn(allUidCpuTimes); |
| 254 | long[][] expectedCpuTimes = { |
| 255 | {843598745, 397843, 32749, 99854}, |
| 256 | {9834, 5885, 487589, 394}, |
| 257 | {203984, 439, 9859, 30948}, |
| 258 | {9389, 858, 239, 349} |
| 259 | }; |
| 260 | for (int i = 0; i < testUids.length; ++i) { |
| 261 | final int idx = i; |
| 262 | final ArgumentMatcher<long[]> matcher = times -> Arrays.equals(times, allCpuTimes[idx]); |
| 263 | when(mKernelSingleUidTimeReader.computeDelta(eq(testUids[i]), argThat(matcher))) |
| 264 | .thenReturn(expectedCpuTimes[i]); |
| 265 | } |
| 266 | |
| 267 | mBatteryStatsImpl.copyFromAllUidsCpuTimes(); |
| 268 | |
| 269 | verifyNoPendingUids(); |
| 270 | for (int i = 0; i < testUids.length; ++i) { |
| 271 | final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]); |
| 272 | for (int procState = 0; procState < NUM_PROCESS_STATE; ++procState) { |
| 273 | if (procState == testProcStates[i]) { |
| 274 | assertArrayEquals("Uid=" + testUids[i], expectedCpuTimes[i], |
| 275 | u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 276 | } else { |
| 277 | assertNull(u.getCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 278 | } |
| 279 | assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState)); |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | @Test |
| 285 | public void testAddCpuTimes() { |
| 286 | long[] timesA = null; |
| 287 | long[] timesB = null; |
| 288 | assertNull(mBatteryStatsImpl.addCpuTimes(timesA, timesB)); |
| 289 | |
| 290 | timesA = new long[] {34, 23, 45, 24}; |
| 291 | assertArrayEquals(timesA, mBatteryStatsImpl.addCpuTimes(timesA, timesB)); |
| 292 | |
| 293 | timesB = timesA; |
| 294 | timesA = null; |
| 295 | assertArrayEquals(timesB, mBatteryStatsImpl.addCpuTimes(timesA, timesB)); |
| 296 | |
| 297 | final long[] expected = {434, 6784, 34987, 9984}; |
| 298 | timesA = new long[timesB.length]; |
| 299 | for (int i = 0; i < timesA.length; ++i) { |
| 300 | timesA[i] = expected[i] - timesB[i]; |
| 301 | } |
| 302 | assertArrayEquals(expected, mBatteryStatsImpl.addCpuTimes(timesA, timesB)); |
| 303 | } |
| 304 | |
| 305 | private void addIsolatedUid(int parentUid, int childUid) { |
| 306 | final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(parentUid); |
| 307 | u.addIsolatedUid(childUid); |
| 308 | } |
| 309 | |
| 310 | private void addPendingUids(int[] uids, int[] procStates) { |
| 311 | final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids(); |
| 312 | for (int i = 0; i < uids.length; ++i) { |
| 313 | pendingUids.put(uids[i], procStates[i]); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | private void updateProcessStates(int[] uids, int[] procStates, |
| 318 | int[] pendingUidsIdx) { |
| 319 | final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids(); |
| 320 | for (int i = 0; i < uids.length; ++i) { |
| 321 | final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uids[i]); |
| 322 | if (ArrayUtils.contains(pendingUidsIdx, i)) { |
| 323 | u.setProcessStateForTest(PROCESS_STATE_TOP); |
| 324 | pendingUids.put(uids[i], procStates[i]); |
| 325 | } else { |
| 326 | u.setProcessStateForTest(procStates[i]); |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | private void verifyNoPendingUids() { |
| 332 | final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids(); |
| 333 | assertEquals("There shouldn't be any pending uids left: " + pendingUids, |
| 334 | 0, pendingUids.size()); |
| 335 | } |
| 336 | } |