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