From 06823d4c2e0fc7d64bff5d3e155d690302e0ab80 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 9 May 2017 16:55:29 -0600 Subject: [PATCH] Use "real" free space; refresh on large changes. For volumes where the OS manages cached data, use the "free space" as reported by StorageStatsManager, which is the same value shown in the Settings app and other UI elements. Also, when the storage space changes significantly, invalidate anyone who was holding a cached "free space" value. Test: builds, boots Bug: 38146029 Change-Id: I4b3a484a8bf32cd137a83f1ea441beca6dc6719a --- .../ExternalStorageProvider.java | 27 +++++++++++++++++-- .../server/usage/StorageStatsService.java | 11 ++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index b958c28730198..f844cc163bbe9 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -17,6 +17,7 @@ package com.android.externalstorage; import android.annotation.Nullable; +import android.app.usage.StorageStatsManager; import android.content.ContentResolver; import android.content.Context; import android.content.UriPermission; @@ -49,10 +50,12 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintWriter; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.UUID; public class ExternalStorageProvider extends FileSystemProvider { private static final String TAG = "ExternalStorage"; @@ -79,6 +82,7 @@ public class ExternalStorageProvider extends FileSystemProvider { private static class RootInfo { public String rootId; public String volumeId; + public UUID storageUuid; public int flags; public String title; public String docId; @@ -124,6 +128,7 @@ public class ExternalStorageProvider extends FileSystemProvider { final String rootId; final String title; + final UUID storageUuid; if (volume.getType() == VolumeInfo.TYPE_EMULATED) { // We currently only support a single emulated volume mounted at // a time, and it's always considered the primary @@ -142,17 +147,20 @@ public class ExternalStorageProvider extends FileSystemProvider { title = !TextUtils.isEmpty(deviceName) ? deviceName : getContext().getString(R.string.root_internal_storage); + storageUuid = StorageManager.UUID_DEFAULT; } else { // This should cover all other storage devices, like an SD card // or USB OTG drive plugged in. Using getBestVolumeDescription() // will give us a nice string like "Samsung SD card" or "SanDisk USB drive" final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume); title = mStorageManager.getBestVolumeDescription(privateVol); + storageUuid = StorageManager.convert(privateVol.fsUuid); } } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC && volume.getMountUserId() == userId) { rootId = volume.getFsUuid(); title = mStorageManager.getBestVolumeDescription(volume); + storageUuid = null; } else { // Unsupported volume; ignore continue; @@ -172,6 +180,7 @@ public class ExternalStorageProvider extends FileSystemProvider { root.rootId = rootId; root.volumeId = volume.id; + root.storageUuid = storageUuid; root.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD; @@ -385,8 +394,22 @@ public class ExternalStorageProvider extends FileSystemProvider { row.add(Root.COLUMN_FLAGS, root.flags); row.add(Root.COLUMN_TITLE, root.title); row.add(Root.COLUMN_DOCUMENT_ID, root.docId); - row.add(Root.COLUMN_AVAILABLE_BYTES, - root.reportAvailableBytes ? root.path.getUsableSpace() : -1); + + long availableBytes = -1; + if (root.reportAvailableBytes) { + if (root.storageUuid != null) { + try { + availableBytes = getContext() + .getSystemService(StorageStatsManager.class) + .getFreeBytes(root.storageUuid); + } catch (IOException e) { + Log.w(TAG, e); + } + } else { + availableBytes = root.path.getUsableSpace(); + } + } + row.add(Root.COLUMN_AVAILABLE_BYTES, availableBytes); } } return result; diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index dae74db85b2e9..16b73d5515e5d 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageStats; import android.content.pm.UserInfo; import android.net.TrafficStats; +import android.net.Uri; import android.os.Binder; import android.os.Environment; import android.os.FileUtils; @@ -467,6 +468,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { if (bytesDelta > mMinimumThresholdBytes) { mPreviousBytes = mStats.getAvailableBytes(); recalculateQuotas(getInitializedStrategy()); + notifySignificantDelta(); } sendEmptyMessageDelayed(MSG_CHECK_STORAGE_DELTA, DELAY_IN_MILLIS); break; @@ -518,4 +520,13 @@ public class StorageStatsService extends IStorageStatsManager.Stub { return Settings.Global.getInt( resolver, Settings.Global.ENABLE_CACHE_QUOTA_CALCULATION, 1) != 0; } + + /** + * Hacky way of notifying that disk space has changed significantly; we do + * this to cause "available space" values to be requeried. + */ + void notifySignificantDelta() { + mContext.getContentResolver().notifyChange( + Uri.parse("content://com.android.externalstorage.documents/"), null, false); + } }