1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.cpu; 18 19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 20 21 import static com.android.server.cpu.CpuInfoReader.CpuInfo.MISSING_FREQUENCY; 22 import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND; 23 import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP; 24 25 import static com.google.common.truth.Truth.assertWithMessage; 26 27 import android.content.Context; 28 import android.content.res.AssetManager; 29 import android.util.Log; 30 import android.util.SparseArray; 31 32 import com.android.server.ExpectableTestCase; 33 34 import libcore.io.Streams; 35 36 import org.junit.After; 37 import org.junit.Before; 38 import org.junit.Test; 39 40 import java.io.File; 41 import java.io.FileOutputStream; 42 import java.io.InputStream; 43 import java.io.OutputStream; 44 import java.util.Objects; 45 46 /** This class contains unit tests for the {@link CpuInfoReader}. */ 47 public final class CpuInfoReaderTest extends ExpectableTestCase { 48 private static final String TAG = CpuInfoReaderTest.class.getSimpleName(); 49 private static final String ROOT_DIR_NAME = "CpuInfoReaderTest"; 50 private static final String VALID_CPUSET_DIR = "valid_cpuset"; 51 private static final String VALID_CPUSET_WITH_EMPTY_CPUS = "valid_cpuset_with_empty_cpus"; 52 private static final String VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS = 53 "valid_cpufreq_with_empty_affected_cpus"; 54 private static final String VALID_CPUFREQ_WITH_EMPTY_RELATED_CPUS = 55 "valid_cpufreq_with_empty_related_cpus"; 56 private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR = 57 "valid_cpufreq_with_time_in_state"; 58 private static final String VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR = 59 "valid_cpufreq_with_time_in_state_2"; 60 private static final String VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_DIR = 61 "valid_cpufreq_without_time_in_state"; 62 private static final String VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_2_DIR = 63 "valid_cpufreq_without_time_in_state_2"; 64 private static final String VALID_PROC_STAT = "valid_proc_stat"; 65 private static final String VALID_PROC_STAT_2 = "valid_proc_stat_2"; 66 private static final String CORRUPTED_CPUFREQ_DIR = "corrupted_cpufreq"; 67 private static final String CORRUPTED_CPUSET_DIR = "corrupted_cpuset"; 68 private static final String CORRUPTED_PROC_STAT = "corrupted_proc_stat"; 69 private static final String EMPTY_DIR = "empty_dir"; 70 private static final String EMPTY_FILE = "empty_file"; 71 72 private final Context mContext = getInstrumentation().getTargetContext(); 73 private final File mCacheRoot = new File(mContext.getCacheDir(), ROOT_DIR_NAME); 74 private final AssetManager mAssetManager = mContext.getAssets(); 75 76 @Before setUp()77 public void setUp() throws Exception { 78 copyAssets(ROOT_DIR_NAME, mContext.getCacheDir()); 79 assertWithMessage("Cache root dir %s exists", mCacheRoot.getAbsolutePath()) 80 .that(mCacheRoot.exists()).isTrue(); 81 } 82 83 @After tearDown()84 public void tearDown() throws Exception { 85 if (!deleteDirectory(mCacheRoot)) { 86 Log.e(TAG, "Failed to delete cache root directory " + mCacheRoot.getAbsolutePath()); 87 } 88 } 89 90 @Test testReadCpuInfoWithTimeInState()91 public void testReadCpuInfoWithTimeInState() throws Exception { 92 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 93 getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT)); 94 95 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 96 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 97 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 98 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, 99 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095, 100 /* normalizedAvailableCpuFreqKHz= */ 2_402_267, 101 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, 102 /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, 103 /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, 104 /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970, 105 /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0, 106 /* guestNiceTimeMillis= */ 0))); 107 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 108 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 109 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, 110 /* normalizedAvailableCpuFreqKHz= */ 2_693_525, 111 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 112 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 113 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 114 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 115 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 116 /* guestNiceTimeMillis= */ 0))); 117 expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, 118 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 119 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 120 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, 121 /* normalizedAvailableCpuFreqKHz= */ 1_901_608, 122 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280, 123 /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020, 124 /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960, 125 /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130, 126 /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0, 127 /* guestNiceTimeMillis= */ 0))); 128 expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, 129 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 130 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 131 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, 132 /* normalizedAvailableCpuFreqKHz= */ 1_907_125, 133 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610, 134 /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050, 135 /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810, 136 /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970, 137 /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0, 138 /* guestNiceTimeMillis= */ 0))); 139 140 compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos); 141 142 cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR)); 143 cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2)); 144 145 actualCpuInfos = cpuInfoReader.readCpuInfos(); 146 147 expectedCpuInfos.clear(); 148 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 149 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 150 /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354, 151 /* normalizedAvailableCpuFreqKHz= */ 2_525_919, 152 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, 153 /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, 154 /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000, 155 /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000, 156 /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0, 157 /* guestNiceTimeMillis= */ 0))); 158 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 159 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000, 160 /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032, 161 /* normalizedAvailableCpuFreqKHz= */ 2_503_009, 162 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000, 163 /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, 164 /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000, 165 /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000, 166 /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0, 167 /* guestNiceTimeMillis= */ 0))); 168 expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, 169 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 170 /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000, 171 /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225, 172 /* normalizedAvailableCpuFreqKHz= */ 1_788_209, 173 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, 174 /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0, 175 /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000, 176 /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000, 177 /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0, 178 /* guestNiceTimeMillis= */ 0))); 179 expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, 180 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 181 /* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY, 182 /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 183 /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY, 184 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000, 185 /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000, 186 /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000, 187 /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000, 188 /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0, 189 /* guestNiceTimeMillis= */ 0))); 190 191 compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos); 192 } 193 194 @Test testReadCpuInfoWithoutTimeInState()195 public void testReadCpuInfoWithoutTimeInState() throws Exception { 196 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 197 getCacheFile(VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_DIR), 198 getCacheFile(VALID_PROC_STAT)); 199 200 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 201 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 202 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 203 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, 204 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 205 /* normalizedAvailableCpuFreqKHz= */ 2_253_713, 206 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, 207 /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, 208 /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, 209 /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970, 210 /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0, 211 /* guestNiceTimeMillis= */ 0))); 212 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 213 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 214 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 215 /* normalizedAvailableCpuFreqKHz= */ 2_492_687, 216 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 217 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 218 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 219 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 220 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 221 /* guestNiceTimeMillis= */ 0))); 222 expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, 223 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 224 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 225 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 226 /* normalizedAvailableCpuFreqKHz= */ 1_788_079, 227 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280, 228 /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020, 229 /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960, 230 /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130, 231 /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0, 232 /* guestNiceTimeMillis= */ 0))); 233 expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, 234 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 235 /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 236 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 237 /* normalizedAvailableCpuFreqKHz= */ 1_799_962, 238 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610, 239 /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050, 240 /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810, 241 /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970, 242 /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0, 243 /* guestNiceTimeMillis= */ 0))); 244 245 compareCpuInfos("CPU infos first snapshot without time_in_state file", expectedCpuInfos, 246 actualCpuInfos); 247 248 cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITHOUT_TIME_IN_STATE_2_DIR)); 249 cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2)); 250 251 actualCpuInfos = cpuInfoReader.readCpuInfos(); 252 253 expectedCpuInfos.clear(); 254 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 255 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 256 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 257 /* normalizedAvailableCpuFreqKHz= */ 2323347, 258 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, 259 /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, 260 /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000, 261 /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000, 262 /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0, 263 /* guestNiceTimeMillis= */ 0))); 264 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 265 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000, 266 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 267 /* normalizedAvailableCpuFreqKHz= */ 209111, 268 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000, 269 /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000, 270 /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000, 271 /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000, 272 /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0, 273 /* guestNiceTimeMillis= */ 0))); 274 expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, 275 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 276 /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000, 277 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 278 /* normalizedAvailableCpuFreqKHz= */ 453514, 279 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000, 280 /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0, 281 /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000, 282 /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000, 283 /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0, 284 /* guestNiceTimeMillis= */ 0))); 285 expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, 286 FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND, 287 /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000, 288 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY, 289 /* normalizedAvailableCpuFreqKHz= */ 37728, 290 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000, 291 /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000, 292 /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000, 293 /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000, 294 /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0, 295 /* guestNiceTimeMillis= */ 0))); 296 297 compareCpuInfos("CPU infos second snapshot without time_in_state file", expectedCpuInfos, 298 actualCpuInfos); 299 } 300 301 @Test testReadCpuInfoWithCorruptedCpuset()302 public void testReadCpuInfoWithCorruptedCpuset() throws Exception { 303 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(CORRUPTED_CPUSET_DIR), 304 getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), 305 getCacheFile(VALID_PROC_STAT)); 306 307 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 308 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 309 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 310 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, 311 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095, 312 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, 313 /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, 314 /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, 315 /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970, 316 /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0, 317 /* guestNiceTimeMillis= */ 0))); 318 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 319 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 320 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, 321 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 322 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 323 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 324 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 325 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 326 /* guestNiceTimeMillis= */ 0))); 327 expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, 328 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 329 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, 330 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280, 331 /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020, 332 /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960, 333 /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130, 334 /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0, 335 /* guestNiceTimeMillis= */ 0))); 336 337 compareCpuInfos("CPU infos with corrupted cpuset", expectedCpuInfos, actualCpuInfos); 338 } 339 340 @Test testReadCpuInfoWithCorruptedCpufreq()341 public void testReadCpuInfoWithCorruptedCpufreq() throws Exception { 342 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 343 getCacheFile(CORRUPTED_CPUFREQ_DIR), getCacheFile(VALID_PROC_STAT)); 344 345 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 346 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 347 348 compareCpuInfos("CPU infos with corrupted CPU frequency", expectedCpuInfos, actualCpuInfos); 349 } 350 351 @Test testReadCpuInfoWithCorruptedProcStat()352 public void testReadCpuInfoWithCorruptedProcStat() throws Exception { 353 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 354 getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), 355 getCacheFile(CORRUPTED_PROC_STAT)); 356 357 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 358 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 359 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 360 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, 361 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095, 362 /* normalizedAvailableCpuFreqKHz= */ 2_402_267, 363 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, 364 /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, 365 /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, 366 /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970, 367 /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0, 368 /* guestNiceTimeMillis= */ 0))); 369 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 370 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 371 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, 372 /* normalizedAvailableCpuFreqKHz= */ 2_693_525, 373 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 374 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 375 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 376 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 377 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 378 /* guestNiceTimeMillis= */ 0))); 379 380 compareCpuInfos("CPU infos with corrupted proc stat", expectedCpuInfos, actualCpuInfos); 381 } 382 383 @Test testReadCpuInfoWithEmptyCpuset()384 public void testReadCpuInfoWithEmptyCpuset() throws Exception { 385 File emptyDir = getCacheFile(EMPTY_DIR); 386 assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue(); 387 CpuInfoReader cpuInfoReader = new CpuInfoReader(emptyDir, getCacheFile( 388 VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), 389 getCacheFile(VALID_PROC_STAT), /* minReadIntervalMillis= */0); 390 391 assertWithMessage("Init CPU reader info").that(cpuInfoReader.init()).isFalse(); 392 393 assertWithMessage("Cpu infos with empty cpuset").that(cpuInfoReader.readCpuInfos()) 394 .isNull(); 395 } 396 397 @Test testReadCpuInfoWithEmptyCpufreq()398 public void testReadCpuInfoWithEmptyCpufreq() throws Exception { 399 File emptyDir = getCacheFile(EMPTY_DIR); 400 assertWithMessage("Make empty dir %s", emptyDir).that(emptyDir.mkdir()).isTrue(); 401 CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), emptyDir, 402 getCacheFile(VALID_PROC_STAT), /* minReadIntervalMillis= */0); 403 404 assertWithMessage("Init CPU reader info").that(cpuInfoReader.init()).isFalse(); 405 406 assertWithMessage("Cpu infos with empty CPU frequency").that(cpuInfoReader.readCpuInfos()) 407 .isNull(); 408 } 409 410 @Test testReadCpuInfoWithEmptyRelatedCpus()411 public void testReadCpuInfoWithEmptyRelatedCpus() throws Exception { 412 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 413 getCacheFile(VALID_CPUFREQ_WITH_EMPTY_RELATED_CPUS), 414 getCacheFile(VALID_PROC_STAT)); 415 416 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 417 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 418 419 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 420 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 421 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, 422 /* normalizedAvailableCpuFreqKHz= */ 2_693_525, 423 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 424 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 425 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 426 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 427 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 428 /* guestNiceTimeMillis= */ 0))); 429 430 compareCpuInfos("CPU infos with policy 0 containing an empty related_cpus file", 431 expectedCpuInfos, actualCpuInfos); 432 } 433 434 @Test testReadCpuInfoWithEmptyCpusetCpus()435 public void testReadCpuInfoWithEmptyCpusetCpus() throws Exception { 436 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_WITH_EMPTY_CPUS), 437 getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), 438 getCacheFile(VALID_PROC_STAT)); 439 440 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 441 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 442 expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, 443 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000, 444 /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095, 445 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610, 446 /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050, 447 /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810, 448 /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970, 449 /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0, 450 /* guestNiceTimeMillis= */ 0))); 451 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 452 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 453 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, 454 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 455 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 456 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 457 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 458 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 459 /* guestNiceTimeMillis= */ 0))); 460 expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, 461 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 462 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, 463 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280, 464 /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020, 465 /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960, 466 /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130, 467 /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0, 468 /* guestNiceTimeMillis= */ 0))); 469 expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, 470 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000, 471 /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285, 472 /* normalizedAvailableCpuFreqKHz= */ 1_907_125, 473 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610, 474 /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050, 475 /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810, 476 /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970, 477 /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0, 478 /* guestNiceTimeMillis= */ 0))); 479 480 compareCpuInfos("CPU infos with empty background cpu set", expectedCpuInfos, 481 actualCpuInfos); 482 } 483 484 @Test testReadCpuInfoWithEmptyAffectedCpus()485 public void testReadCpuInfoWithEmptyAffectedCpus() throws Exception { 486 CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 487 getCacheFile(VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS), 488 getCacheFile(VALID_PROC_STAT)); 489 490 SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos(); 491 SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>(); 492 493 expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, 494 FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000, 495 /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380, 496 /* normalizedAvailableCpuFreqKHz= */ 2_693_525, 497 new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280, 498 /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020, 499 /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960, 500 /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130, 501 /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0, 502 /* guestNiceTimeMillis= */ 0))); 503 504 compareCpuInfos("CPU infos with policy 0 containing an empty affected_cpus file", 505 expectedCpuInfos, actualCpuInfos); 506 } 507 508 @Test testReadCpuInfoWithEmptyProcStat()509 public void testReadCpuInfoWithEmptyProcStat() throws Exception { 510 File emptyFile = getCacheFile(EMPTY_FILE); 511 assertWithMessage("Create empty file %s", emptyFile).that(emptyFile.createNewFile()) 512 .isTrue(); 513 CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 514 getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(EMPTY_FILE), 515 /* minReadIntervalMillis= */0); 516 517 assertWithMessage("Cpu infos with empty proc stat").that(cpuInfoReader.readCpuInfos()) 518 .isNull(); 519 } 520 521 @Test testReadingTooFrequentlyReturnsLastReadCpuInfos()522 public void testReadingTooFrequentlyReturnsLastReadCpuInfos() throws Exception { 523 CpuInfoReader cpuInfoReader = new CpuInfoReader(getCacheFile(VALID_CPUSET_DIR), 524 getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT), 525 /* minReadIntervalMillis= */ 60_000); 526 assertWithMessage("Initialize CPU info reader").that(cpuInfoReader.init()).isTrue(); 527 528 SparseArray<CpuInfoReader.CpuInfo> firstCpuInfos = cpuInfoReader.readCpuInfos(); 529 assertWithMessage("CPU infos first snapshot").that(firstCpuInfos).isNotNull(); 530 assertWithMessage("CPU infos first snapshot size").that(firstCpuInfos.size()) 531 .isGreaterThan(0); 532 533 SparseArray<CpuInfoReader.CpuInfo> secondCpuInfos = cpuInfoReader.readCpuInfos(); 534 compareCpuInfos("CPU infos second snapshot", firstCpuInfos, secondCpuInfos); 535 536 SparseArray<CpuInfoReader.CpuInfo> thirdCpuInfos = cpuInfoReader.readCpuInfos(); 537 compareCpuInfos("CPU infos third snapshot", firstCpuInfos, thirdCpuInfos); 538 } 539 compareCpuInfos(String message, SparseArray<CpuInfoReader.CpuInfo> expected, SparseArray<CpuInfoReader.CpuInfo> actual)540 private void compareCpuInfos(String message, 541 SparseArray<CpuInfoReader.CpuInfo> expected, 542 SparseArray<CpuInfoReader.CpuInfo> actual) { 543 assertWithMessage("%s. Total CPU infos", message).that(actual.size()) 544 .isEqualTo(expected.size()); 545 for (int i = 0; i < expected.size(); i++) { 546 int cpuCoreId = expected.keyAt(i); 547 CpuInfoReader.CpuInfo expectedCpuInfo = expected.valueAt(i); 548 CpuInfoReader.CpuInfo actualCpuInfo = actual.get(cpuCoreId); 549 expectWithMessage("%s. Core %s's CPU info", message, cpuCoreId).that(actualCpuInfo) 550 .isEqualTo(expectedCpuInfo); 551 } 552 } 553 getCacheFile(String assetName)554 private File getCacheFile(String assetName) { 555 return new File(mCacheRoot, assetName); 556 } 557 copyAssets(String assetPath, File targetRoot)558 private void copyAssets(String assetPath, File targetRoot) throws Exception { 559 File target = new File(targetRoot, assetPath); 560 String[] assets = mAssetManager.list(assetPath); 561 if (assets == null || assets.length == 0) { 562 try (InputStream in = mAssetManager.open(assetPath); 563 OutputStream out = new FileOutputStream(target)) { 564 Streams.copy(in, out); 565 } 566 return; 567 } 568 assertWithMessage("Make target directory %s", target).that(target.mkdir()).isTrue(); 569 for (String assetName : assets) { 570 copyAssets(String.format("%s%s%s", assetPath, File.separator, assetName), targetRoot); 571 } 572 } 573 newCpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile)574 private static CpuInfoReader newCpuInfoReader(File cpusetDir, File cpuFreqDir, 575 File procStatFile) { 576 CpuInfoReader cpuInfoReader = new CpuInfoReader(cpusetDir, cpuFreqDir, procStatFile, 577 /* minReadIntervalMillis= */ 0); 578 assertWithMessage("Initialize CPU info reader").that(cpuInfoReader.init()).isTrue(); 579 return cpuInfoReader; 580 } 581 deleteDirectory(File rootDir)582 private static boolean deleteDirectory(File rootDir) { 583 if (!rootDir.exists() || !rootDir.isDirectory()) { 584 return false; 585 } 586 for (File file : Objects.requireNonNull(rootDir.listFiles())) { 587 if (file.isDirectory()) { 588 deleteDirectory(file); 589 } else if (!file.delete()) { 590 return false; 591 } 592 } 593 return rootDir.delete(); 594 } 595 } 596