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 // Apps using up some cache space shouldn't change how much we can 394 // allocate, or how much we think is free; but it should decrease real 395 // disk space. 396 if (stats.isQuotaSupported(filesUuid)) { 397 assertMostlyEquals(beforeAllocatable, 398 sm.getAllocatableBytes(filesUuid), 10 * MB_IN_BYTES); 399 assertMostlyEquals(beforeFree, 400 stats.getFreeBytes(filesUuid), 10 * MB_IN_BYTES); 401 } else { 402 assertMostlyEquals(beforeAllocatable - totalAllocated, 403 sm.getAllocatableBytes(filesUuid), 10 * MB_IN_BYTES); 404 assertMostlyEquals(beforeFree - totalAllocated, 405 stats.getFreeBytes(filesUuid), 10 * MB_IN_BYTES); 406 } 407 assertMostlyEquals(beforeRaw - totalAllocated, 408 filesDir.getUsableSpace(), 10 * MB_IN_BYTES); 409 410 assertMostlyEquals(targetA, getCacheBytes(PKG_A, user)); 411 assertMostlyEquals(targetB, getCacheBytes(PKG_B, user)); 412 413 // Allocate some space for ourselves, which should trim away at 414 // over-quota app first, even though its files are newer. 415 final long clear1 = filesDir.getUsableSpace() + (targetB / 2); 416 if (stats.isQuotaSupported(filesUuid)) { 417 sm.allocateBytes(filesUuid, clear1); 418 } else { 419 UiDevice.getInstance(getInstrumentation()) 420 .executeShellCommand("pm trim-caches " + clear1 + " " + pmUuid); 421 } 422 423 assertMostlyEquals(targetA, getCacheBytes(PKG_A, user)); 424 assertMostlyEquals(targetB / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES); 425 426 // Allocate some more space for ourselves, which should now start 427 // trimming away at older app. Since we pivot between the two apps once 428 // they're tied for cache ratios, we expect to clear about half of the 429 // remaining space from each of them. 430 final long clear2 = filesDir.getUsableSpace() + (targetB / 2); 431 if (stats.isQuotaSupported(filesUuid)) { 432 sm.allocateBytes(filesUuid, clear2); 433 } else { 434 UiDevice.getInstance(getInstrumentation()) 435 .executeShellCommand("pm trim-caches " + clear2 + " " + pmUuid); 436 } 437 438 assertMostlyEquals(targetA / 2, getCacheBytes(PKG_A, user), 2 * MB_IN_BYTES); 439 assertMostlyEquals(targetA / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES); 440 } 441 testCacheBehavior(int[] originalCacheReservePercents)442 private void testCacheBehavior(int[] originalCacheReservePercents) throws Exception { 443 final Context context = getContext(); 444 final StorageManager sm = context.getSystemService(StorageManager.class); 445 final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); 446 447 final UUID filesUuid = sm.getUuidForPath(context.getFilesDir()); 448 final String pmUuid = filesUuid.equals(StorageManager.UUID_DEFAULT) ? "internal" 449 : filesUuid.toString(); 450 451 final File normal = new File(context.getCacheDir(), "normal"); 452 final File group = new File(context.getCacheDir(), "group"); 453 final File tomb = new File(context.getCacheDir(), "tomb"); 454 455 final long size = 2 * MB_IN_BYTES; 456 457 final long normalTime = 1262304000; 458 final long groupTime = 1262303000; 459 final long tombTime = 1262302000; 460 461 normal.mkdir(); 462 group.mkdir(); 463 tomb.mkdir(); 464 465 sm.setCacheBehaviorGroup(group, true); 466 sm.setCacheBehaviorTombstone(tomb, true); 467 468 final File a = useFallocate(makeUniqueFile(normal), size, normalTime); 469 final File b = useFallocate(makeUniqueFile(normal), size, normalTime); 470 final File c = useFallocate(makeUniqueFile(normal), size, normalTime); 471 472 final File d = useFallocate(makeUniqueFile(group), size, groupTime); 473 final File e = useFallocate(makeUniqueFile(group), size, groupTime); 474 final File f = useFallocate(makeUniqueFile(group), size, groupTime); 475 476 final File g = useFallocate(makeUniqueFile(tomb), size, tombTime); 477 final File h = useFallocate(makeUniqueFile(tomb), size, tombTime); 478 final File i = useFallocate(makeUniqueFile(tomb), size, tombTime); 479 480 normal.setLastModified(normalTime); 481 group.setLastModified(groupTime); 482 tomb.setLastModified(tombTime); 483 484 final long clear1 = group.getUsableSpace() + (8 * MB_IN_BYTES); 485 if (stats.isQuotaSupported(filesUuid)) { 486 sm.allocateBytes(filesUuid, clear1); 487 } else { 488 UiDevice.getInstance(getInstrumentation()) 489 .executeShellCommand("pm trim-caches " + clear1 + " " + pmUuid); 490 } 491 492 assertTrue(a.exists()); 493 assertTrue(b.exists()); 494 assertTrue(c.exists()); 495 assertFalse(group.exists()); 496 assertFalse(d.exists()); 497 assertFalse(e.exists()); 498 assertFalse(f.exists()); 499 assertTrue(g.exists()); assertEquals(0, g.length()); 500 assertTrue(h.exists()); assertEquals(0, h.length()); 501 assertTrue(i.exists()); assertEquals(0, i.length()); 502 } 503 504 /* originalCacheReservePercents is an array of size 2 with CacheReservePercentHigh 505 * at index 0 and CacheReservePercentLow at index 1. 506 */ setCacheReservePercentsToZero(int[] originalCacheReservePercents)507 private void setCacheReservePercentsToZero(int[] originalCacheReservePercents) { 508 SystemUtil.runWithShellPermissionIdentity(() -> { 509 originalCacheReservePercents[0] = DeviceConfig.getInt( 510 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 511 StorageManager.CACHE_RESERVE_PERCENT_HIGH_KEY, -1); 512 DeviceConfig.setProperty( 513 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 514 StorageManager.CACHE_RESERVE_PERCENT_HIGH_KEY, 515 Integer.toString(0), /* makeDefault */ false); 516 originalCacheReservePercents[1] = DeviceConfig.getInt( 517 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 518 StorageManager.CACHE_RESERVE_PERCENT_LOW_KEY, -1); 519 DeviceConfig.setProperty( 520 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 521 StorageManager.CACHE_RESERVE_PERCENT_LOW_KEY, 522 Integer.toString(0), /* makeDefault */ false); 523 }); 524 } 525 resetCacheReservePercents(int[] originalCacheReservePercents)526 private void resetCacheReservePercents(int[] originalCacheReservePercents) { 527 SystemUtil.runWithShellPermissionIdentity(() -> { 528 DeviceConfig.setProperty( 529 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 530 StorageManager.CACHE_RESERVE_PERCENT_HIGH_KEY, 531 (originalCacheReservePercents[0] != -1) 532 ? Integer.toString(originalCacheReservePercents[0]) : null, 533 /* makeDefault */ false); 534 DeviceConfig.setProperty( 535 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 536 StorageManager.CACHE_RESERVE_PERCENT_LOW_KEY, 537 (originalCacheReservePercents[1] != -1) 538 ? Integer.toString(originalCacheReservePercents[1]) : null, 539 /* makeDefault */ false); 540 }); 541 } 542 getCacheBytes(String pkg, UserHandle user)543 private long getCacheBytes(String pkg, UserHandle user) throws Exception { 544 return getContext().getSystemService(StorageStatsManager.class) 545 .queryStatsForPackage(UUID_DEFAULT, pkg, user).getCacheBytes(); 546 } 547 doAllocateReceiver(String pkg, double fraction, long time)548 private long doAllocateReceiver(String pkg, double fraction, long time) throws Exception { 549 final CountDownLatch latch = new CountDownLatch(1); 550 final Intent intent = new Intent(); 551 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 552 intent.setComponent(new ComponentName(pkg, UtilsReceiver.class.getName())); 553 intent.putExtra(UtilsReceiver.EXTRA_FRACTION, fraction); 554 intent.putExtra(UtilsReceiver.EXTRA_TIME, time); 555 final MutableLong bytes = new MutableLong(0); 556 getInstrumentation().getTargetContext().sendOrderedBroadcast(intent, null, 557 new BroadcastReceiver() { 558 @Override 559 public void onReceive(Context context, Intent intent) { 560 bytes.value = getResultExtras(false).getLong(UtilsReceiver.EXTRA_BYTES); 561 latch.countDown(); 562 } 563 }, null, Activity.RESULT_CANCELED, null, null); 564 latch.await(30, TimeUnit.SECONDS); 565 return bytes.value; 566 } 567 doAllocateProvider(String pkg, double fraction, long time)568 private long doAllocateProvider(String pkg, double fraction, long time) throws Exception { 569 final Bundle args = new Bundle(); 570 args.putDouble(UtilsReceiver.EXTRA_FRACTION, fraction); 571 args.putLong(UtilsReceiver.EXTRA_TIME, time); 572 573 try (final ContentProviderClient client = getContext().getContentResolver() 574 .acquireContentProviderClient(pkg)) { 575 final Bundle res = client.call(pkg, pkg, args); 576 return res.getLong(UtilsReceiver.EXTRA_BYTES); 577 } 578 } 579 getSizeOfFilesEndWith(File dir, String suffix)580 private long getSizeOfFilesEndWith(File dir, String suffix) { 581 if (!dir.isDirectory()) { 582 return 0; 583 } 584 585 long size = 0; 586 try { 587 for (File file : dir.listFiles()) { 588 if (file.isFile() && file.getName().endsWith(suffix)) { 589 size += file.length(); 590 } 591 } 592 } catch (NullPointerException e) { 593 size += 0; 594 } 595 596 return size; 597 } 598 getSizeOfDir(File dir)599 private long getSizeOfDir(File dir) { 600 if (!dir.isDirectory()) { 601 return 0; 602 } 603 604 long size = 0; 605 try { 606 for (File file : dir.listFiles()) { 607 if (file.isFile()) { 608 size += file.length(); 609 } else if (file.isDirectory()) { 610 size += getSizeOfDir(file); 611 } 612 } 613 } catch (NullPointerException e) { 614 size += 0; 615 } 616 617 return size; 618 } 619 } 620