Merge "Change reserved cache space as sum of cache quotas of all uids"

This commit is contained in:
Neharika Jali
2021-12-16 05:57:46 +00:00
committed by Android (Google) Code Review
4 changed files with 117 additions and 17 deletions

View File

@@ -349,6 +349,7 @@ package android.os {
package android.os.storage {
public class StorageManager {
method public long computeStorageCacheBytes(@NonNull java.io.File);
method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 1; // 0x1

View File

@@ -1976,6 +1976,7 @@ package android.os.storage {
}
public class StorageManager {
method public long computeStorageCacheBytes(@NonNull java.io.File);
method @NonNull public static java.util.UUID convert(@NonNull String);
method @NonNull public static String convert(@NonNull java.util.UUID);
method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);

View File

@@ -1437,11 +1437,36 @@ public class StorageManager {
throw new IllegalStateException("Missing primary storage");
}
private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;
private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
/**
* Devices having above STORAGE_THRESHOLD_PERCENT_HIGH of total space free are considered to be
* in high free space category.
*
* @hide
*/
public static final int STORAGE_THRESHOLD_PERCENT_HIGH = 20;
/**
* Devices having below STORAGE_THRESHOLD_PERCENT_LOW of total space free are considered to be
* in low free space category.
*
* @hide
*/
public static final int STORAGE_THRESHOLD_PERCENT_LOW = 5;
/**
* For devices in high free space category, CACHE_RESERVE_PERCENT_HIGH percent of total space is
* allocated for cache.
*
* @hide
*/
public static final int CACHE_RESERVE_PERCENT_HIGH = 10;
/**
* For devices in low free space category, CACHE_RESERVE_PERCENT_LOW percent of total space is
* allocated for cache.
*
* @hide
*/
public static final int CACHE_RESERVE_PERCENT_LOW = 2;
private static final int DEFAULT_CACHE_PERCENTAGE = 10;
private static final long DEFAULT_CACHE_MAX_BYTES = DataUnit.GIBIBYTES.toBytes(5);
private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
@@ -1465,7 +1490,7 @@ public class StorageManager {
@UnsupportedAppUsage
public long getStorageLowBytes(File path) {
final long lowPercent = Settings.Global.getInt(mResolver,
Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, STORAGE_THRESHOLD_PERCENT_LOW);
final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
final long maxLowBytes = Settings.Global.getLong(mResolver,
@@ -1474,29 +1499,55 @@ public class StorageManager {
return Math.min(lowBytes, maxLowBytes);
}
/**
* Compute the minimum number of bytes of storage on the device that could
* be reserved for cached data depending on the device state which is then passed on
* to getStorageCacheBytes.
*
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
@SuppressLint("StreamFiles")
public long computeStorageCacheBytes(@NonNull File path) {
final long totalBytes = path.getTotalSpace();
final long usableBytes = path.getUsableSpace();
final long storageThresholdHighBytes = totalBytes * STORAGE_THRESHOLD_PERCENT_HIGH / 100;
final long storageThresholdLowBytes = getStorageLowBytes(path);
long result;
if (usableBytes > storageThresholdHighBytes) {
// If free space is >STORAGE_THRESHOLD_PERCENT_HIGH of total space,
// reserve CACHE_RESERVE_PERCENT_HIGH of total space
result = totalBytes * CACHE_RESERVE_PERCENT_HIGH / 100;
} else if (usableBytes < storageThresholdLowBytes) {
// If free space is <min(STORAGE_THRESHOLD_PERCENT_LOW of total space, 500MB),
// reserve CACHE_RESERVE_PERCENT_LOW of total space
result = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100;
} else {
// Else, linearly interpolate the amount of space to reserve
result = ((CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW)
* (usableBytes - storageThresholdHighBytes) + CACHE_RESERVE_PERCENT_HIGH
* (storageThresholdHighBytes - storageThresholdLowBytes)) * totalBytes
/ (100 * (storageThresholdHighBytes - storageThresholdLowBytes));
}
return result;
}
/**
* Return the minimum number of bytes of storage on the device that should
* be reserved for cached data.
*
* @hide
*/
public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
final long cachePercent = Settings.Global.getInt(mResolver,
Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
final long maxCacheBytes = Settings.Global.getLong(mResolver,
Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
final long result = Math.min(cacheBytes, maxCacheBytes);
public long getStorageCacheBytes(@NonNull File path, @AllocateFlags int flags) {
if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
return 0;
} else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
return 0;
} else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
return result / 2;
return computeStorageCacheBytes(path) / 2;
} else {
return result;
return computeStorageCacheBytes(path);
}
}

View File

@@ -16,6 +16,10 @@
package android.os.storage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.test.InstrumentationTestCase;
@@ -23,6 +27,10 @@ import android.util.Log;
import libcore.io.Streams;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
@@ -39,6 +47,7 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
protected Context mContext = null;
protected StorageManager mSm = null;
@Mock private File mFile;
private static String LOG_TAG = "StorageManagerBaseTest";
protected static final long MAX_WAIT_TIME = 120*1000;
protected static final long WAIT_TIME_INCR = 5*1000;
@@ -121,11 +130,49 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
*/
@Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = getInstrumentation().getContext();
mSm = (StorageManager)mContext.getSystemService(android.content.Context.STORAGE_SERVICE);
}
/**
* Tests the space reserved for cache when system has high free space i.e. more than
* StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space.
*/
@Test
public void testGetStorageCacheBytesUnderHighStorage() throws Exception {
when(mFile.getUsableSpace()).thenReturn(10000L);
when(mFile.getTotalSpace()).thenReturn(15000L);
long result = mSm.getStorageCacheBytes(mFile, 0);
assertThat(result).isEqualTo(1500L);
}
/**
* Tests the space reserved for cache when system has low free space i.e. less than
* StorageManager.STORAGE_THRESHOLD_PERCENT_LOW of total space.
*/
@Test
public void testGetStorageCacheBytesUnderLowStorage() throws Exception {
when(mFile.getUsableSpace()).thenReturn(10000L);
when(mFile.getTotalSpace()).thenReturn(250000L);
long result = mSm.getStorageCacheBytes(mFile, 0);
assertThat(result).isEqualTo(5000L);
}
/**
* Tests the space reserved for cache when system has moderate free space i.e.more than
* StorageManager.STORAGE_THRESHOLD_PERCENT_LOW of total space but less than
* StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space.
*/
@Test
public void testGetStorageCacheBytesUnderModerateStorage() throws Exception {
when(mFile.getUsableSpace()).thenReturn(10000L);
when(mFile.getTotalSpace()).thenReturn(100000L);
long result = mSm.getStorageCacheBytes(mFile, 0);
assertThat(result).isEqualTo(4666L);
}
/**
* Creates an OBB file (with the given name), into the app's standard files directory
*
@@ -526,4 +573,4 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
doValidateIntContents(path + File.separator + "subdir2" + File.separator + "subdir2a"
+ File.separator + "subdir2a1", "OneToOneThousandInts", 0, 1000);
}
}
}