summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSudheer Shanka <sudheersai@google.com>2019-01-04 12:10:56 -0800
committerSudheer Shanka <sudheersai@google.com>2019-01-07 15:06:11 -0800
commit6cce72017535474329c9c6ae51d1cc13cadb40da (patch)
tree22eeeb1e052949e5cc404531c0bd711a1e146cc8 /src
parentc93b9b181562bac87ba3082b0a11da3b1e7ac02d (diff)
downloadandroid_packages_providers_DownloadProvider-6cce72017535474329c9c6ae51d1cc13cadb40da.tar.gz
android_packages_providers_DownloadProvider-6cce72017535474329c9c6ae51d1cc13cadb40da.tar.bz2
android_packages_providers_DownloadProvider-6cce72017535474329c9c6ae51d1cc13cadb40da.zip
Query MediaProvider for possibly stale columns in DownloadProvider.
Some of the downloads columns data in DownloadProvider could possibly stale. When these columns gets queried from DownloadProvider, DownloadProvider will query internally query MediaProvider and serve those values. Bug: 120876251 Test: atest DownloadProviderTests Test: atest cts/tests/app/src/android/app/cts/DownloadManagerTest.java Test: atest MediaProviderTests Test: atest cts/tests/tests/provider/src/android/provider/cts/MediaStore* Change-Id: Iaae77646a5f8303aa2a73437fbf28595e7019e6f
Diffstat (limited to 'src')
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java145
1 files changed, 132 insertions, 13 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index 8dc14506..d4468da3 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -62,7 +62,10 @@ import android.provider.MediaStore.Files;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.LongArray;
+import android.util.LongSparseArray;
import com.android.internal.util.IndentingPrintWriter;
@@ -378,12 +381,13 @@ public final class DownloadProvider extends ContentProvider {
final DownloadInfo.Reader reader
= new DownloadInfo.Reader(getContext().getContentResolver(), cursor);
final DownloadInfo info = new DownloadInfo(getContext());
+ final ContentValues updateValues = new ContentValues();
while (cursor.moveToNext()) {
reader.updateFromDatabase(info);
final Uri mediaStoreUri = updateMediaProvider(client, null,
convertToMediaProviderValues(info));
if (mediaStoreUri != null) {
- final ContentValues updateValues = new ContentValues();
+ updateValues.clear();
updateValues.put(Downloads.Impl.COLUMN_MEDIASTORE_URI,
mediaStoreUri.toString());
db.update(DB_TABLE, updateValues, Downloads.Impl._ID + "=?",
@@ -806,6 +810,7 @@ public final class DownloadProvider extends ContentProvider {
return isVisibleInDownloads ? mediaStoreUri : null;
}
} catch (RemoteException e) {
+ // Should not happen
}
return null;
}
@@ -826,6 +831,7 @@ public final class DownloadProvider extends ContentProvider {
return ContentUris.withAppendedId(filesUri, cursor.getLong(0));
}
} catch (RemoteException e) {
+ // Should not happen
}
return null;
}
@@ -1138,13 +1144,100 @@ public final class DownloadProvider extends ContentProvider {
final SQLiteQueryBuilder qb = getQueryBuilder(uri, match);
+ // map of volumeName -> { mediastore ids that need to be queried }
+ final ArrayMap<String, LongArray> mediaStoreIdsForVolumes = new ArrayMap<>();
+ try (Cursor cursor = qb.query(db, new String[] { Downloads.Impl.COLUMN_MEDIASTORE_URI },
+ selection, selectionArgs, null, null, sort)) {
+ while (cursor.moveToNext()) {
+ final String uriString = cursor.getString(0);
+ if (uriString == null) {
+ continue;
+ }
+ final Uri mediaStoreUri = Uri.parse(uriString);
+ final String volumeName = MediaStore.getVolumeName(mediaStoreUri);
+ LongArray ids = mediaStoreIdsForVolumes.get(volumeName);
+ if (ids == null) {
+ ids = new LongArray();
+ mediaStoreIdsForVolumes.put(volumeName, ids);
+ }
+ ids.add(ContentUris.parseId(mediaStoreUri));
+ }
+ }
+ // map of volumeName -> { map of {mediastore id -> mediastore data} }
+ final ArrayMap<String, LongSparseArray<MediaStoreData>> mediaStoreDataForVolumes
+ = new ArrayMap<>();
+ final CallingIdentity token = clearCallingIdentity();
+ try (ContentProviderClient client = getContext().getContentResolver()
+ .acquireContentProviderClient(MediaStore.AUTHORITY)) {
+ final String[] projectionIn = new String[] {
+ MediaStore.Downloads._ID,
+ MediaStore.Downloads.DISPLAY_NAME,
+ MediaStore.Downloads.DATA,
+ };
+ for (int i = 0; i < mediaStoreIdsForVolumes.size(); ++i) {
+ final String volumeName = mediaStoreIdsForVolumes.keyAt(i);
+ final LongArray ids = mediaStoreIdsForVolumes.valueAt(i);
+ final LongSparseArray<MediaStoreData> mediaStoreDataForIds
+ = new LongSparseArray<>();
+ mediaStoreDataForVolumes.put(volumeName, mediaStoreDataForIds);
+ try (Cursor mediaCursor = getMediaProviderRowsForIds(
+ client, projectionIn, volumeName, ids)) {
+ while (mediaCursor.moveToNext()) {
+ final long id = mediaCursor.getLong(0);
+ final String displayName = mediaCursor.getString(1);
+ final String filePath = mediaCursor.getString(2);
+ mediaStoreDataForIds.put(id, new MediaStoreData(displayName, filePath));
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ } finally {
+ restoreCallingIdentity(token);
+ }
+
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final TranslatingCursor.Config config = getTranslatingCursorConfig(match);
final TranslatingCursor.Translator translator
- = (data, id) -> translateSystemToApp(data, pid, uid);
- final Cursor ret = TranslatingCursor.query(config, translator, qb, db,
- projection, selection, selectionArgs, null, null, sort, null, null);
+ = (data, auxiliaryColIndex, matchingColumn, cursor) -> {
+ final String uriString = cursor.getString(auxiliaryColIndex);
+ if (uriString != null) {
+ final Uri mediaStoreUri = Uri.parse(uriString);
+ final String volumeName = MediaStore.getVolumeName(mediaStoreUri);
+ final LongSparseArray<MediaStoreData> mediaStoreDataForIds
+ = mediaStoreDataForVolumes.get(volumeName);
+ if (mediaStoreDataForIds != null) {
+ final long id = ContentUris.parseId(mediaStoreUri);
+ final MediaStoreData mediaStoreData = mediaStoreDataForIds.get(id);
+ if (mediaStoreData != null) {
+ switch (matchingColumn) {
+ case Downloads.Impl.COLUMN_TITLE:
+ data = mediaStoreData.displayName;
+ break;
+ case Downloads.Impl._DATA:
+ case Downloads.Impl.COLUMN_FILE_NAME_HINT:
+ case DownloadManager.COLUMN_LOCAL_FILENAME:
+ data = mediaStoreData.filePath;
+ break;
+ default:
+ return data;
+ }
+ }
+ }
+ }
+
+ switch (matchingColumn) {
+ case Downloads.Impl._DATA:
+ case Downloads.Impl.COLUMN_FILE_NAME_HINT:
+ case DownloadManager.COLUMN_LOCAL_FILENAME:
+ return translateSystemToApp(data, pid, uid);
+ default:
+ return data;
+ }
+ };
+ final Cursor ret = TranslatingCursor.query(config, translator,
+ qb, db, projection, selection, selectionArgs, null, null, sort, null, null);
if (ret != null) {
ret.setNotificationUri(getContext().getContentResolver(), uri);
@@ -1161,6 +1254,19 @@ public final class DownloadProvider extends ContentProvider {
return ret;
}
+ private Cursor getMediaProviderRowsForIds(ContentProviderClient mediaProvider,
+ String[] projection, String volumeName, LongArray ids) throws RemoteException {
+ final StringBuilder queryString = new StringBuilder();
+ queryString.append(MediaStore.Downloads._ID + " in (");
+ final int size = ids.size();
+ for (int i = 0; i < size; ++i) {
+ queryString.append(ids.get(i));
+ queryString.append((i == size - 1) ? ")" : ",");
+ }
+ return mediaProvider.query(MediaStore.Downloads.getContentUri(volumeName),
+ projection, queryString.toString(), null, null);
+ }
+
private TranslatingCursor.Config getTranslatingCursorConfig(int match) {
final Uri baseUri;
switch (match) {
@@ -1175,9 +1281,11 @@ public final class DownloadProvider extends ContentProvider {
default:
baseUri = null;
}
- return new TranslatingCursor.Config(baseUri,
- Downloads.Impl._ID, Downloads.Impl._DATA, Downloads.Impl.COLUMN_FILE_NAME_HINT,
- DownloadManager.COLUMN_LOCAL_FILENAME);
+ return new TranslatingCursor.Config(baseUri, Downloads.Impl.COLUMN_MEDIASTORE_URI,
+ Downloads.Impl._DATA,
+ Downloads.Impl.COLUMN_FILE_NAME_HINT,
+ DownloadManager.COLUMN_LOCAL_FILENAME,
+ Downloads.Impl.COLUMN_TITLE);
}
private void logVerboseQueryInfo(String[] projection, final String selection,
@@ -1345,16 +1453,17 @@ public final class DownloadProvider extends ContentProvider {
final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver,
cursor);
final DownloadInfo info = new DownloadInfo(context);
+ final ContentValues updateValues = new ContentValues();
while (cursor.moveToNext()) {
reader.updateFromDatabase(info);
if (info.mFileName == null) {
if (info.mMediaStoreUri != null) {
client.delete(Uri.parse(info.mMediaStoreUri), null, null);
+ updateValues.clear();
+ updateValues.putNull(Downloads.Impl.COLUMN_MEDIASTORE_URI);
+ qb.update(db, updateValues, Downloads.Impl._ID + "=?",
+ new String[] { Long.toString(info.mId) });
}
- final ContentValues updateValues = new ContentValues();
- updateValues.putNull(Downloads.Impl.COLUMN_MEDIASTORE_URI);
- qb.update(db, updateValues, Downloads.Impl._ID + "=?",
- new String[] { Long.toString(info.mId) });
} else if (info.mDestination == Downloads.Impl.DESTINATION_EXTERNAL
|| info.mDestination == Downloads.Impl.DESTINATION_FILE_URI
|| info.mDestination == Downloads.Impl
@@ -1363,7 +1472,7 @@ public final class DownloadProvider extends ContentProvider {
info.mMediaStoreUri, convertToMediaProviderValues(info));
if (!TextUtils.equals(info.mMediaStoreUri,
mediaStoreUri == null ? null : mediaStoreUri.toString())) {
- final ContentValues updateValues = new ContentValues();
+ updateValues.clear();
if (mediaStoreUri == null) {
updateValues.putNull(Downloads.Impl.COLUMN_MEDIASTORE_URI);
} else {
@@ -1371,7 +1480,7 @@ public final class DownloadProvider extends ContentProvider {
mediaStoreUri.toString());
}
qb.update(db, updateValues, Downloads.Impl._ID + "=?",
- new String[]{Long.toString(info.mId)});
+ new String[] { Long.toString(info.mId) });
}
}
if (updateSchedule) {
@@ -1779,4 +1888,14 @@ public final class DownloadProvider extends ContentProvider {
final Uri uri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
getContext().revokeUriPermission(uri, ~0);
}
+
+ private static final class MediaStoreData {
+ public String displayName;
+ public String filePath;
+
+ public MediaStoreData(String displayName, String filePath) {
+ this.displayName = displayName;
+ this.filePath = filePath;
+ }
+ }
}