summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/module-lib-current.txt1
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/os/storage/StorageManager.java83
-rw-r--r--core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java49
4 files changed, 117 insertions, 17 deletions
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 70bb13a36b6e..ba34ce433ac6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -341,6 +341,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
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c4b20117b5b8..96374fbd05fa 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -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);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 77c794cd17a8..e52cd5aa6cff 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1434,11 +1434,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);
@@ -1462,7 +1487,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,
@@ -1472,28 +1497,54 @@ public class StorageManager {
}
/**
+ * 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);
}
}
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
index 16dcff5e0c8c..7ccbb0150cb6 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -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,12 +130,50 @@ 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
*
* @param name The name of the OBB file we want to create/write to
@@ -526,4 +573,4 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
doValidateIntContents(path + File.separator + "subdir2" + File.separator + "subdir2a"
+ File.separator + "subdir2a1", "OneToOneThousandInts", 0, 1000);
}
-} \ No newline at end of file
+}