diff options
3 files changed, 62 insertions, 22 deletions
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 69c1295df4f9..5b9205d16898 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -1987,11 +1987,31 @@ public class StorageManager { */ public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2; + /** + * Flag indicating that a disk space check should not take into account + * freeable cached space when determining allocatable space. + * + * Intended for use with {@link #getAllocatableBytes()}. + * @hide + */ + public static final int FLAG_ALLOCATE_NON_CACHE_ONLY = 1 << 3; + + /** + * Flag indicating that a disk space check should only return freeable + * cached space when determining allocatable space. + * + * Intended for use with {@link #getAllocatableBytes()}. + * @hide + */ + public static final int FLAG_ALLOCATE_CACHE_ONLY = 1 << 4; + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = { FLAG_ALLOCATE_AGGRESSIVE, FLAG_ALLOCATE_DEFY_ALL_RESERVED, FLAG_ALLOCATE_DEFY_HALF_RESERVED, + FLAG_ALLOCATE_NON_CACHE_ONLY, + FLAG_ALLOCATE_CACHE_ONLY, }) @Retention(RetentionPolicy.SOURCE) public @interface AllocateFlags {} diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index ad1ff902b7d8..1d81c59a8f89 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -261,8 +261,21 @@ public class PackageHelper { public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException { final StorageManager storage = context.getSystemService(StorageManager.class); final UUID target = storage.getUuidForPath(Environment.getDataDirectory()); - return (params.sizeBytes <= storage.getAllocatableBytes(target, - translateAllocateFlags(params.installFlags))); + final int flags = translateAllocateFlags(params.installFlags); + + final long allocateableBytes = storage.getAllocatableBytes(target, + flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY); + + // If we fit on internal storage without including freeable cache space, don't bother + // checking to determine how much space is taken up by the cache. + if (params.sizeBytes <= allocateableBytes) { + return true; + } + + final long cacheClearable = storage.getAllocatableBytes(target, + flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY); + + return params.sizeBytes <= allocateableBytes + cacheClearable; } public static boolean fitsOnExternal(Context context, SessionParams params) { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index deff7ef7d39a..ddde7fef8962 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3208,28 +3208,28 @@ class StorageManagerService extends IStorageManager.Stub // should be kept in sync with getFreeBytes(). final File path = storage.findPathForUuid(volumeUuid); - final long usable = path.getUsableSpace(); - final long lowReserved = storage.getStorageLowBytes(path); - final long fullReserved = storage.getStorageFullBytes(path); + long usable = 0; + long lowReserved = 0; + long fullReserved = 0; + long cacheClearable = 0; - if (stats.isQuotaSupported(volumeUuid)) { + if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) { + usable = path.getUsableSpace(); + lowReserved = storage.getStorageLowBytes(path); + fullReserved = storage.getStorageFullBytes(path); + } + + if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0 + && stats.isQuotaSupported(volumeUuid)) { final long cacheTotal = stats.getCacheBytes(volumeUuid); final long cacheReserved = storage.getStorageCacheBytes(path, flags); - final long cacheClearable = Math.max(0, cacheTotal - cacheReserved); + cacheClearable = Math.max(0, cacheTotal - cacheReserved); + } - if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { - return Math.max(0, (usable + cacheClearable) - fullReserved); - } else { - return Math.max(0, (usable + cacheClearable) - lowReserved); - } + if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { + return Math.max(0, (usable + cacheClearable) - fullReserved); } else { - // When we don't have fast quota information, we ignore cached - // data and only consider unused bytes. - if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { - return Math.max(0, usable - fullReserved); - } else { - return Math.max(0, usable - lowReserved); - } + return Math.max(0, (usable + cacheClearable) - lowReserved); } } catch (IOException e) { throw new ParcelableException(e); @@ -3242,10 +3242,17 @@ class StorageManagerService extends IStorageManager.Stub public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) { flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage); - final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage); + final long allocatableBytes = getAllocatableBytes(volumeUuid, + flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage); if (bytes > allocatableBytes) { - throw new ParcelableException(new IOException("Failed to allocate " + bytes - + " because only " + allocatableBytes + " allocatable")); + // If we don't have room without taking cache into account, check to see if we'd have + // room if we included freeable cache space. + final long cacheClearable = getAllocatableBytes(volumeUuid, + flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage); + if (bytes > allocatableBytes + cacheClearable) { + throw new ParcelableException(new IOException("Failed to allocate " + bytes + + " because only " + (allocatableBytes + cacheClearable) + " allocatable")); + } } final StorageManager storage = mContext.getSystemService(StorageManager.class); |