summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2014-10-16 14:40:23 -0700
committerThe Android Automerger <android-build@google.com>2014-10-16 15:34:43 -0700
commita04e9d0a00622f67bcc0d5a25229d0344259e0ba (patch)
treeed8b091087e78fcd6101f3f40fb66422dfe03a2f
parente8175658d3a16a3fd8c60a9c6760268e74d0b81f (diff)
downloadandroid_packages_providers_DownloadProvider-a04e9d0a00622f67bcc0d5a25229d0344259e0ba.tar.gz
android_packages_providers_DownloadProvider-a04e9d0a00622f67bcc0d5a25229d0344259e0ba.tar.bz2
android_packages_providers_DownloadProvider-a04e9d0a00622f67bcc0d5a25229d0344259e0ba.zip
Trim stale downloads from third-party apps.
Buggy third-party apps can enqueue lots of downloads and then forget to remove them, causing DownloadManager to stop functioning. This change removes any downloads that match _all_ of the following conditions: 1. Download status is in a terminal (non-pending) state, usually a concrete success or failure. 2. Download hasn't been touched in over a week. 3. Download is not visible in UI. Bug: 17785419 Change-Id: Id82752fd6935371c1af682205d35f7ba35169473
-rw-r--r--src/com/android/providers/downloads/DownloadIdleService.java52
1 files changed, 47 insertions, 5 deletions
diff --git a/src/com/android/providers/downloads/DownloadIdleService.java b/src/com/android/providers/downloads/DownloadIdleService.java
index ddfeba41..b5371552 100644
--- a/src/com/android/providers/downloads/DownloadIdleService.java
+++ b/src/com/android/providers/downloads/DownloadIdleService.java
@@ -29,6 +29,7 @@ import android.os.Environment;
import android.provider.Downloads;
import android.system.ErrnoException;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.Slog;
import com.android.providers.downloads.StorageUtils.ConcreteFile;
@@ -57,10 +58,11 @@ public class DownloadIdleService extends JobService {
@Override
public void run() {
+ cleanStale();
cleanOrphans();
jobFinished(mParams, false);
}
- };
+ }
@Override
public boolean onStartJob(JobParameters params) {
@@ -75,7 +77,47 @@ public class DownloadIdleService extends JobService {
return false;
}
- private interface DownloadQuery {
+ private interface StaleQuery {
+ final String[] PROJECTION = new String[] {
+ Downloads.Impl._ID,
+ Downloads.Impl.COLUMN_STATUS,
+ Downloads.Impl.COLUMN_LAST_MODIFICATION,
+ Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI };
+
+ final int _ID = 0;
+ }
+
+ /**
+ * Remove stale downloads that third-party apps probably forgot about. We
+ * only consider non-visible downloads that haven't been touched in over a
+ * week.
+ */
+ public void cleanStale() {
+ final ContentResolver resolver = getContentResolver();
+
+ final long modifiedBefore = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
+ final Cursor cursor = resolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
+ StaleQuery.PROJECTION, Downloads.Impl.COLUMN_STATUS + " >= '200' AND "
+ + Downloads.Impl.COLUMN_LAST_MODIFICATION + " <= '" + modifiedBefore
+ + "' AND " + Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + " == '0'",
+ null, null);
+
+ int count = 0;
+ try {
+ while (cursor.moveToNext()) {
+ final long id = cursor.getLong(StaleQuery._ID);
+ resolver.delete(ContentUris.withAppendedId(
+ Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id), null, null);
+ count++;
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ Slog.d(TAG, "Removed " + count + " stale downloads");
+ }
+
+ private interface OrphanQuery {
final String[] PROJECTION = new String[] {
Downloads.Impl._ID,
Downloads.Impl._DATA };
@@ -93,10 +135,10 @@ public class DownloadIdleService extends JobService {
// Collect known files from database
final HashSet<ConcreteFile> fromDb = Sets.newHashSet();
final Cursor cursor = resolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
- DownloadQuery.PROJECTION, null, null, null);
+ OrphanQuery.PROJECTION, null, null, null);
try {
while (cursor.moveToNext()) {
- final String path = cursor.getString(DownloadQuery._DATA);
+ final String path = cursor.getString(OrphanQuery._DATA);
if (TextUtils.isEmpty(path)) continue;
final File file = new File(path);
@@ -111,7 +153,7 @@ public class DownloadIdleService extends JobService {
// currently mounted device, so remove it from database.
// This logic preserves files on external storage while
// media is removed.
- final long id = cursor.getLong(DownloadQuery._ID);
+ final long id = cursor.getLong(OrphanQuery._ID);
Slog.d(TAG, "Missing " + file + ", deleting " + id);
resolver.delete(ContentUris.withAppendedId(
Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id), null, null);