summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/downloads/DownloadProvider.java')
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java167
1 files changed, 34 insertions, 133 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index a2f8532e..550c8fba 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -79,6 +79,7 @@ import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
@@ -636,8 +637,7 @@ public final class DownloadProvider extends ContentProvider {
public Bundle call(String method, String arg, Bundle extras) {
switch (method) {
case Downloads.CALL_MEDIASTORE_DOWNLOADS_DELETED: {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.WRITE_MEDIA_STORAGE,
+ Preconditions.checkArgument(Binder.getCallingUid() == Process.myUid(),
"Not allowed to call " + Downloads.CALL_MEDIASTORE_DOWNLOADS_DELETED);
final long[] deletedDownloadIds = extras.getLongArray(Downloads.EXTRA_IDS);
final String[] mimeTypes = extras.getStringArray(Downloads.EXTRA_MIME_TYPES);
@@ -662,6 +662,12 @@ public final class DownloadProvider extends ContentProvider {
}
return null;
}
+ case Downloads.CALL_REVOKE_MEDIASTORE_URI_PERMS : {
+ Preconditions.checkArgument(Binder.getCallingUid() == Process.myUid(),
+ "Not allowed to call " + Downloads.CALL_REVOKE_MEDIASTORE_URI_PERMS);
+ DownloadStorageProvider.revokeAllMediaStoreUriPermissions(getContext());
+ return null;
+ }
default:
throw new UnsupportedOperationException("Unsupported call: " + method);
}
@@ -1324,82 +1330,7 @@ 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<String>> 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.DATA,
- };
- for (int i = 0; i < mediaStoreIdsForVolumes.size(); ++i) {
- final String volumeName = mediaStoreIdsForVolumes.keyAt(i);
- final LongArray ids = mediaStoreIdsForVolumes.valueAt(i);
- final LongSparseArray<String> 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 filePath = mediaCursor.getString(1);
- mediaStoreDataForIds.put(id, filePath);
- }
- }
- }
- } catch (RemoteException e) {
- // Should not happen
- } finally {
- restoreCallingIdentity(token);
- }
-
- final TranslatingCursor.Config config = getTranslatingCursorConfig(match);
- final TranslatingCursor.Translator translator
- = (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<String> mediaStoreDataForIds
- = mediaStoreDataForVolumes.get(volumeName);
- if (mediaStoreDataForIds != null) {
- switch (matchingColumn) {
- case Downloads.Impl._DATA:
- case Downloads.Impl.COLUMN_FILE_NAME_HINT:
- case DownloadManager.COLUMN_LOCAL_FILENAME:
- final long id = ContentUris.parseId(mediaStoreUri);
- return mediaStoreDataForIds.get(id, data);
- default:
- return data;
- }
- }
- }
-
- return data;
- };
- final Cursor ret = TranslatingCursor.query(config, translator,
- qb, db, projection, selection, selectionArgs, null, null, sort, null, null);
+ final Cursor ret = qb.query(db, projection, selection, selectionArgs, null, null, sort);
if (ret != null) {
ret.setNotificationUri(getContext().getContentResolver(), uri);
@@ -1416,39 +1347,6 @@ 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) {
- case MY_DOWNLOADS:
- case MY_DOWNLOADS_ID:
- baseUri = Downloads.Impl.CONTENT_URI;
- break;
- case ALL_DOWNLOADS:
- case ALL_DOWNLOADS_ID:
- baseUri = Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
- break;
- default:
- baseUri = null;
- }
- return new TranslatingCursor.Config(baseUri, Downloads.Impl.COLUMN_MEDIASTORE_URI,
- Downloads.Impl._DATA,
- Downloads.Impl.COLUMN_FILE_NAME_HINT,
- DownloadManager.COLUMN_LOCAL_FILENAME);
- }
-
private void logVerboseQueryInfo(String[] projection, final String selection,
final String[] selectionArgs, final String sort, SQLiteDatabase db) {
java.lang.StringBuilder sb = new java.lang.StringBuilder();
@@ -1622,7 +1520,8 @@ public final class DownloadProvider extends ContentProvider {
|| (info.mMediaScanned != MEDIA_NOT_SCANNABLE);
if (info.mFileName == null) {
if (info.mMediaStoreUri != null) {
- client.delete(Uri.parse(info.mMediaStoreUri), null, null);
+ // If there was a mediastore entry, it would be deleted in it's
+ // next idle pass.
updateValues.clear();
updateValues.putNull(Downloads.Impl.COLUMN_MEDIASTORE_URI);
qb.update(db, updateValues, Downloads.Impl._ID + "=?",
@@ -1660,8 +1559,6 @@ public final class DownloadProvider extends ContentProvider {
info.sendIntentIfRequested();
}
}
- } catch (RemoteException e) {
- // Should not happen
} finally {
restoreCallingIdentity(token);
}
@@ -1788,32 +1685,18 @@ public final class DownloadProvider extends ContentProvider {
final String path = info.mFileName;
if (!TextUtils.isEmpty(path)) {
- boolean fileDeleted = false;
try {
final File file = new File(path).getCanonicalFile();
if (Helpers.isFilenameValid(getContext(), file)) {
Log.v(Constants.TAG,
"Deleting " + file + " via provider delete");
file.delete();
- fileDeleted = true;
+ deleteMediaStoreEntry(file);
+ } else {
+ Log.d(Constants.TAG, "Ignoring invalid file: " + file);
}
- } catch (IOException ignore) {
- }
- if (!fileDeleted) {
- Log.d(Constants.TAG, "Ignoring invalid path: " + path);
- }
- }
-
- final String mediaUri = info.mMediaStoreUri;
- if (!TextUtils.isEmpty(mediaUri)) {
- final long token = Binder.clearCallingIdentity();
- try {
- getContext().getContentResolver().delete(Uri.parse(mediaUri), null,
- null);
- } catch (Exception e) {
- Log.w(Constants.TAG, "Failed to delete media entry: " + e);
- } finally {
- Binder.restoreCallingIdentity(token);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Couldn't delete file: " + path, e);
}
}
@@ -1848,6 +1731,24 @@ public final class DownloadProvider extends ContentProvider {
return count;
}
+ private void deleteMediaStoreEntry(File file) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final String path = file.getAbsolutePath();
+ final Uri.Builder builder = MediaStore.setIncludePending(
+ MediaStore.Files.getContentUriForPath(path).buildUpon());
+ builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
+
+ final Uri filesUri = builder.build();
+ getContext().getContentResolver().delete(filesUri,
+ MediaStore.Files.FileColumns.DATA + "=?", new String[] { path });
+ } catch (Exception e) {
+ Log.d(Constants.TAG, "Failed to delete mediastore entry for file:" + file, e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Remotely opens a file
*/