summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-03-01 11:18:38 -0800
committerJeff Sharkey <jsharkey@android.com>2013-03-01 11:18:40 -0800
commit5ba69740a47857fcebd36866e07963ba798269d5 (patch)
tree676f2501844882633a9b9f14324397cb8a8411c8 /src
parent80a535d83ea9ed21f443fdc701c743569ae53eec (diff)
downloadandroid_packages_providers_DownloadProvider-5ba69740a47857fcebd36866e07963ba798269d5.tar.gz
android_packages_providers_DownloadProvider-5ba69740a47857fcebd36866e07963ba798269d5.tar.bz2
android_packages_providers_DownloadProvider-5ba69740a47857fcebd36866e07963ba798269d5.zip
Fix race conditions around filename claiming.
When multiple downloads are running in parallel, they can end up claiming the same filename and clobber over each other. This change introduces locking around filename generation, and touches the claimed filename so other threads fail the File.exists() check and keep looking. Tests to verify. Bug: 8255596 Change-Id: Ie75ed047c199cf679832c75159056ca036eac18d
Diffstat (limited to 'src')
-rw-r--r--src/com/android/providers/downloads/Helpers.java30
1 files changed, 20 insertions, 10 deletions
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 593e28b8..33205557 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -17,10 +17,6 @@
package com.android.providers.downloads;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Environment;
import android.os.SystemClock;
@@ -29,6 +25,7 @@ import android.util.Log;
import android.webkit.MimeTypeMap;
import java.io.File;
+import java.io.IOException;
import java.util.Random;
import java.util.Set;
import java.util.regex.Matcher;
@@ -44,6 +41,8 @@ public class Helpers {
private static final Pattern CONTENT_DISPOSITION_PATTERN =
Pattern.compile("attachment;\\s*filename\\s*=\\s*\"([^\"]*)\"");
+ private static final Object sUniqueLock = new Object();
+
private Helpers() {
}
@@ -92,10 +91,10 @@ public class Helpers {
destination);
}
storageManager.verifySpace(destination, path, contentLength);
- path = getFullPath(path, mimeType, destination, base);
if (DownloadDrmHelper.isDrmConvertNeeded(mimeType)) {
path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path);
}
+ path = getFullPath(path, mimeType, destination, base);
return path;
}
@@ -132,7 +131,21 @@ public class Helpers {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "target file: " + filename + extension);
}
- return chooseUniqueFilename(destination, filename, extension, recoveryDir);
+
+ synchronized (sUniqueLock) {
+ final String path = chooseUniqueFilenameLocked(
+ destination, filename, extension, recoveryDir);
+
+ // Claim this filename inside lock to prevent other threads from
+ // clobbering us. We're not paranoid enough to use O_EXCL.
+ try {
+ new File(path).createNewFile();
+ } catch (IOException e) {
+ throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
+ "Failed to create target file " + path, e);
+ }
+ return path;
+ }
}
private static String chooseFilename(String url, String hint, String contentDisposition,
@@ -282,11 +295,8 @@ public class Helpers {
return extension;
}
- private static String chooseUniqueFilename(int destination, String filename,
+ private static String chooseUniqueFilenameLocked(int destination, String filename,
String extension, boolean recoveryDir) throws StopRequestException {
- // TODO: switch to actually creating the file here, otherwise we expose
- // ourselves to race conditions.
-
String fullFilename = filename + extension;
if (!new File(fullFilename).exists()
&& (!recoveryDir ||