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.car.storagemonitoring; 18 19 import android.car.storagemonitoring.IoStatsEntry; 20 import android.car.storagemonitoring.UidIoRecord; 21 import android.test.suitebuilder.annotation.MediumTest; 22 import android.util.SparseArray; 23 24 import com.android.car.procfsinspector.ProcessInfo; 25 import com.android.car.systeminterface.SystemStateInterface; 26 27 import junit.framework.TestCase; 28 29 import java.time.Duration; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.stream.Collectors; 34 35 /** 36 * Tests IoStatsTracker functionality. 37 */ 38 @MediumTest 39 public class IoStatsTrackerTest extends TestCase { 40 private static final int SAMPLE_WINDOW_MS = 1000; 41 private static final List<IoStatsEntry> EMPTY = Collections.emptyList(); 42 private static final String TAG = IoStatsTrackerTest.class.getSimpleName(); 43 testNewUsersAppear()44 public void testNewUsersAppear() throws Exception { 45 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 46 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 47 SAMPLE_WINDOW_MS, mockSystemStateInterface); 48 49 assertEquals(0, ioStatsTracker.getCurrentSample().size()); 50 assertEquals(0, ioStatsTracker.getTotal().size()); 51 52 UserActivity user0 = new UserActivity(0); 53 user0.foreground_rchar = 50; 54 user0.background_wchar = 10; 55 56 UserActivity user1 = new UserActivity(1); 57 user1.foreground_rchar = 30; 58 user1.background_wchar = 50; 59 60 UidIoRecord process0 = user0.updateSystemState(mockSystemStateInterface); 61 UidIoRecord process1 = user1.updateSystemState(mockSystemStateInterface); 62 63 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 64 65 assertEquals(2, ioStatsTracker.getCurrentSample().size()); 66 assertEquals(2, ioStatsTracker.getTotal().size()); 67 68 assertTrue(ioStatsTracker.getCurrentSample().get(0).representsSameMetrics(process0)); 69 assertTrue(ioStatsTracker.getCurrentSample().get(1).representsSameMetrics(process1)); 70 71 assertTrue(ioStatsTracker.getTotal().get(0).representsSameMetrics(process0)); 72 assertTrue(ioStatsTracker.getTotal().get(1).representsSameMetrics(process1)); 73 } 74 testUserMetricsChange()75 public void testUserMetricsChange() throws Exception { 76 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 77 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 78 SAMPLE_WINDOW_MS, mockSystemStateInterface); 79 80 UserActivity user0 = new UserActivity(0); 81 user0.foreground_rchar = 50; 82 user0.background_wchar = 10; 83 84 user0.updateSystemState(mockSystemStateInterface); 85 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 86 87 user0.foreground_rchar = 60; 88 user0.foreground_wchar = 10; 89 UidIoRecord process0 = user0.updateSystemState(mockSystemStateInterface); 90 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 91 92 assertEquals(1, ioStatsTracker.getCurrentSample().size()); 93 assertEquals(1, ioStatsTracker.getTotal().size()); 94 95 IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0); 96 IoStatsEntry total0 = ioStatsTracker.getTotal().get(0); 97 98 assertNotNull(sample0); 99 assertNotNull(total0); 100 101 assertTrue(total0.representsSameMetrics(process0)); 102 103 assertEquals(10, sample0.foreground.bytesRead); 104 assertEquals(10, sample0.foreground.bytesWritten); 105 assertEquals(0, sample0.background.bytesWritten); 106 } 107 testUpdateNoIoProcessActive()108 public void testUpdateNoIoProcessActive() throws Exception { 109 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 110 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 111 SAMPLE_WINDOW_MS, mockSystemStateInterface); 112 113 UserActivity user0 = new UserActivity(0); 114 user0.foreground_rchar = 50; 115 user0.background_wchar = 10; 116 117 user0.updateSystemState(mockSystemStateInterface); 118 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 119 120 user0.spawnProcess(); 121 user0.updateSystemState(mockSystemStateInterface); 122 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 123 124 assertEquals(1, ioStatsTracker.getCurrentSample().size()); 125 assertEquals(1, ioStatsTracker.getTotal().size()); 126 127 IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0); 128 IoStatsEntry total0 = ioStatsTracker.getTotal().get(0); 129 130 assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis); 131 assertEquals(2 * SAMPLE_WINDOW_MS, total0.runtimeMillis); 132 133 assertEquals(0, sample0.foreground.bytesRead); 134 assertEquals(0, sample0.background.bytesWritten); 135 } 136 testUpdateNoIoProcessInactive()137 public void testUpdateNoIoProcessInactive() throws Exception { 138 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 139 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 140 SAMPLE_WINDOW_MS, mockSystemStateInterface); 141 142 UserActivity user0 = new UserActivity(0); 143 user0.foreground_rchar = 50; 144 user0.background_wchar = 10; 145 146 user0.updateSystemState(mockSystemStateInterface); 147 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 148 149 user0.killProcess(); 150 UidIoRecord record0 = user0.updateSystemState(mockSystemStateInterface); 151 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 152 153 assertEquals(0, ioStatsTracker.getCurrentSample().size()); 154 assertEquals(1, ioStatsTracker.getTotal().size()); 155 156 IoStatsEntry total0 = ioStatsTracker.getTotal().get(0); 157 assertEquals(SAMPLE_WINDOW_MS, total0.runtimeMillis); 158 assertTrue(total0.representsSameMetrics(record0)); 159 } 160 testUpdateIoHappens()161 public void testUpdateIoHappens() throws Exception { 162 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 163 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 164 SAMPLE_WINDOW_MS, mockSystemStateInterface); 165 166 UserActivity user0 = new UserActivity(0); 167 user0.foreground_rchar = 50; 168 user0.background_wchar = 10; 169 170 user0.updateSystemState(mockSystemStateInterface); 171 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 172 173 user0.foreground_rchar = 60; 174 UidIoRecord record0 = user0.updateSystemState(mockSystemStateInterface); 175 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 176 177 assertEquals(1, ioStatsTracker.getCurrentSample().size()); 178 assertEquals(1, ioStatsTracker.getTotal().size()); 179 180 IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0); 181 IoStatsEntry total0 = ioStatsTracker.getTotal().get(0); 182 183 assertTrue(total0.representsSameMetrics(record0)); 184 assertEquals(2 * SAMPLE_WINDOW_MS, total0.runtimeMillis); 185 assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis); 186 assertEquals(10, sample0.foreground.bytesRead); 187 assertEquals(0, sample0.background.bytesWritten); 188 } 189 testUpdateGoAwayComeBackProcess()190 public void testUpdateGoAwayComeBackProcess() throws Exception { 191 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 192 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 193 SAMPLE_WINDOW_MS, mockSystemStateInterface); 194 195 UserActivity user0 = new UserActivity(0); 196 user0.foreground_rchar = 50; 197 user0.background_wchar = 10; 198 199 user0.updateSystemState(mockSystemStateInterface); 200 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 201 202 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 203 204 assertEquals(0, ioStatsTracker.getCurrentSample().size()); 205 assertEquals(1, ioStatsTracker.getTotal().size()); 206 207 user0.spawnProcess(); 208 user0.updateSystemState(mockSystemStateInterface); 209 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 210 211 assertEquals(1, ioStatsTracker.getCurrentSample().size()); 212 IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0); 213 assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis); 214 } 215 testUpdateGoAwayComeBackIo()216 public void testUpdateGoAwayComeBackIo() throws Exception { 217 final MockSystemStateInterface mockSystemStateInterface = new MockSystemStateInterface(); 218 IoStatsTracker ioStatsTracker = new IoStatsTracker(EMPTY, 219 SAMPLE_WINDOW_MS, mockSystemStateInterface); 220 221 UserActivity user0 = new UserActivity(0); 222 user0.foreground_rchar = 50; 223 user0.background_wchar = 10; 224 225 user0.updateSystemState(mockSystemStateInterface); 226 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 227 228 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 229 230 assertEquals(0, ioStatsTracker.getCurrentSample().size()); 231 assertEquals(1, ioStatsTracker.getTotal().size()); 232 233 user0.foreground_fsync = 1; 234 235 user0.updateSystemState(mockSystemStateInterface); 236 ioStatsTracker.update(mockSystemStateInterface.mIoRecords); 237 238 assertEquals(1, ioStatsTracker.getCurrentSample().size()); 239 240 IoStatsEntry sample0 = ioStatsTracker.getCurrentSample().get(0); 241 assertEquals(2 * SAMPLE_WINDOW_MS, sample0.runtimeMillis); 242 assertEquals(1, sample0.foreground.fsyncCalls); 243 } 244 245 private static final class UserActivity { 246 private final int mUid; 247 private boolean mHasProcess; 248 249 private long foreground_rchar; 250 private long foreground_wchar; 251 private long foreground_read_bytes; 252 private long foreground_write_bytes; 253 private long foreground_fsync; 254 255 private long background_rchar; 256 private long background_wchar; 257 private long background_read_bytes; 258 private long background_write_bytes; 259 private long background_fsync; 260 UserActivity(int uid)261 UserActivity(int uid) { 262 mUid = uid; 263 } 264 spawnProcess()265 void spawnProcess() { 266 mHasProcess = true; 267 } killProcess()268 void killProcess() { 269 mHasProcess = false; 270 } 271 updateSystemState(MockSystemStateInterface systemState)272 UidIoRecord updateSystemState(MockSystemStateInterface systemState) { 273 UidIoRecord uidIoRecord = new UidIoRecord(mUid, 274 foreground_rchar, 275 foreground_wchar, 276 foreground_read_bytes, 277 foreground_write_bytes, 278 foreground_fsync, 279 background_rchar, 280 background_wchar, 281 background_read_bytes, 282 background_write_bytes, 283 background_fsync); 284 285 systemState.addIoRecord(uidIoRecord); 286 if (mHasProcess) { 287 systemState.addProcess(new ProcessInfo(1, mUid)); 288 } else { 289 systemState.removeUserProcesses(mUid); 290 } 291 292 return uidIoRecord; 293 } 294 } 295 296 private final class MockSystemStateInterface implements SystemStateInterface { 297 private final List<ProcessInfo> mProcesses = new ArrayList<>(); 298 private final SparseArray<UidIoRecord> mIoRecords = new SparseArray<>(); 299 300 @Override shutdown()301 public void shutdown() { 302 } 303 304 @Override enterDeepSleep()305 public boolean enterDeepSleep() { 306 return true; 307 } 308 309 @Override scheduleActionForBootCompleted(Runnable action, Duration delay)310 public void scheduleActionForBootCompleted(Runnable action, Duration delay) { 311 } 312 313 @Override isWakeupCausedByTimer()314 public boolean isWakeupCausedByTimer() { 315 return false; 316 } 317 318 @Override isSystemSupportingDeepSleep()319 public boolean isSystemSupportingDeepSleep() { 320 return false; 321 } 322 323 @Override getRunningProcesses()324 public synchronized List<ProcessInfo> getRunningProcesses() { 325 return mProcesses; 326 } 327 addProcess(ProcessInfo processInfo)328 synchronized void addProcess(ProcessInfo processInfo) { 329 mProcesses.add(processInfo); 330 } 331 removeUserProcesses(int uid)332 synchronized void removeUserProcesses(int uid) { 333 mProcesses.removeAll( 334 mProcesses.stream().filter(pi -> pi.uid == uid).collect(Collectors.toList())); 335 } 336 addIoRecord(UidIoRecord record)337 synchronized void addIoRecord(UidIoRecord record) { 338 mIoRecords.put(record.uid, record); 339 } 340 clear()341 synchronized void clear() { 342 mProcesses.clear(); 343 mIoRecords.clear(); 344 } 345 } 346 } 347