diff options
author | Jeff Sharkey <jsharkey@android.com> | 2014-10-16 14:40:23 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2014-10-16 14:40:25 -0700 |
commit | e24609e8f2aada5cb8ac1c3e93141b260e201efe (patch) | |
tree | ed8b091087e78fcd6101f3f40fb66422dfe03a2f /src/com/android | |
parent | e8175658d3a16a3fd8c60a9c6760268e74d0b81f (diff) | |
download | android_packages_providers_DownloadProvider-e24609e8f2aada5cb8ac1c3e93141b260e201efe.tar.gz android_packages_providers_DownloadProvider-e24609e8f2aada5cb8ac1c3e93141b260e201efe.tar.bz2 android_packages_providers_DownloadProvider-e24609e8f2aada5cb8ac1c3e93141b260e201efe.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
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/providers/downloads/DownloadIdleService.java | 52 |
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); |