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.cts.storagestatsapp; 18 19 import static android.os.storage.StorageManager.UUID_DEFAULT; 20 21 import static com.android.cts.storageapp.Utils.CACHE_ALL; 22 import static com.android.cts.storageapp.Utils.CACHE_EXT; 23 import static com.android.cts.storageapp.Utils.CODE_ALL; 24 import static com.android.cts.storageapp.Utils.DATA_ALL; 25 import static com.android.cts.storageapp.Utils.MB_IN_BYTES; 26 import static com.android.cts.storageapp.Utils.PKG_A; 27 import static com.android.cts.storageapp.Utils.PKG_B; 28 import static com.android.cts.storageapp.Utils.PKG_C; 29 import static com.android.cts.storageapp.Utils.REF_PROFILES_BASE_DIR; 30 import static com.android.cts.storageapp.Utils.CUR_PROFILES_BASE_DIR; 31 import static com.android.cts.storageapp.Utils.PROFILE_FILE_NAME; 32 import static com.android.cts.storageapp.Utils.TAG; 33 import static com.android.cts.storageapp.Utils.assertAtLeast; 34 import static com.android.cts.storageapp.Utils.assertMostlyEquals; 35 import static com.android.cts.storageapp.Utils.getSizeManual; 36 import static com.android.cts.storageapp.Utils.logCommand; 37 import static com.android.cts.storageapp.Utils.makeUniqueFile; 38 import static com.android.cts.storageapp.Utils.useFallocate; 39 import static com.android.cts.storageapp.Utils.useSpace; 40 import static com.android.cts.storageapp.Utils.useWrite; 41 42 import static org.junit.Assert.assertEquals; 43 import static org.junit.Assume.assumeTrue; 44 45 import org.junit.Before; 46 import org.junit.Rule; 47 48 import android.app.Activity; 49 import android.app.usage.ExternalStorageStats; 50 import android.app.usage.Flags; 51 import android.app.usage.StorageStats; 52 import android.app.usage.StorageStatsManager; 53 import android.content.BroadcastReceiver; 54 import android.content.ComponentName; 55 import android.content.ContentProviderClient; 56 import android.content.Context; 57 import android.content.Intent; 58 import android.content.pm.ApplicationInfo; 59 import android.content.pm.PackageManager; 60 import android.os.Build; 61 import android.os.Bundle; 62 import android.os.Environment; 63 import android.os.SystemProperties; 64 import android.os.UserHandle; 65 import android.os.storage.StorageManager; 66 import android.platform.test.annotations.RequiresFlagsEnabled; 67 import android.platform.test.flag.junit.CheckFlagsRule; 68 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 69 import android.provider.DeviceConfig; 70 import android.provider.MediaStore; 71 import android.test.InstrumentationTestCase; 72 import android.util.Log; 73 import android.util.MutableLong; 74 75 import androidx.test.uiautomator.UiDevice; 76 77 import com.android.compatibility.common.util.SystemUtil; 78 import com.android.cts.storageapp.UtilsReceiver; 79 80 import junit.framework.AssertionFailedError; 81 82 import java.io.File; 83 import java.util.UUID; 84 import java.util.concurrent.CountDownLatch; 85 import java.util.concurrent.TimeUnit; 86 87 /** 88 * Tests to verify {@link StorageStatsManager} behavior. 89 */ 90 public class StorageStatsTest extends InstrumentationTestCase { 91 private PackageManager pm; 92 private StorageStatsManager stats; 93 private UserHandle user; 94 95 @SuppressWarnings("JUnit4ClassUsedInJUnit3") 96 @Rule 97 public final CheckFlagsRule mCheckFlagsRule = 98 DeviceFlagsValueProvider.createCheckFlagsRule(); 99 100 @Before setUp()101 public void setUp() { 102 pm = getContext().getPackageManager(); 103 stats = getContext().getSystemService(StorageStatsManager.class); 104 user = android.os.Process.myUserHandle(); 105 } getContext()106 private Context getContext() { 107 return getInstrumentation().getContext(); 108 } 109 110 /** 111 * Require that quota support be fully enabled on devices that first ship 112 * with P. This test verifies that both kernel options and the fstab 'quota' 113 * option are enabled. 114 */ testVerify()115 public void testVerify() throws Exception { 116 if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.P) { 117 final StorageStatsManager stats = getContext() 118 .getSystemService(StorageStatsManager.class); 119 assertTrue("Devices that first ship with P or newer must enable quotas to " 120 + "support StorageStatsManager APIs. You may need to enable the " 121 + "CONFIG_QUOTA, CONFIG_QFMT_V2, CONFIG_QUOTACTL kernel options " 122 + "and add the 'quota' fstab option on /data.", 123 stats.isQuotaSupported(UUID_DEFAULT)); 124 assertTrue("Devices that first ship with P or newer must enable resgid to " 125 + "preserve system stability in the face of abusive apps.", 126 stats.isReservedSupported(UUID_DEFAULT)); 127 } 128 } 129 testVerifySummary()130 public void testVerifySummary() throws Exception { 131 final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class); 132 133 final long actualTotal = stats.getTotalBytes(UUID_DEFAULT); 134 final long expectedTotal = Environment.getDataDirectory().getTotalSpace(); 135 assertAtLeast(expectedTotal, actualTotal); 136 137 final long actualFree = stats.getFreeBytes(UUID_DEFAULT); 138 final long expectedFree = Environment.getDataDirectory().getUsableSpace(); 139 assertAtLeast(expectedFree, actualFree); 140 } 141 testVerifyStats()142 public void testVerifyStats() throws Exception { 143 final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class); 144 final int uid = android.os.Process.myUid(); 145 final UserHandle user = UserHandle.getUserHandleForUid(uid); 146 147 final StorageStats beforeApp = stats.queryStatsForUid(UUID_DEFAULT, uid); 148 final StorageStats beforeUser = stats.queryStatsForUser(UUID_DEFAULT, user); 149 150 useSpace(getContext()); 151 152 final StorageStats afterApp = stats.queryStatsForUid(UUID_DEFAULT, uid); 153 final StorageStats afterUser = stats.queryStatsForUser(UUID_DEFAULT, user); 154 155 final long deltaCode = CODE_ALL; 156 assertMostlyEquals(deltaCode, afterApp.getAppBytes() - beforeApp.getAppBytes()); 157 assertMostlyEquals(deltaCode, afterUser.getAppBytes() - beforeUser.getAppBytes()); 158 159 final long deltaData = DATA_ALL; 160 assertMostlyEquals(deltaData, afterApp.getDataBytes() - beforeApp.getDataBytes()); 161 assertMostlyEquals(deltaData, afterUser.getDataBytes() - beforeUser.getDataBytes()); 162 163 final long deltaCache = CACHE_ALL; 164 assertMostlyEquals(deltaCache, afterApp.getCacheBytes() - beforeApp.getCacheBytes()); 165 assertMostlyEquals(deltaCache, afterUser.getCacheBytes() - beforeUser.getCacheBytes()); 166 167 final long deltaExternalCache = CACHE_EXT; 168 assertMostlyEquals(deltaExternalCache, 169 afterApp.getExternalCacheBytes() - beforeApp.getExternalCacheBytes()); 170 assertMostlyEquals(deltaExternalCache, 171 afterUser.getExternalCacheBytes() - beforeUser.getExternalCacheBytes()); 172 } 173 174 @RequiresFlagsEnabled(Flags.FLAG_GET_APP_BYTES_BY_DATA_TYPE_API) testVerifyStatsByDataType()175 public void testVerifyStatsByDataType() throws Exception { 176 final ApplicationInfo appInfo = pm.getApplicationInfo(PKG_C, 0); 177 useSpace(getContext()); 178 179 String appSrcPath = appInfo.sourceDir; 180 File appSrcDir = new File(appInfo.sourceDir); 181 // sourceDir could return the base.apk with path, in that case, use the parent directory. 182 if (appSrcDir.isFile()) { 183 appSrcDir = appSrcDir.getParentFile(); 184 } 185 186 final StorageStats as = stats.queryStatsForPackage(UUID_DEFAULT, PKG_C, user); 187 188 long apkSize = getSizeOfFilesEndWith(appSrcDir, ".apk"); 189 assertEquals(apkSize, as.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_FILE_TYPE_APK)); 190 191 long dmSize = getSizeOfFilesEndWith(appSrcDir, ".dm"); 192 assertEquals(dmSize, as.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_FILE_TYPE_DM)); 193 194 long libSize = getSizeOfDir(new File(appSrcPath + "/lib/")); 195 assertEquals(libSize, as.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_LIB)); 196 197 // Check the profile sizes if they are fetched by ArtManagedFileStats. 198 long curProfileBytes = 199 as.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_FILE_TYPE_CURRENT_PROFILE); 200 File curProfile = new File(new File(CUR_PROFILES_BASE_DIR + appInfo.uid + "/", PKG_C), 201 PROFILE_FILE_NAME); 202 assertEquals(curProfile.length(), curProfileBytes); 203 204 long refProfileBytes = 205 as.getAppBytesByDataType(StorageStats.APP_DATA_TYPE_FILE_TYPE_REFERENCE_PROFILE); 206 assertTrue(refProfileBytes > 0); 207 } 208 testVerifyStatsMultiple()209 public void testVerifyStatsMultiple() throws Exception { 210 final ApplicationInfo a = pm.getApplicationInfo(PKG_A, 0); 211 final ApplicationInfo b = pm.getApplicationInfo(PKG_B, 0); 212 213 final StorageStats as = stats.queryStatsForUid(UUID_DEFAULT, a.uid); 214 final StorageStats bs = stats.queryStatsForUid(UUID_DEFAULT, b.uid); 215 216 assertMostlyEquals(DATA_ALL * 2, as.getDataBytes()); 217 assertMostlyEquals(CACHE_ALL * 2, as.getCacheBytes()); 218 219 assertMostlyEquals(DATA_ALL, bs.getDataBytes()); 220 assertMostlyEquals(CACHE_ALL, bs.getCacheBytes()); 221 222 // Since OBB storage space may be shared or isolated between users, 223 // we'll accept either expected or double usage. 224 try { 225 assertMostlyEquals(CODE_ALL * 2, as.getAppBytes(), 5 * MB_IN_BYTES); 226 assertMostlyEquals(CODE_ALL * 1, bs.getAppBytes(), 5 * MB_IN_BYTES); 227 } catch (AssertionFailedError e) { 228 assertMostlyEquals(CODE_ALL * 4, as.getAppBytes(), 5 * MB_IN_BYTES); 229 assertMostlyEquals(CODE_ALL * 2, bs.getAppBytes(), 5 * MB_IN_BYTES); 230 } 231 } 232 233 /** 234 * Create some external files of specific media types and ensure that 235 * they're tracked correctly. 236 */ testVerifyStatsExternal()237 public void testVerifyStatsExternal() throws Exception { 238 final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class); 239 final int uid = android.os.Process.myUid(); 240 final UserHandle user = UserHandle.getUserHandleForUid(uid); 241 242 final ExternalStorageStats before = stats.queryExternalStatsForUser(UUID_DEFAULT, user); 243 244 final File dir = Environment.getExternalStorageDirectory(); 245 final File downloadsDir = Environment.getExternalStoragePublicDirectory( 246 Environment.DIRECTORY_DOWNLOADS); 247 downloadsDir.mkdirs(); 248 249 final File image = new File(dir, System.nanoTime() + ".jpg"); 250 final File video = new File(downloadsDir, System.nanoTime() + ".MP4"); 251 final File audio = new File(dir, System.nanoTime() + ".png.WaV"); 252 final File internal = new File( 253 getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), "test.jpg"); 254 255 useWrite(image, 2 * MB_IN_BYTES); 256 useWrite(video, 3 * MB_IN_BYTES); 257 useWrite(audio, 5 * MB_IN_BYTES); 258 useWrite(internal, 7 * MB_IN_BYTES); 259 260 final ExternalStorageStats afterInit = stats.queryExternalStatsForUser(UUID_DEFAULT, user); 261 262 assertMostlyEquals(17 * MB_IN_BYTES, afterInit.getTotalBytes() - before.getTotalBytes()); 263 assertMostlyEquals(5 * MB_IN_BYTES, afterInit.getAudioBytes() - before.getAudioBytes()); 264 assertMostlyEquals(3 * MB_IN_BYTES, afterInit.getVideoBytes() - before.getVideoBytes()); 265 assertMostlyEquals(2 * MB_IN_BYTES, afterInit.getImageBytes() - before.getImageBytes()); 266 assertMostlyEquals(7 * MB_IN_BYTES, afterInit.getAppBytes() - before.getAppBytes()); 267 268 // Rename to ensure that stats are updated 269 video.renameTo(new File(dir, System.nanoTime() + ".PnG")); 270 271 // Since we have MANAGE_EXTERNAL_STORAGE, need to ask for a re-scan 272 MediaStore.scanFile(getContext().getContentResolver(), dir); 273 MediaStore.scanFile(getContext().getContentResolver(), downloadsDir); 274 MediaStore.waitForIdle(getContext().getContentResolver()); 275 276 final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(UUID_DEFAULT, user); 277 278 assertMostlyEquals(17 * MB_IN_BYTES, afterRename.getTotalBytes() - before.getTotalBytes()); 279 assertMostlyEquals(5 * MB_IN_BYTES, afterRename.getAudioBytes() - before.getAudioBytes()); 280 assertMostlyEquals(0 * MB_IN_BYTES, afterRename.getVideoBytes() - before.getVideoBytes()); 281 assertMostlyEquals(5 * MB_IN_BYTES, afterRename.getImageBytes() - before.getImageBytes()); 282 assertMostlyEquals(7 * MB_IN_BYTES, afterRename.getAppBytes() - before.getAppBytes()); 283 } 284 285 /** 286 * Measuring external storage manually should always be consistent with 287 * whatever the stats APIs are returning. 288 */ testVerifyStatsExternalConsistent()289 public void testVerifyStatsExternalConsistent() throws Exception { 290 final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class); 291 final UserHandle user = android.os.Process.myUserHandle(); 292 293 // Since scoped storage, apps can't access the package-specific Android/ 294 // directories anymore. So we compute the current size, and assume the 295 // delta is in Android/*, which unfortunately may have data from 296 // test APKs that aren't cleaned up properly. 297 // 298 // Then, when we compute the new size and compare it with the stats, 299 // we expect the same delta 300 final long manualSizeBefore = getSizeManual( 301 Environment.getExternalStorageDirectory(), true); 302 final long statsSizeBefore = stats.queryExternalStatsForUser( 303 UUID_DEFAULT, user).getTotalBytes(); 304 305 final long deltaBefore = statsSizeBefore - manualSizeBefore; 306 307 useSpace(getContext()); 308 309 final File top = Environment.getExternalStorageDirectory(); 310 final File pics = Environment 311 .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); 312 pics.mkdirs(); 313 314 useWrite(makeUniqueFile(top), 5 * MB_IN_BYTES); 315 useWrite(makeUniqueFile(pics), 5 * MB_IN_BYTES); 316 useWrite(makeUniqueFile(pics), 5 * MB_IN_BYTES); 317 318 // for fuse file system 319 Thread.sleep(10000); 320 321 // TODO: remove this once 34723223 is fixed 322 logCommand("sync"); 323 324 long manualSize = getSizeManual(Environment.getExternalStorageDirectory(), true); 325 // Since scoped storage, we can't walk the Android/ tree anymore; so pass in this 326 // app's files and cache dirs directly. 327 manualSize += getSizeManual(getContext().getExternalFilesDir(null), true); 328 manualSize += getSizeManual(getContext().getExternalCacheDir(), true); 329 final long statsSize = stats.queryExternalStatsForUser(UUID_DEFAULT, user).getTotalBytes(); 330 331 final long deltaAfter = statsSize - manualSize; 332 assertMostlyEquals(deltaBefore, deltaAfter); 333 } 334 testVerifyCategory()335 public void testVerifyCategory() throws Exception { 336 final ApplicationInfo a = pm.getApplicationInfo(PKG_A, 0); 337 final ApplicationInfo b = pm.getApplicationInfo(PKG_B, 0); 338 339 assertEquals(ApplicationInfo.CATEGORY_VIDEO, a.category); 340 assertEquals(ApplicationInfo.CATEGORY_UNDEFINED, b.category); 341 } 342 testCacheClearing()343 public void testCacheClearing() throws Exception { 344 final int[] originalCacheReservePercents = new int[2]; 345 setCacheReservePercentsToZero(originalCacheReservePercents); 346 347 try { 348 testCacheClearing(originalCacheReservePercents); 349 } finally { 350 resetCacheReservePercents(originalCacheReservePercents); 351 } 352 } 353 testCacheBehavior()354 public void testCacheBehavior() throws Exception { 355 final int[] originalCacheReservePercents = new int[2]; 356 setCacheReservePercentsToZero(originalCacheReservePercents); 357 358 try { 359 testCacheBehavior(originalCacheReservePercents); 360 } finally { 361 resetCacheReservePercents(originalCacheReservePercents); 362 } 363 } 364 testCacheClearing(int[] originalCacheReservePercents)365 private void testCacheClearing(int[] originalCacheReservePercents) throws Exception { 366 final Context context = getContext(); 367 final StorageManager sm = context.getSystemService(StorageManager.class); 368 final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); 369 final UserHandle user = android.os.Process.myUserHandle(); 370 371 final File filesDir = context.getFilesDir(); 372 final UUID filesUuid = sm.getUuidForPath(filesDir); 373 final String pmUuid = filesUuid.equals(StorageManager.UUID_DEFAULT) ? "internal" 374 : filesUuid.toString(); 375 376 final long beforeAllocatable = sm.getAllocatableBytes(filesUuid); 377 final long beforeFree = stats.getFreeBytes(filesUuid); 378 final long beforeRaw = filesDir.getUsableSpace(); 379 380 Log.d(TAG, "Before raw " + beforeRaw + ", free " + beforeFree + ", allocatable " 381 + beforeAllocatable); 382 383 assertMostlyEquals(0, getCacheBytes(PKG_A, user)); 384 assertMostlyEquals(0, getCacheBytes(PKG_B, user)); 385 386 // Ask apps to allocate some cached data 387 final long targetA = doAllocateProvider(PKG_A, 0.5, 1262304000); 388 final long targetB = doAllocateProvider(PKG_B, 2.0, 1420070400); 389 final long totalAllocated = targetA + targetB; 390 391 MediaStore.waitForIdle(getContext().getContentResolver()); 392 393 // Difference caused by other operations when writing to cache 394 // The longer the writing time, the greater the difference 395 final long difference = Math.max(10 * MB_IN_BYTES, totalAllocated / 100); 396 397 // Apps using up some cache space shouldn't change how much we can 398 // allocate, or how much we think is free; but it should decrease real 399 // disk space. 400 if (stats.isQuotaSupported(filesUuid)) { 401 assertMostlyEquals(beforeAllocatable, 402 sm.getAllocatableBytes(filesUuid), difference); 403 assertMostlyEquals(beforeFree, 404 stats.getFreeBytes(filesUuid), difference); 405 } else { 406 assertMostlyEquals(beforeAllocatable - totalAllocated, 407 sm.getAllocatableBytes(filesUuid), difference); 408 assertMostlyEquals(beforeFree - totalAllocated, 409 stats.getFreeBytes(filesUuid), difference); 410 } 411 assertMostlyEquals(beforeRaw - totalAllocated, 412 filesDir.getUsableSpace(), difference); 413 414 assertMostlyEquals(targetA, getCacheBytes(PKG_A, user), 2 * MB_IN_BYTES); 415 assertMostlyEquals(targetB, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES); 416 417 // Allocate some space for ourselves, which should trim away at 418 // over-quota app first, even though its files are newer. 419 final long clear1 = filesDir.getUsableSpace() + (targetB / 2); 420 if (stats.isQuotaSupported(filesUuid)) { 421 sm.allocateBytes(filesUuid, clear1); 422 } else { 423 UiDevice.getInstance(getInstrumentation()) 424 .executeShellCommand("pm trim-caches " + clear1 + " " + pmUuid); 425 } 426 427 assertMostlyEquals(targetA, getCacheBytes(PKG_A, user), 2 * MB_IN_BYTES); 428 assertMostlyEquals(targetB / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES); 429 430 // Allocate some more space for ourselves, which should now start 431 // trimming away at older app. Since we pivot between the two apps once 432 // they're tied for cache ratios, we expect to clear about half of the 433 // remaining space from each of them. 434 final long clear2 = filesDir.getUsableSpace() + (targetB / 2); 435 if (stats.isQuotaSupported(filesUuid)) { 436 sm.allocateBytes(filesUuid, clear2); 437 } else { 438 UiDevice.getInstance(getInstrumentation()) 439 .executeShellCommand("pm trim-caches " + clear2 + " " + pmUuid); 440 } 441 442 assertMostlyEquals(targetA / 2, getCacheBytes(PKG_A, user), 2 * MB_IN_BYTES); 443 assertMostlyEquals(targetA / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES); 444 } 445 testCacheBehavior(int[] originalCacheReservePercents)446 private void testCacheBehavior(int[] originalCacheReservePercents) throws Exception { 447 final Context context = getContext(); 448 final StorageManager sm = context.getSystemService(StorageManager.class); 449 final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); 450 451 final UUID filesUuid = sm.getUuidForPath(context.getFilesDir()); 452 final String pmUuid = filesUuid.equals(StorageManager.UUID_DEFAULT) ? "internal" 453 : filesUuid.toString(); 454 455 final File normal = new File(context.getCacheDir(), "normal"); 456 final File group = new File(context.getCacheDir(), "group"); 457 final File tomb = new File(context.getCacheDir(), "tomb"); 458 459 final long size = 2 * MB_IN_BYTES; 460 461 final long normalTime = 1262304000; 462 final long groupTime = 1262303000; 463 final long tombTime = 1262302000; 464 465 normal.mkdir(); 466 group.mkdir(); 467 tomb.mkdir(); 468 469 sm.setCacheBehaviorGroup(group, true); 470 sm.setCacheBehaviorTombstone(tomb, true); 471 472 final File a = useFallocate(makeUniqueFile(normal), size, normalTime); 473 final File b = useFallocate(makeUniqueFile(normal), size, normalTime); 474 final File c = useFallocate(makeUniqueFile(normal), size, normalTime); 475 476 final File d = useFallocate(makeUniqueFile(group), size, groupTime); 477 final File e = useFallocate(makeUniqueFile(group), size, groupTime); 478 final File f = useFallocate(makeUniqueFile(group), size, groupTime); 479 480 final File g = useFallocate(makeUniqueFile(tomb), size, tombTime); 481 final File h = useFallocate(makeUniqueFile(tomb), size, tombTime); 482 final File i = useFallocate(makeUniqueFile(tomb), size, tombTime); 483 484 normal.setLastModified(normalTime); 485 group.setLastModified(groupTime); 486 tomb.setLastModified(tombTime); 487 488 final long clear1 = group.getUsableSpace() + (8 * MB_IN_BYTES); 489 if (stats.isQuotaSupported(filesUuid)) { 490 sm.allocateBytes(filesUuid, clear1); 491 } else { 492 UiDevice.getInstance(getInstrumentation()) 493 .executeShellCommand("pm trim-caches " + clear1 + " " + pmUuid); 494 } 495 496 assertTrue(a.exists()); 497 assertTrue(b.exists()); 498 assertTrue(c.exists()); 499 assertFalse(group.exists()); 500 assertFalse(d.exists()); 501 assertFalse(e.exists()); 502 assertFalse(f.exists()); 503 assertTrue(g.exists()); assertEquals(0, g.length()); 504 assertTrue(h.exists()); assertEquals(0, h.length()); 505 assertTrue(i.exists()); assertEquals(0, i.length()); 506 } 507 508 /* originalCacheReservePercents is an array of size 2 with CacheReservePercentHigh 509 * at index 0 and CacheReservePercentLow at index 1. 510 */ setCacheReservePercentsToZero(int[] originalCacheReservePercents)511 private void setCacheReservePercentsToZero(int[] originalCacheReservePercents) { 512 SystemUtil.runWithShellPermissionIdentity(() -> { 513 originalCacheReservePercents[0] = DeviceConfig.getInt( 514 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 515 StorageManager.CACHE_RESERVE_PERCENT_HIGH_KEY, -1); 516 DeviceConfig.setProperty( 517 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 518 StorageManager.CACHE_RESERVE_PERCENT_HIGH_KEY, 519 Integer.toString(0), /* makeDefault */ false); 520 originalCacheReservePercents[1] = DeviceConfig.getInt( 521 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 522 StorageManager.CACHE_RESERVE_PERCENT_LOW_KEY, -1); 523 DeviceConfig.setProperty( 524 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 525 StorageManager.CACHE_RESERVE_PERCENT_LOW_KEY, 526 Integer.toString(0), /* makeDefault */ false); 527 }); 528 } 529 resetCacheReservePercents(int[] originalCacheReservePercents)530 private void resetCacheReservePercents(int[] originalCacheReservePercents) { 531 SystemUtil.runWithShellPermissionIdentity(() -> { 532 DeviceConfig.setProperty( 533 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 534 StorageManager.CACHE_RESERVE_PERCENT_HIGH_KEY, 535 (originalCacheReservePercents[0] != -1) 536 ? Integer.toString(originalCacheReservePercents[0]) : null, 537 /* makeDefault */ false); 538 DeviceConfig.setProperty( 539 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 540 StorageManager.CACHE_RESERVE_PERCENT_LOW_KEY, 541 (originalCacheReservePercents[1] != -1) 542 ? Integer.toString(originalCacheReservePercents[1]) : null, 543 /* makeDefault */ false); 544 }); 545 } 546 getCacheBytes(String pkg, UserHandle user)547 private long getCacheBytes(String pkg, UserHandle user) throws Exception { 548 return getContext().getSystemService(StorageStatsManager.class) 549 .queryStatsForPackage(UUID_DEFAULT, pkg, user).getCacheBytes(); 550 } 551 doAllocateReceiver(String pkg, double fraction, long time)552 private long doAllocateReceiver(String pkg, double fraction, long time) throws Exception { 553 final CountDownLatch latch = new CountDownLatch(1); 554 final Intent intent = new Intent(); 555 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 556 intent.setComponent(new ComponentName(pkg, UtilsReceiver.class.getName())); 557 intent.putExtra(UtilsReceiver.EXTRA_FRACTION, fraction); 558 intent.putExtra(UtilsReceiver.EXTRA_TIME, time); 559 final MutableLong bytes = new MutableLong(0); 560 getInstrumentation().getTargetContext().sendOrderedBroadcast(intent, null, 561 new BroadcastReceiver() { 562 @Override 563 public void onReceive(Context context, Intent intent) { 564 bytes.value = getResultExtras(false).getLong(UtilsReceiver.EXTRA_BYTES); 565 latch.countDown(); 566 } 567 }, null, Activity.RESULT_CANCELED, null, null); 568 latch.await(30, TimeUnit.SECONDS); 569 return bytes.value; 570 } 571 doAllocateProvider(String pkg, double fraction, long time)572 private long doAllocateProvider(String pkg, double fraction, long time) throws Exception { 573 final Bundle args = new Bundle(); 574 args.putDouble(UtilsReceiver.EXTRA_FRACTION, fraction); 575 args.putLong(UtilsReceiver.EXTRA_TIME, time); 576 577 try (final ContentProviderClient client = getContext().getContentResolver() 578 .acquireContentProviderClient(pkg)) { 579 final Bundle res = client.call(pkg, pkg, args); 580 return res.getLong(UtilsReceiver.EXTRA_BYTES); 581 } 582 } 583 getSizeOfFilesEndWith(File dir, String suffix)584 private long getSizeOfFilesEndWith(File dir, String suffix) { 585 if (!dir.isDirectory()) { 586 return 0; 587 } 588 589 long size = 0; 590 try { 591 for (File file : dir.listFiles()) { 592 if (file.isFile() && file.getName().endsWith(suffix)) { 593 size += file.length(); 594 } 595 } 596 } catch (NullPointerException e) { 597 size += 0; 598 } 599 600 return size; 601 } 602 getSizeOfDir(File dir)603 private long getSizeOfDir(File dir) { 604 if (!dir.isDirectory()) { 605 return 0; 606 } 607 608 long size = 0; 609 try { 610 for (File file : dir.listFiles()) { 611 if (file.isFile()) { 612 size += file.length(); 613 } else if (file.isDirectory()) { 614 size += getSizeOfDir(file); 615 } 616 } 617 } catch (NullPointerException e) { 618 size += 0; 619 } 620 621 return size; 622 } 623 } 624