summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralukin <alukin@google.com>2024-01-12 07:56:29 +0000
committerAndroid Build Cherrypicker Worker <android-build-cherrypicker-worker@google.com>2024-01-12 07:56:29 +0000
commitf5dd1ea3e2d84fff14087f1d46b3656cdf2307fa (patch)
treef648e17608fb2a5802d966509aecc83dce0d3660
parent2c8bbf1e23f4b531335a4dedca2d8973e3046644 (diff)
downloadbase-f5dd1ea3e2d84fff14087f1d46b3656cdf2307fa.tar.gz
Fix StorageStatsService#getTotalBytes
Fixing getTotalBytes by calling a new API in Vold. 1. Returned the original implementation of rounding logic. Now it only rounds the bytes by increasing the size, and never by decreasing. 2. Returned the original logic for all the device sizes <= 512GB to prevent any potential regressions. 3. For devices with larger capacities now calling vold (one-time call, then the value is stored in memory) to get the block device size. It's a very precise number of bytes, so only doing a small rounding (up to 3GB) to try to bring the totalBytes to a nice-looking value, otherwise just return as is. Should be tested together with a Settings UI fix: I3dcc9698403612f961cf0de41925dcbcb43e260b Verified on multiple devices with storage <= 512GB: b/290892417#comment26. Also verified for 1TB devices: personally and in b/295265657#comment10 Bug: 290892417 Bug: 295358118 Test: verified manually + manually verified calling of new API Test: atest FileUtilsTest Test: atest StorageHostTest (cherry picked from commit be2ec6d958d7be2c798513d2b4cba6c3169e8ec5) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f97e97bfa1dbc0b3bfcd81115b22deb267b36ca7) Merged-In: I01d72ede6c3ac62198d04829866655ba5a92dc45 Change-Id: I01d72ede6c3ac62198d04829866655ba5a92dc45
-rw-r--r--core/java/android/os/FileUtils.java24
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl1
-rw-r--r--core/java/android/os/storage/StorageManager.java9
-rw-r--r--core/tests/coretests/src/android/os/FileUtilsTest.java65
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java13
-rw-r--r--services/usage/java/com/android/server/usage/StorageStatsService.java27
6 files changed, 83 insertions, 56 deletions
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index af09a0662795..5b24dcacbf53 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1294,32 +1294,30 @@ public final class FileUtils {
* Round the given size of a storage device to a nice round power-of-two
* value, such as 256MB or 32GB. This avoids showing weird values like
* "29.5GB" in UI.
- *
- * Some storage devices are still using GiB (powers of 1024) over
- * GB (powers of 1000) measurements and this method takes it into account.
- *
* Round ranges:
* ...
- * [256 GiB + 1; 512 GiB] -> 512 GB
- * [512 GiB + 1; 1 TiB] -> 1 TB
- * [1 TiB + 1; 2 TiB] -> 2 TB
+ * (128 GB; 256 GB] -> 256 GB
+ * (256 GB; 512 GB] -> 512 GB
+ * (512 GB; 1000 GB] -> 1000 GB
+ * (1000 GB; 2000 GB] -> 2000 GB
+ * ...
* etc
*
* @hide
*/
public static long roundStorageSize(long size) {
long val = 1;
- long kiloPow = 1;
- long kibiPow = 1;
- while ((val * kibiPow) < size) {
+ long pow = 1;
+ while ((val * pow) < size) {
val <<= 1;
if (val > 512) {
val = 1;
- kibiPow *= 1024;
- kiloPow *= 1000;
+ pow *= 1000;
}
}
- return val * kiloPow;
+
+ Log.d(TAG, String.format("Rounded bytes from %d to %d", size, val * pow));
+ return val * pow;
}
private static long toBytes(long value, String unit) {
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index bc52744078ea..369a1932e437 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -174,4 +174,5 @@ interface IStorageManager {
boolean isAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 95;
void setCloudMediaProvider(in String authority) = 96;
String getCloudMediaProvider() = 97;
+ long getInternalStorageBlockDeviceSize() = 98;
} \ No newline at end of file
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 80dd48825ba7..ee387e7c284f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1359,6 +1359,15 @@ public class StorageManager {
}
/** {@hide} */
+ public long getInternalStorageBlockDeviceSize() {
+ try {
+ return mStorageManager.getInternalStorageBlockDeviceSize();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
public void mkdirs(File file) {
BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath());
try {
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 394ff0ae9a2e..a0d8183b8da7 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -505,45 +505,32 @@ public class FileUtilsTest {
@Test
public void testRoundStorageSize() throws Exception {
- final long GB1 = DataUnit.GIGABYTES.toBytes(1);
- final long GiB1 = DataUnit.GIBIBYTES.toBytes(1);
- final long GB2 = DataUnit.GIGABYTES.toBytes(2);
- final long GiB2 = DataUnit.GIBIBYTES.toBytes(2);
- final long GiB128 = DataUnit.GIBIBYTES.toBytes(128);
- final long GB256 = DataUnit.GIGABYTES.toBytes(256);
- final long GiB256 = DataUnit.GIBIBYTES.toBytes(256);
- final long GB512 = DataUnit.GIGABYTES.toBytes(512);
- final long GiB512 = DataUnit.GIBIBYTES.toBytes(512);
- final long TB1 = DataUnit.TERABYTES.toBytes(1);
- final long TiB1 = DataUnit.TEBIBYTES.toBytes(1);
- final long TB2 = DataUnit.TERABYTES.toBytes(2);
- final long TiB2 = DataUnit.TEBIBYTES.toBytes(2);
- final long TB4 = DataUnit.TERABYTES.toBytes(4);
- final long TiB4 = DataUnit.TEBIBYTES.toBytes(4);
- final long TB8 = DataUnit.TERABYTES.toBytes(8);
- final long TiB8 = DataUnit.TEBIBYTES.toBytes(8);
-
- assertEquals(GB1, roundStorageSize(GB1 - 1));
- assertEquals(GB1, roundStorageSize(GB1));
- assertEquals(GB1, roundStorageSize(GB1 + 1));
- assertEquals(GB1, roundStorageSize(GiB1 - 1));
- assertEquals(GB1, roundStorageSize(GiB1));
- assertEquals(GB2, roundStorageSize(GiB1 + 1));
- assertEquals(GB2, roundStorageSize(GiB2));
-
- assertEquals(GB256, roundStorageSize(GiB128 + 1));
- assertEquals(GB256, roundStorageSize(GiB256));
- assertEquals(GB512, roundStorageSize(GiB256 + 1));
- assertEquals(GB512, roundStorageSize(GiB512));
- assertEquals(TB1, roundStorageSize(GiB512 + 1));
- assertEquals(TB1, roundStorageSize(TiB1));
- assertEquals(TB2, roundStorageSize(TiB1 + 1));
- assertEquals(TB2, roundStorageSize(TiB2));
- assertEquals(TB4, roundStorageSize(TiB2 + 1));
- assertEquals(TB4, roundStorageSize(TiB4));
- assertEquals(TB8, roundStorageSize(TiB4 + 1));
- assertEquals(TB8, roundStorageSize(TiB8));
- assertEquals(TB1, roundStorageSize(1013077688320L)); // b/268571529
+ final long M256 = DataUnit.MEGABYTES.toBytes(256);
+ final long M512 = DataUnit.MEGABYTES.toBytes(512);
+ final long G1 = DataUnit.GIGABYTES.toBytes(1);
+ final long G2 = DataUnit.GIGABYTES.toBytes(2);
+ final long G32 = DataUnit.GIGABYTES.toBytes(32);
+ final long G64 = DataUnit.GIGABYTES.toBytes(64);
+ final long G512 = DataUnit.GIGABYTES.toBytes(512);
+ final long G1000 = DataUnit.TERABYTES.toBytes(1);
+ final long G2000 = DataUnit.TERABYTES.toBytes(2);
+
+ assertEquals(M256, roundStorageSize(M256 - 1));
+ assertEquals(M256, roundStorageSize(M256));
+ assertEquals(M512, roundStorageSize(M256 + 1));
+ assertEquals(M512, roundStorageSize(M512 - 1));
+ assertEquals(M512, roundStorageSize(M512));
+ assertEquals(G1, roundStorageSize(M512 + 1));
+ assertEquals(G1, roundStorageSize(G1));
+ assertEquals(G2, roundStorageSize(G1 + 1));
+
+ assertEquals(G32, roundStorageSize(G32 - 1));
+ assertEquals(G32, roundStorageSize(G32));
+ assertEquals(G64, roundStorageSize(G32 + 1));
+
+ assertEquals(G512, roundStorageSize(G512 - 1));
+ assertEquals(G1000, roundStorageSize(G512 + 1));
+ assertEquals(G2000, roundStorageSize(G1000 + 1));
}
@Test
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 73dbb86ae7cc..d47573d52767 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -73,8 +73,8 @@ import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
import android.content.res.ObbInfo;
import android.database.ContentObserver;
-import android.media.MediaCodecList;
import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.net.Uri;
import android.os.BatteryManager;
@@ -219,6 +219,8 @@ class StorageManagerService extends IStorageManager.Stub
@GuardedBy("mLock")
private final Set<Integer> mCeStoragePreparedUsers = new ArraySet<>();
+ private volatile long mInternalStorageSize = 0;
+
public static class Lifecycle extends SystemService {
private StorageManagerService mStorageManagerService;
@@ -3479,6 +3481,15 @@ class StorageManagerService extends IStorageManager.Stub
return authority;
}
+ @Override
+ public long getInternalStorageBlockDeviceSize() throws RemoteException {
+ if (mInternalStorageSize == 0) {
+ mInternalStorageSize = mVold.getStorageSize();
+ }
+
+ return mInternalStorageSize;
+ }
+
/**
* Enforces that the caller is the {@link ExternalStorageService}
*
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 0d88a0d485ff..030615fd7527 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -259,7 +259,24 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
// NOTE: No permissions required
if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
- return FileUtils.roundStorageSize(mStorage.getPrimaryStorageSize());
+ // As a safety measure, use the original implementation for the devices
+ // with storage size <= 512GB to prevent any potential regressions
+ final long roundedUserspaceBytes = mStorage.getPrimaryStorageSize();
+ if (roundedUserspaceBytes <= DataUnit.GIGABYTES.toBytes(512)) {
+ return roundedUserspaceBytes;
+ }
+
+ // Since 1TB devices can actually have either 1000GB or 1024GB,
+ // get the block device size and do just a small rounding if any at all
+ final long totalBytes = mStorage.getInternalStorageBlockDeviceSize();
+ final long totalBytesRounded = FileUtils.roundStorageSize(totalBytes);
+ // If the storage size is 997GB-999GB, round it to a 1000GB to show
+ // 1TB in UI instead of 0.99TB. Same for 2TB, 4TB, 8TB etc.
+ if (totalBytesRounded - totalBytes <= DataUnit.GIGABYTES.toBytes(3)) {
+ return totalBytesRounded;
+ } else {
+ return totalBytes;
+ }
} else {
final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
if (vol == null) {
@@ -286,15 +303,19 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
// Free space is usable bytes plus any cached data that we're
// willing to automatically clear. To avoid user confusion, this
// logic should be kept in sync with getAllocatableBytes().
+ long freeBytes;
if (isQuotaSupported(volumeUuid, PLATFORM_PACKAGE_NAME)) {
final long cacheTotal = getCacheBytes(volumeUuid, PLATFORM_PACKAGE_NAME);
final long cacheReserved = mStorage.getStorageCacheBytes(path, 0);
final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
- return path.getUsableSpace() + cacheClearable;
+ freeBytes = path.getUsableSpace() + cacheClearable;
} else {
- return path.getUsableSpace();
+ freeBytes = path.getUsableSpace();
}
+
+ Slog.d(TAG, "getFreeBytes: " + freeBytes);
+ return freeBytes;
} finally {
Binder.restoreCallingIdentity(token);
}