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 17package com.android.internal.os; 18 19import static org.junit.Assert.assertArrayEquals; 20import static org.junit.Assert.assertEquals; 21import static org.junit.Assert.assertFalse; 22import static org.junit.Assert.assertTrue; 23 24import android.support.test.filters.SmallTest; 25import android.support.test.runner.AndroidJUnit4; 26import android.util.SparseArray; 27 28import com.android.internal.os.KernelSingleUidTimeReader.Injector; 29 30import org.junit.Before; 31import org.junit.Test; 32import org.junit.runner.RunWith; 33 34import java.io.IOException; 35import java.nio.ByteBuffer; 36import java.nio.ByteOrder; 37import java.util.Arrays; 38 39@SmallTest 40@RunWith(AndroidJUnit4.class) 41public class KernelSingleUidTimeReaderTest { 42 private final static int TEST_UID = 2222; 43 private final static int TEST_FREQ_COUNT = 5; 44 45 private KernelSingleUidTimeReader mReader; 46 private TestInjector mInjector; 47 48 @Before 49 public void setUp() { 50 mInjector = new TestInjector(); 51 mReader = new KernelSingleUidTimeReader(TEST_FREQ_COUNT, mInjector); 52 } 53 54 @Test 55 public void readDelta() { 56 final SparseArray<long[]> allLastCpuTimes = mReader.getLastUidCpuTimeMs(); 57 long[] latestCpuTimes = new long[] {120, 130, 140, 150, 160}; 58 mInjector.setData(latestCpuTimes); 59 long[] deltaCpuTimes = mReader.readDeltaMs(TEST_UID); 60 assertCpuTimesEqual(latestCpuTimes, deltaCpuTimes); 61 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 62 63 long[] expectedDeltaTimes = new long[] {200, 340, 1230, 490, 4890}; 64 for (int i = 0; i < latestCpuTimes.length; ++i) { 65 latestCpuTimes[i] += expectedDeltaTimes[i]; 66 } 67 mInjector.setData(latestCpuTimes); 68 deltaCpuTimes = mReader.readDeltaMs(TEST_UID); 69 assertCpuTimesEqual(expectedDeltaTimes, deltaCpuTimes); 70 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 71 72 // delta should be null if cpu times haven't changed 73 deltaCpuTimes = mReader.readDeltaMs(TEST_UID); 74 assertCpuTimesEqual(null, deltaCpuTimes); 75 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 76 77 // Malformed data (-ve) 78 long[] malformedLatestTimes = new long[latestCpuTimes.length]; 79 for (int i = 0; i < latestCpuTimes.length; ++i) { 80 if (i == 1) { 81 malformedLatestTimes[i] = -4; 82 } else { 83 malformedLatestTimes[i] = latestCpuTimes[i] + i * 42; 84 } 85 } 86 mInjector.setData(malformedLatestTimes); 87 deltaCpuTimes = mReader.readDeltaMs(TEST_UID); 88 assertCpuTimesEqual(null, deltaCpuTimes); 89 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 90 91 // Malformed data (decreased) 92 malformedLatestTimes = new long[latestCpuTimes.length]; 93 for (int i = 0; i < latestCpuTimes.length; ++i) { 94 if (i == 1) { 95 malformedLatestTimes[i] = latestCpuTimes[i] - 4; 96 } else { 97 malformedLatestTimes[i] = latestCpuTimes[i] + i * 42; 98 } 99 } 100 mInjector.setData(malformedLatestTimes); 101 deltaCpuTimes = mReader.readDeltaMs(TEST_UID); 102 assertCpuTimesEqual(null, deltaCpuTimes); 103 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 104 } 105 106 @Test 107 public void readDelta_fileNotAvailable() { 108 mInjector.letReadDataThrowException(true); 109 110 for (int i = 0; i < KernelSingleUidTimeReader.TOTAL_READ_ERROR_COUNT; ++i) { 111 assertTrue(mReader.singleUidCpuTimesAvailable()); 112 mReader.readDeltaMs(TEST_UID); 113 } 114 assertFalse(mReader.singleUidCpuTimesAvailable()); 115 } 116 117 @Test 118 public void readDelta_incorrectCount() { 119 assertTrue(mReader.singleUidCpuTimesAvailable()); 120 121 long[] cpuTimes = new long[TEST_FREQ_COUNT - 1]; 122 for (int i = 0; i < cpuTimes.length; ++i) { 123 cpuTimes[i] = 111 + i; 124 } 125 mInjector.setData(cpuTimes); 126 assertCpuTimesEqual(null, mReader.readDeltaMs(TEST_UID)); 127 assertFalse(mReader.singleUidCpuTimesAvailable()); 128 129 // Reset 130 mReader.setSingleUidCpuTimesAvailable(true); 131 132 cpuTimes = new long[TEST_FREQ_COUNT + 1]; 133 for (int i = 0; i < cpuTimes.length; ++i) { 134 cpuTimes[i] = 222 + i; 135 } 136 mInjector.setData(cpuTimes); 137 assertCpuTimesEqual(null, mReader.readDeltaMs(TEST_UID)); 138 assertFalse(mReader.singleUidCpuTimesAvailable()); 139 } 140 141 @Test 142 public void testComputeDelta() { 143 // proc file not available 144 mReader.setSingleUidCpuTimesAvailable(false); 145 long[] latestCpuTimes = new long[] {12, 13, 14, 15, 16}; 146 long[] deltaCpuTimes = mReader.computeDelta(TEST_UID, latestCpuTimes); 147 assertCpuTimesEqual(null, deltaCpuTimes); 148 149 // cpu times have changed 150 mReader.setSingleUidCpuTimesAvailable(true); 151 SparseArray<long[]> allLastCpuTimes = mReader.getLastUidCpuTimeMs(); 152 long[] lastCpuTimes = new long[] {12, 13, 14, 15, 16}; 153 allLastCpuTimes.put(TEST_UID, lastCpuTimes); 154 long[] expectedDeltaTimes = new long[] {123, 324, 43, 989, 80}; 155 for (int i = 0; i < latestCpuTimes.length; ++i) { 156 latestCpuTimes[i] = lastCpuTimes[i] + expectedDeltaTimes[i]; 157 } 158 deltaCpuTimes = mReader.computeDelta(TEST_UID, latestCpuTimes); 159 assertCpuTimesEqual(expectedDeltaTimes, deltaCpuTimes); 160 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 161 162 // no change in cpu times 163 deltaCpuTimes = mReader.computeDelta(TEST_UID, latestCpuTimes); 164 assertCpuTimesEqual(null, deltaCpuTimes); 165 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 166 167 // Malformed cpu times (-ve) 168 long[] malformedLatestTimes = new long[latestCpuTimes.length]; 169 for (int i = 0; i < latestCpuTimes.length; ++i) { 170 if (i == 1) { 171 malformedLatestTimes[i] = -4; 172 } else { 173 malformedLatestTimes[i] = latestCpuTimes[i] + i * 42; 174 } 175 } 176 deltaCpuTimes = mReader.computeDelta(TEST_UID, malformedLatestTimes); 177 assertCpuTimesEqual(null, deltaCpuTimes); 178 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 179 180 // Malformed cpu times (decreased) 181 for (int i = 0; i < latestCpuTimes.length; ++i) { 182 if (i == 1) { 183 malformedLatestTimes[i] = latestCpuTimes[i] - 4; 184 } else { 185 malformedLatestTimes[i] = latestCpuTimes[i] + i * 42; 186 } 187 } 188 deltaCpuTimes = mReader.computeDelta(TEST_UID, malformedLatestTimes); 189 assertCpuTimesEqual(null, deltaCpuTimes); 190 assertCpuTimesEqual(latestCpuTimes, allLastCpuTimes.get(TEST_UID)); 191 } 192 193 @Test 194 public void testGetDelta() { 195 // No last cpu times 196 long[] lastCpuTimes = null; 197 long[] latestCpuTimes = new long[] {12, 13, 14, 15, 16}; 198 long[] deltaCpuTimes = mReader.getDeltaLocked(lastCpuTimes, latestCpuTimes); 199 assertCpuTimesEqual(latestCpuTimes, deltaCpuTimes); 200 201 // Latest cpu times are -ve 202 lastCpuTimes = new long[] {12, 13, 14, 15, 16}; 203 latestCpuTimes = new long[] {15, -10, 19, 21, 23}; 204 deltaCpuTimes = mReader.getDeltaLocked(lastCpuTimes, latestCpuTimes); 205 assertCpuTimesEqual(null, deltaCpuTimes); 206 207 // Latest cpu times are less than last cpu times 208 lastCpuTimes = new long[] {12, 13, 14, 15, 16}; 209 latestCpuTimes = new long[] {15, 11, 21, 34, 171}; 210 deltaCpuTimes = mReader.getDeltaLocked(lastCpuTimes, latestCpuTimes); 211 assertCpuTimesEqual(null, deltaCpuTimes); 212 213 lastCpuTimes = new long[] {12, 13, 14, 15, 16}; 214 latestCpuTimes = new long[] {112, 213, 314, 415, 516}; 215 deltaCpuTimes = mReader.getDeltaLocked(lastCpuTimes, latestCpuTimes); 216 assertCpuTimesEqual(new long[] {100, 200, 300, 400, 500}, deltaCpuTimes); 217 } 218 219 @Test 220 public void testRemoveUid() { 221 final SparseArray<long[]> lastUidCpuTimes = mReader.getLastUidCpuTimeMs(); 222 lastUidCpuTimes.put(12, new long[] {}); 223 lastUidCpuTimes.put(16, new long[] {}); 224 225 mReader.removeUid(12); 226 assertFalse("Removal failed, cpuTimes=" + lastUidCpuTimes, 227 lastUidCpuTimes.indexOfKey(12) >= 0); 228 mReader.removeUid(16); 229 assertFalse("Removal failed, cpuTimes=" + lastUidCpuTimes, 230 lastUidCpuTimes.indexOfKey(16) >= 0); 231 } 232 233 @Test 234 public void testRemoveUidsRange() { 235 final SparseArray<long[]> lastUidCpuTimes = mReader.getLastUidCpuTimeMs(); 236 final int startUid = 12; 237 final int endUid = 24; 238 239 for (int i = startUid; i <= endUid; ++i) { 240 lastUidCpuTimes.put(startUid, new long[] {}); 241 } 242 mReader.removeUidsInRange(startUid, endUid); 243 assertEquals("There shouldn't be any items left, cpuTimes=" + lastUidCpuTimes, 244 0, lastUidCpuTimes.size()); 245 246 for (int i = startUid; i <= endUid; ++i) { 247 lastUidCpuTimes.put(startUid, new long[] {}); 248 } 249 mReader.removeUidsInRange(startUid - 1, endUid); 250 assertEquals("There shouldn't be any items left, cpuTimes=" + lastUidCpuTimes, 251 0, lastUidCpuTimes.size()); 252 253 for (int i = startUid; i <= endUid; ++i) { 254 lastUidCpuTimes.put(startUid, new long[] {}); 255 } 256 mReader.removeUidsInRange(startUid, endUid + 1); 257 assertEquals("There shouldn't be any items left, cpuTimes=" + lastUidCpuTimes, 258 0, lastUidCpuTimes.size()); 259 260 for (int i = startUid; i <= endUid; ++i) { 261 lastUidCpuTimes.put(startUid, new long[] {}); 262 } 263 mReader.removeUidsInRange(startUid - 1, endUid + 1); 264 assertEquals("There shouldn't be any items left, cpuTimes=" + lastUidCpuTimes, 265 0, lastUidCpuTimes.size()); 266 } 267 268 private void assertCpuTimesEqual(long[] expected, long[] actual) { 269 assertArrayEquals("Expected=" + Arrays.toString(expected) 270 + ", Actual=" + Arrays.toString(actual), expected, actual); 271 } 272 273 class TestInjector extends Injector { 274 private byte[] mData; 275 private boolean mThrowExcpetion; 276 277 @Override 278 public byte[] readData(String procFile) throws IOException { 279 if (mThrowExcpetion) { 280 throw new IOException("In the test"); 281 } else { 282 return mData; 283 } 284 } 285 286 public void setData(long[] cpuTimes) { 287 final ByteBuffer buffer = ByteBuffer.allocate(cpuTimes.length * Long.BYTES); 288 buffer.order(ByteOrder.nativeOrder()); 289 for (long time : cpuTimes) { 290 buffer.putLong(time / 10); 291 } 292 mData = buffer.array(); 293 } 294 295 public void letReadDataThrowException(boolean throwException) { 296 mThrowExcpetion = throwException; 297 } 298 } 299} 300