diff options
author | Vasu Nori <vnori@google.com> | 2010-12-16 18:31:23 -0800 |
---|---|---|
committer | Vasu Nori <vnori@google.com> | 2010-12-23 13:28:32 -0800 |
commit | 5218d33d57990c3e3549c58bd3f0ac244dfc3d59 (patch) | |
tree | 4c7f740b3eadf7ed34515b47c36827251aac2e34 /src/com/android/providers/downloads/Helpers.java | |
parent | 6bf8b8d183ef3fa118ad9fb8eb35c2ee101e46a1 (diff) | |
download | android_packages_providers_DownloadProvider-5218d33d57990c3e3549c58bd3f0ac244dfc3d59.tar.gz android_packages_providers_DownloadProvider-5218d33d57990c3e3549c58bd3f0ac244dfc3d59.tar.bz2 android_packages_providers_DownloadProvider-5218d33d57990c3e3549c58bd3f0ac244dfc3d59.zip |
bug:3286430 set quota on downloads data dir
make sure the doanloads data dir size is limited by some quote -
100MB default and 200MB for SR.
bug:3286430
tests are in Change-Id: I688f7e058511089bec7fa21e972e23780604d98a
Change-Id: Iba7fab9fa91ea018f35e1c3ef5ec0e6b03cba650
Diffstat (limited to 'src/com/android/providers/downloads/Helpers.java')
-rw-r--r-- | src/com/android/providers/downloads/Helpers.java | 224 |
1 files changed, 17 insertions, 207 deletions
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java index f392f3e9..a9c48beb 100644 --- a/src/com/android/providers/downloads/Helpers.java +++ b/src/com/android/providers/downloads/Helpers.java @@ -16,16 +16,13 @@ package com.android.providers.downloads; -import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.database.Cursor; import android.drm.mobile1.DrmRawContent; import android.net.Uri; import android.os.Environment; -import android.os.StatFs; import android.os.SystemClock; import android.provider.Downloads; import android.util.Config; @@ -42,7 +39,6 @@ import java.util.regex.Pattern; * Some helper functions for the download manager */ public class Helpers { - public static Random sRandom = new Random(SystemClock.uptimeMillis()); /** Regex used to parse content-disposition headers */ @@ -71,22 +67,9 @@ public class Helpers { } /** - * Exception thrown from methods called by generateSaveFile() for any fatal error. - */ - public static class GenerateSaveFileError extends Exception { - int mStatus; - String mMessage; - - public GenerateSaveFileError(int status, String message) { - mStatus = status; - mMessage = message; - } - } - - /** * Creates a filename (where the file should be saved) from info about a download. */ - public static String generateSaveFile( + static String generateSaveFile( Context context, String url, String hint, @@ -95,64 +78,24 @@ public class Helpers { String mimeType, int destination, long contentLength, - boolean isPublicApi) throws GenerateSaveFileError { + boolean isPublicApi, StorageManager storageManager) throws StopRequestException { checkCanHandleDownload(context, mimeType, destination, isPublicApi); + String path; + File base = null; if (destination == Downloads.Impl.DESTINATION_FILE_URI) { - String path = verifyFileUri(context, hint, contentLength); - String c = getFullPath(path, mimeType, destination, null); - return c; + path = Uri.parse(hint).getPath(); } else { - return chooseFullPath(context, url, hint, contentDisposition, contentLocation, mimeType, - destination, contentLength); + base = storageManager.locateDestinationDirectory(mimeType, destination, + contentLength); + path = chooseFilename(url, hint, contentDisposition, contentLocation, + destination); } - } - - private static String verifyFileUri(Context context, String hint, long contentLength) - throws GenerateSaveFileError { - if (!isExternalMediaMounted()) { - throw new GenerateSaveFileError(Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR, - "external media not mounted"); - } - String path = Uri.parse(hint).getPath(); - if (getAvailableBytes(getFilesystemRoot(context, path)) < contentLength) { - throw new GenerateSaveFileError(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR, - "insufficient space on external storage"); - } - - return path; - } - - /** - * @return the root of the filesystem containing the given path - */ - static File getFilesystemRoot(Context context, String path) { - File cache = Environment.getDownloadCacheDirectory(); - if (path.startsWith(cache.getPath())) { - return cache; - } - File systemCache = Helpers.getDownloadsDataDirectory(context); - if (path.startsWith(systemCache.getPath())) { - return systemCache; - } - File external = Environment.getExternalStorageDirectory(); - if (path.startsWith(external.getPath())) { - return external; - } - throw new IllegalArgumentException("Cannot determine filesystem root for " + path); - } - - private static String chooseFullPath(Context context, String url, String hint, - String contentDisposition, String contentLocation, - String mimeType, int destination, long contentLength) - throws GenerateSaveFileError { - File base = locateDestinationDirectory(context, mimeType, destination, contentLength); - String filename = chooseFilename(url, hint, contentDisposition, contentLocation, - destination); - return getFullPath(filename, mimeType, destination, base); + storageManager.verifySpace(destination, path, contentLength); + return getFullPath(path, mimeType, destination, base); } private static String getFullPath(String filename, String mimeType, int destination, - File base) throws GenerateSaveFileError { + File base) throws StopRequestException { // Split filename between base and extension // Add an extension if filename does not have one String extension = null; @@ -178,7 +121,7 @@ public class Helpers { } private static void checkCanHandleDownload(Context context, String mimeType, int destination, - boolean isPublicApi) throws GenerateSaveFileError { + boolean isPublicApi) throws StopRequestException { if (isPublicApi) { return; } @@ -186,7 +129,7 @@ public class Helpers { if (destination == Downloads.Impl.DESTINATION_EXTERNAL || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) { if (mimeType == null) { - throw new GenerateSaveFileError(Downloads.Impl.STATUS_NOT_ACCEPTABLE, + throw new StopRequestException(Downloads.Impl.STATUS_NOT_ACCEPTABLE, "external download with no mime type not allowed"); } if (!DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) { @@ -211,92 +154,13 @@ public class Helpers { if (Constants.LOGV) { Log.v(Constants.TAG, "no handler found for type " + mimeType); } - throw new GenerateSaveFileError(Downloads.Impl.STATUS_NOT_ACCEPTABLE, + throw new StopRequestException(Downloads.Impl.STATUS_NOT_ACCEPTABLE, "no handler found for this download type"); } } } } - private static File locateDestinationDirectory(Context context, String mimeType, - int destination, long contentLength) - throws GenerateSaveFileError { - // DRM messages should be temporarily stored internally and then passed to - // the DRM content provider - if (destination == Downloads.Impl.DESTINATION_CACHE_PARTITION - || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE - || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING - || destination == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION - || DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) { - return getCacheDestination(context, contentLength, destination); - } - - return getExternalDestination(contentLength); - } - - private static File getExternalDestination(long contentLength) throws GenerateSaveFileError { - if (!isExternalMediaMounted()) { - throw new GenerateSaveFileError(Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR, - "external media not mounted"); - } - - File root = Environment.getExternalStorageDirectory(); - if (getAvailableBytes(root) < contentLength) { - // Insufficient space. - Log.d(Constants.TAG, "download aborted - not enough free space"); - throw new GenerateSaveFileError(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR, - "insufficient space on external media"); - } - - File base = new File(root.getPath() + Constants.DEFAULT_DL_SUBDIR); - if (!base.isDirectory() && !base.mkdir()) { - // Can't create download directory, e.g. because a file called "download" - // already exists at the root level, or the SD card filesystem is read-only. - throw new GenerateSaveFileError(Downloads.Impl.STATUS_FILE_ERROR, - "unable to create external downloads directory " + base.getPath()); - } - return base; - } - - public static boolean isExternalMediaMounted() { - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - // No SD card found. - Log.d(Constants.TAG, "no external storage"); - return false; - } - return true; - } - - private static File getCacheDestination(Context context, long contentLength, int destination) - throws GenerateSaveFileError { - File base; - base = (destination == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) ? - Environment.getDownloadCacheDirectory() : - Helpers.getDownloadsDataDirectory(context); - long bytesAvailable = getAvailableBytes(base); - while (bytesAvailable < contentLength) { - // Insufficient space; try discarding purgeable files. - if (!discardPurgeableFiles(destination, context, contentLength - bytesAvailable)) { - // No files to purge, give up. - throw new GenerateSaveFileError(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR, - "not enough free space in internal download storage: " + base + - ", unable to free any more"); - } - bytesAvailable = getAvailableBytes(base); - } - return base; - } - - /** - * @return the number of bytes available on the filesystem rooted at the given File - */ - public static long getAvailableBytes(File root) { - StatFs stat = new StatFs(root.getPath()); - // put a bit of margin (in case creating the file grows the system by a few blocks) - long availableBlocks = (long) stat.getAvailableBlocks() - 4; - return stat.getBlockSize() * availableBlocks; - } - private static String chooseFilename(String url, String hint, String contentDisposition, String contentLocation, int destination) { String filename = null; @@ -445,7 +309,7 @@ public class Helpers { } private static String chooseUniqueFilename(int destination, String filename, - String extension, boolean recoveryDir) throws GenerateSaveFileError { + String extension, boolean recoveryDir) throws StopRequestException { String fullFilename = filename + extension; if (!new File(fullFilename).exists() && (!recoveryDir || @@ -483,62 +347,11 @@ public class Helpers { sequence += sRandom.nextInt(magnitude) + 1; } } - throw new GenerateSaveFileError(Downloads.Impl.STATUS_FILE_ERROR, + throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR, "failed to generate an unused filename on internal download storage"); } /** - * Deletes purgeable files from the cache partition. This also deletes - * the matching database entries. Files are deleted in LRU order until - * the total byte size is greater than targetBytes. - */ - static final boolean discardPurgeableFiles(int destination, Context context, - long targetBytes) { - String destStr = (destination == Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION) ? - String.valueOf(destination) : - String.valueOf(Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE); - String[] bindArgs = new String[]{destStr}; - Cursor cursor = context.getContentResolver().query( - Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, - null, - "( " + - Downloads.Impl.COLUMN_STATUS + " = '" + Downloads.Impl.STATUS_SUCCESS + "' AND " + - Downloads.Impl.COLUMN_DESTINATION + " = ? )", - bindArgs, - Downloads.Impl.COLUMN_LAST_MODIFICATION); - if (cursor == null) { - return false; - } - long totalFreed = 0; - try { - cursor.moveToFirst(); - while (!cursor.isAfterLast() && totalFreed < targetBytes) { - File file = new File(cursor.getString(cursor.getColumnIndex(Downloads.Impl._DATA))); - if (Constants.LOGVV) { - Log.v(Constants.TAG, "purging " + file.getAbsolutePath() + " for " + - file.length() + " bytes"); - } - totalFreed += file.length(); - file.delete(); - long id = cursor.getLong(cursor.getColumnIndex(Downloads.Impl._ID)); - context.getContentResolver().delete( - ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id), - null, null); - cursor.moveToNext(); - } - } finally { - cursor.close(); - } - if (Constants.LOGV) { - if (totalFreed > 0) { - Log.v(Constants.TAG, "Purged files, freed " + totalFreed + " for " + - targetBytes + " requested"); - } - } - return totalFreed > 0; - } - - /** * Returns whether the network is available */ public static boolean isNetworkAvailable(SystemFacade system) { @@ -864,7 +677,4 @@ public class Helpers { } return sb.toString(); } - static final File getDownloadsDataDirectory(Context context) { - return context.getCacheDir(); - } } |