diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-04-27 23:23:16 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-04-27 23:23:16 +0000 |
commit | 8f2879758e870b8e2e65ac5b152930a0293968ed (patch) | |
tree | be624316e8700a3bc64d711983981021e41580f6 | |
parent | 5861c814fd1eee5c6d8bd69b28492529c6280e45 (diff) | |
parent | fca4711560d491fb0742e657487d5dcf4f0e57f5 (diff) | |
download | android_packages_providers_DownloadProvider-8f2879758e870b8e2e65ac5b152930a0293968ed.tar.gz android_packages_providers_DownloadProvider-8f2879758e870b8e2e65ac5b152930a0293968ed.tar.bz2 android_packages_providers_DownloadProvider-8f2879758e870b8e2e65ac5b152930a0293968ed.zip |
Snap for 5511022 from fca4711560d491fb0742e657487d5dcf4f0e57f5 to qt-release
Change-Id: I9d56834311830d85ef5f4b6cfb0d2ee78801350d
-rw-r--r-- | res/values-eu/strings.xml | 4 | ||||
-rw-r--r-- | res/values-kk/strings.xml | 2 | ||||
-rw-r--r-- | src/com/android/providers/downloads/DownloadProvider.java | 304 | ||||
-rw-r--r-- | src/com/android/providers/downloads/Helpers.java | 20 | ||||
-rw-r--r-- | ui/res/values-or/strings.xml | 2 |
5 files changed, 198 insertions, 134 deletions
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 55a8b3d0..a44366ee 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -19,9 +19,9 @@ <string name="app_label" msgid="3658948994665187911">"Deskargen kudeatzailea"</string> <string name="storage_description" msgid="7982444311558023664">"Deskargak"</string> <string name="permlab_downloadManager" msgid="7779544811202855500">"Atzitu deskargen kudeatzailea."</string> - <string name="permdesc_downloadManager" msgid="4237406545998908947">"Deskargen kudeatzailea atzitzea eta fitxategiak deskargatzeko hori erabiltzea baimentzen die aplikazioei. Aplikazio gaiztoek deskargak eteteko eta informazio pribatua atzitzeko erabil dezakete hori."</string> + <string name="permdesc_downloadManager" msgid="4237406545998908947">"Deskargen kudeatzailea atzitzea eta fitxategiak deskargatzeko hori erabiltzeko baimena ematen die aplikazioei. Aplikazio gaiztoek deskargak eteteko eta informazio pribatua atzitzeko erabil dezakete hori."</string> <string name="permlab_downloadManagerAdvanced" msgid="7103642833308809655">"Deskargen kudeatzailearen eginbide aurreratuak."</string> - <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Deskargen kudeatzailearen eginbide aurreratuak atzitzea baimentzen die aplikazioei. Aplikazio gaiztoek deskargak eteteko eta informazio pribatua atzitzeko erabil dezakete hori."</string> + <string name="permdesc_downloadManagerAdvanced" msgid="2659546004160962761">"Deskargen kudeatzailearen eginbide aurreratuak atzitzeko baimena ematen die aplikazioei. Aplikazio gaiztoek deskargak eteteko eta informazio pribatua atzitzeko erabil dezakete hori."</string> <string name="permlab_downloadCompletedIntent" msgid="945913803765675685">"Bidali deskargen jakinarazpenak."</string> <string name="permdesc_downloadCompletedIntent" msgid="2094706189855699533">"Osatutako deskargei buruzko jakinarazpenak bidaltzea baimentzen die aplikazioei. Aplikazio gaiztoek fitxategiak deskargatzen dituzten beste aplikazioak nahasteko erabil dezakete hori."</string> <string name="permlab_downloadCacheNonPurgeable" msgid="3069534308882047412">"Erreserbatu memoria deskarga-cachean"</string> diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index 1ed6618a..4de53653 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -16,7 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_label" msgid="3658948994665187911">"Жүктеу менеджері"</string> + <string name="app_label" msgid="3658948994665187911">"Жүктеп алу менеджері"</string> <string name="storage_description" msgid="7982444311558023664">"Жүктеп алынғандар"</string> <string name="permlab_downloadManager" msgid="7779544811202855500">"Жүктеу менеджеріне кіру."</string> <string name="permdesc_downloadManager" msgid="4237406545998908947">"Қолданбаға жүктеу менеджеріне кіріп, оны файлдарды жүктеу үшін қолдану мүмкіндігін береді. Залалды қолданбалар бұны жүктеулерге кедергі жасау үшін және жеке ақпаратқа кіру үшін қолдануы мүмкін."</string> diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java index acc814c5..a6159ca7 100644 --- a/src/com/android/providers/downloads/DownloadProvider.java +++ b/src/com/android/providers/downloads/DownloadProvider.java @@ -16,11 +16,10 @@ package com.android.providers.downloads; -import static android.os.Binder.getCallingPid; -import static android.os.Binder.getCallingUid; import static android.provider.BaseColumns._ID; import static android.provider.Downloads.Impl.COLUMN_DESTINATION; import static android.provider.Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI; +import static android.provider.Downloads.Impl.COLUMN_MEDIASTORE_URI; import static android.provider.Downloads.Impl.COLUMN_MEDIA_SCANNED; import static android.provider.Downloads.Impl.COLUMN_OTHER_UID; import static android.provider.Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD; @@ -43,6 +42,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.UriMatcher; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.DatabaseUtils; @@ -53,17 +53,17 @@ import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.OnCloseListener; import android.os.Process; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.storage.StorageManager; import android.provider.BaseColumns; import android.provider.Downloads; import android.provider.MediaStore; -import android.provider.MediaStore.Files; import android.provider.OpenableColumns; import android.text.TextUtils; import android.text.format.DateUtils; @@ -72,6 +72,7 @@ import android.util.Log; import android.util.LongArray; import android.util.LongSparseArray; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import libcore.io.IoUtils; @@ -99,7 +100,7 @@ public final class DownloadProvider extends ContentProvider { /** Database filename */ private static final String DB_NAME = "downloads.db"; /** Current database version */ - private static final int DB_VERSION = 111; + private static final int DB_VERSION = 112; /** Name of table in the database */ private static final String DB_TABLE = "downloads"; /** Memory optimization - close idle connections after 30s of inactivity */ @@ -325,6 +326,10 @@ public final class DownloadProvider extends ContentProvider { addMediaStoreUris(db); break; + case 112: + UpdateMediaStoreUrisFromFilesToDownloads(db); + break; + default: throw new IllegalStateException("Don't know how to upgrade to " + version); } @@ -411,6 +416,36 @@ public final class DownloadProvider extends ContentProvider { } /** + * DownloadProvider has been updated to use MediaStore.Downloads based uris + * for COLUMN_MEDIASTORE_URI but the existing entries would still have MediaStore.Files + * based uris. It's possible that in the future we might incorrectly assume that all the + * uris are MediaStore.DownloadColumns based and end up querying some + * MediaStore.Downloads specific columns. To avoid this, update the existing entries to + * use MediaStore.Downloads based uris only. + */ + private void UpdateMediaStoreUrisFromFilesToDownloads(SQLiteDatabase db) { + try (Cursor cursor = db.query(DB_TABLE, + new String[] { Downloads.Impl._ID, COLUMN_MEDIASTORE_URI }, + COLUMN_MEDIASTORE_URI + " IS NOT NULL", null, null, null, null)) { + final ContentValues updateValues = new ContentValues(); + while (cursor.moveToNext()) { + final long id = cursor.getLong(0); + final Uri mediaStoreFilesUri = Uri.parse(cursor.getString(1)); + + final long mediaStoreId = ContentUris.parseId(mediaStoreFilesUri); + final String volumeName = MediaStore.getVolumeName(mediaStoreFilesUri); + final Uri mediaStoreDownloadsUri + = MediaStore.Downloads.getContentUri(volumeName, mediaStoreId); + + updateValues.clear(); + updateValues.put(COLUMN_MEDIASTORE_URI, mediaStoreDownloadsUri.toString()); + db.update(DB_TABLE, updateValues, Downloads.Impl._ID + "=?", + new String[] { Long.toString(id) }); + } + } + } + + /** * Add a column to a table using ALTER TABLE. * @param dbTable name of the table * @param columnName name of the column to add @@ -569,17 +604,36 @@ public final class DownloadProvider extends ContentProvider { @Override public Bundle call(String method, String arg, Bundle extras) { - if (method == Downloads.MEDIASTORE_DOWNLOADS_DELETED_CALL) { - getContext().enforceCallingOrSelfPermission( - android.Manifest.permission.WRITE_MEDIA_STORAGE, - "Not allowed to call " + Downloads.MEDIASTORE_DOWNLOADS_DELETED_CALL); - final long[] deletedDownloadIds = extras.getLongArray(Downloads.EXTRA_IDS); - final String[] mimeTypes = extras.getStringArray(Downloads.EXTRA_MIME_TYPES); - DownloadStorageProvider.onMediaProviderDownloadsDelete(getContext(), - deletedDownloadIds, mimeTypes); - return null; - } else { - throw new UnsupportedOperationException("Unsupported call: " + method); + switch (method) { + case Downloads.CALL_MEDIASTORE_DOWNLOADS_DELETED: { + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.WRITE_MEDIA_STORAGE, + "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); + DownloadStorageProvider.onMediaProviderDownloadsDelete(getContext(), + deletedDownloadIds, mimeTypes); + return null; + } + case Downloads.CALL_CREATE_EXTERNAL_PUBLIC_DIR: { + final String dirType = extras.getString(Downloads.DIR_TYPE); + if (!ArrayUtils.contains(Environment.STANDARD_DIRECTORIES, dirType)) { + throw new IllegalStateException("Not one of standard directories: " + dirType); + } + final File file = Environment.getExternalStoragePublicDirectory(dirType); + if (file.exists()) { + if (!file.isDirectory()) { + throw new IllegalStateException(file.getAbsolutePath() + + " already exists and is not a directory"); + } + } else if (!file.mkdirs()) { + throw new IllegalStateException("Unable to create directory: " + + file.getAbsolutePath()); + } + return null; + } + default: + throw new UnsupportedOperationException("Unsupported call: " + method); } } @@ -625,10 +679,8 @@ public final class DownloadProvider extends ContentProvider { } if (dest == Downloads.Impl.DESTINATION_FILE_URI) { checkFileUriDestination(values); - final String fileUri = values.getAsString(Downloads.Impl.COLUMN_FILE_NAME_HINT); - values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, translateAppToSystem( - fileUri, getCallingPid(), getCallingUid())); - + } else if (dest == DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) { + checkDownloadedFilePath(values); } else if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.WRITE_EXTERNAL_STORAGE, @@ -640,6 +692,7 @@ public final class DownloadProvider extends ContentProvider { throw new SecurityException("No permission to write"); } } + filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest); } @@ -674,8 +727,6 @@ public final class DownloadProvider extends ContentProvider { */ if (values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION) == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) { - values.put(Downloads.Impl._DATA, translateAppToSystem( - values.getAsString(Downloads.Impl._DATA), getCallingPid(), getCallingUid())); // these requests always are marked as 'completed' filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_SUCCESS); filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, @@ -816,13 +867,8 @@ public final class DownloadProvider extends ContentProvider { @Nullable String currentMediaStoreUri, @NonNull ContentValues mediaValues) { Uri mediaStoreUri; - final String filePath = mediaValues.getAsString(Files.FileColumns.DATA); - final boolean isVisibleInDownloads = mediaValues.getAsInteger( - Files.FileColumns.IS_DOWNLOAD) == 1; + final String filePath = mediaValues.getAsString(MediaStore.DownloadColumns.DATA); if (currentMediaStoreUri == null) { - if (!isVisibleInDownloads) { - return null; - } mediaStoreUri = getMediaStoreUri(mediaProvider, filePath); } else { mediaStoreUri = Uri.parse(currentMediaStoreUri); @@ -830,7 +876,8 @@ public final class DownloadProvider extends ContentProvider { try { if (mediaStoreUri == null) { - mediaStoreUri = mediaProvider.insert(Files.getContentUriForPath(filePath), + mediaStoreUri = mediaProvider.insert( + MediaStore.Downloads.getContentUriForPath(filePath), mediaValues); if (mediaStoreUri == null) { Log.e(Constants.TAG, "Error inserting into mediaProvider: " + mediaValues); @@ -842,7 +889,7 @@ public final class DownloadProvider extends ContentProvider { Log.e(Constants.TAG, "Error updating MediaProvider, uri: " + mediaStoreUri + ", values: " + mediaValues); } - return isVisibleInDownloads ? mediaStoreUri : null; + return mediaStoreUri; } } catch (RemoteException e) { // Should not happen @@ -859,11 +906,12 @@ public final class DownloadProvider extends ContentProvider { private Uri getMediaStoreUri(@NonNull ContentProviderClient mediaProvider, @NonNull String filePath) { - final Uri filesUri = Files.getContentUriForPath(filePath); - try (Cursor cursor = mediaProvider.query(filesUri, new String[] { Files.FileColumns._ID }, - Files.FileColumns.DATA + "=?", new String[] { filePath }, null, null)) { + final Uri downloadsUri = MediaStore.Downloads.getContentUriForPath(filePath); + try (Cursor cursor = mediaProvider.query(downloadsUri, + new String[] { MediaStore.DownloadColumns._ID }, + MediaStore.DownloadColumns.DATA + "=?", new String[] { filePath }, null, null)) { if (cursor.moveToNext()) { - return ContentUris.withAppendedId(filesUri, cursor.getLong(0)); + return ContentUris.withAppendedId(downloadsUri, cursor.getLong(0)); } } catch (RemoteException e) { // Should not happen @@ -883,12 +931,11 @@ public final class DownloadProvider extends ContentProvider { mediaValues.put(MediaStore.Downloads.SIZE, info.mTotalBytes); mediaValues.put(MediaStore.Downloads.DOWNLOAD_URI, info.mUri); mediaValues.put(MediaStore.Downloads.REFERER_URI, info.mReferer); - mediaValues.put(MediaStore.Downloads.DISPLAY_NAME, info.mTitle); mediaValues.put(MediaStore.Downloads.DESCRIPTION, info.mDescription); mediaValues.put(MediaStore.Downloads.MIME_TYPE, info.mMimeType); mediaValues.put(MediaStore.Downloads.IS_PENDING, Downloads.Impl.isStatusSuccess(info.mStatus) ? 0 : 1); - mediaValues.put(Files.FileColumns.IS_DOWNLOAD, 1); + mediaValues.put(MediaStore.Downloads.OWNER_PACKAGE_NAME, getPackageForUid(info.mUid)); return mediaValues; } @@ -908,8 +955,6 @@ public final class DownloadProvider extends ContentProvider { downloadValues.getAsString(Downloads.Impl.COLUMN_URI)); mediaValues.put(MediaStore.Downloads.REFERER_URI, downloadValues.getAsString(Downloads.Impl.COLUMN_REFERER)); - mediaValues.put(MediaStore.Downloads.DISPLAY_NAME, - downloadValues.getAsString(Downloads.Impl.COLUMN_TITLE)); mediaValues.put(MediaStore.Downloads.DESCRIPTION, downloadValues.getAsString(Downloads.Impl.COLUMN_DESCRIPTION)); mediaValues.put(MediaStore.Downloads.MIME_TYPE, @@ -917,37 +962,11 @@ public final class DownloadProvider extends ContentProvider { final boolean isPending = downloadValues.getAsInteger(Downloads.Impl.COLUMN_STATUS) != Downloads.Impl.STATUS_SUCCESS; mediaValues.put(MediaStore.Downloads.IS_PENDING, isPending ? 1 : 0); - mediaValues.put(Files.FileColumns.IS_DOWNLOAD, downloadValues.getAsBoolean( - Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI) ? 1 : 0); + mediaValues.put(MediaStore.Downloads.OWNER_PACKAGE_NAME, + getPackageForUid(downloadValues.getAsInteger(Constants.UID))); return mediaValues; } - private @Nullable String translateAppToSystem(@Nullable String path, int pid, int uid) { - if (path == null) return path; - - final Uri fileUri = getFileUri(path); - if (fileUri != null) { - path = fileUri.getPath(); - } - final File app = new File(path); - final File system = mStorageManager.translateAppToSystem(app, pid, uid); - // If the input was file uri, we need to return a file uri - return fileUri == null ? system.getPath() : Uri.fromFile(system).toString(); - } - - private @Nullable String translateSystemToApp(@Nullable String path, int pid, int uid) { - if (path == null) return path; - - final Uri fileUri = getFileUri(path); - if (fileUri != null) { - path = fileUri.getPath(); - } - final File system = new File(path); - final File app = mStorageManager.translateSystemToApp(system, pid, uid); - // If the input was file uri, we need to return a file uri - return fileUri == null ? app.getPath() : Uri.fromFile(app).toString(); - } - private static Uri getFileUri(String uriString) { final Uri uri = Uri.parse(uriString); return TextUtils.equals(uri.getScheme(), ContentResolver.SCHEME_FILE) ? uri : null; @@ -976,7 +995,7 @@ public final class DownloadProvider extends ContentProvider { throw new IllegalArgumentException("Not a file URI: " + uri); } final String path = uri.getPath(); - if (path == null) { + if (path == null || path.contains("..")) { throw new IllegalArgumentException("Invalid file URI: " + uri); } @@ -987,27 +1006,90 @@ public final class DownloadProvider extends ContentProvider { throw new SecurityException(e); } + final int targetSdkVersion = getCallingPackageTargetSdkVersion(); + + if (Helpers.isFilenameValidInExternalPackage(getContext(), file, getCallingPackage()) + || Helpers.isFilenameValidInPublicDownloadsDir(file)) { + // No permissions required for paths belonging to calling package or + // public downloads dir. + return; + } else if (targetSdkVersion < Build.VERSION_CODES.Q + && Helpers.isFilenameValidInExternal(getContext(), file)) { + // Otherwise we require write permission + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.WRITE_EXTERNAL_STORAGE, + "No permission to write to " + file); + + final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class); + if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, + getCallingPackage()) != AppOpsManager.MODE_ALLOWED) { + throw new SecurityException("No permission to write to " + file); + } + } else { + throw new SecurityException("Unsupported path " + file); + } + } + + private void checkDownloadedFilePath(ContentValues values) { + final String path = values.getAsString(Downloads.Impl._DATA); + if (path == null || path.contains("..")) { + throw new IllegalArgumentException("Invalid file path: " + + (path == null ? "null" : path)); + } + + final File file; + try { + file = new File(path).getCanonicalFile(); + } catch (IOException e) { + throw new SecurityException(e); + } + + if (!file.exists()) { + throw new IllegalArgumentException("File doesn't exist: " + file); + } + + final int targetSdkVersion = getCallingPackageTargetSdkVersion(); + final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); + final boolean runningLegacyMode = appOpsManager.checkOp(AppOpsManager.OP_LEGACY_STORAGE, + Binder.getCallingUid(), getCallingPackage()) == AppOpsManager.MODE_ALLOWED; + if (Helpers.isFilenameValidInExternalPackage(getContext(), file, getCallingPackage())) { - // No permissions required for paths belonging to calling package + // No permissions required for paths belonging to calling package. return; - } else if (Helpers.isFilenameValidInExternal(getContext(), file)) { - if (!StorageManager.hasIsolatedStorage()) { - // Otherwise we require write permission - getContext().enforceCallingOrSelfPermission( - android.Manifest.permission.WRITE_EXTERNAL_STORAGE, - "No permission to write to " + file); + } else if ((runningLegacyMode && Helpers.isFilenameValidInPublicDownloadsDir(file)) + || (targetSdkVersion < Build.VERSION_CODES.Q + && Helpers.isFilenameValidInExternal(getContext(), file))) { + // Otherwise we require write permission + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.WRITE_EXTERNAL_STORAGE, + "No permission to write to " + file); - final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class); - if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, - getCallingPackage()) != AppOpsManager.MODE_ALLOWED) { - throw new SecurityException("No permission to write to " + file); - } + final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class); + if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, + getCallingPackage()) != AppOpsManager.MODE_ALLOWED) { + throw new SecurityException("No permission to write to " + file); } } else { throw new SecurityException("Unsupported path " + file); } } + private int getCallingPackageTargetSdkVersion() { + final String callingPackage = getCallingPackage(); + if (callingPackage != null) { + ApplicationInfo ai = null; + try { + ai = getContext().getPackageManager() + .getApplicationInfo(callingPackage, 0); + } catch (PackageManager.NameNotFoundException ignored) { + } + if (ai != null) { + return ai.targetSdkVersion; + } + } + return Build.VERSION_CODES.CUR_DEVELOPMENT; + } + /** * Apps with the ACCESS_DOWNLOAD_MANAGER permission can access this provider freely, subject to * constraints in the rest of the code. Apps without that may still access this provider through @@ -1211,29 +1293,27 @@ public final class DownloadProvider extends ContentProvider { } } // map of volumeName -> { map of {mediastore id -> mediastore data} } - final ArrayMap<String, LongSparseArray<MediaStoreData>> mediaStoreDataForVolumes + 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.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 + 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 displayName = mediaCursor.getString(1); - final String filePath = mediaCursor.getString(2); - mediaStoreDataForIds.put(id, new MediaStoreData(displayName, filePath)); + final String filePath = mediaCursor.getString(1); + mediaStoreDataForIds.put(id, filePath); } } } @@ -1243,8 +1323,6 @@ public final class DownloadProvider extends ContentProvider { restoreCallingIdentity(token); } - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); final TranslatingCursor.Config config = getTranslatingCursorConfig(match); final TranslatingCursor.Translator translator = (data, auxiliaryColIndex, matchingColumn, cursor) -> { @@ -1252,36 +1330,22 @@ public final class DownloadProvider extends ContentProvider { if (uriString != null) { final Uri mediaStoreUri = Uri.parse(uriString); final String volumeName = MediaStore.getVolumeName(mediaStoreUri); - final LongSparseArray<MediaStoreData> mediaStoreDataForIds + final LongSparseArray<String> 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: + final long id = ContentUris.parseId(mediaStoreUri); + return mediaStoreDataForIds.get(id, data); + 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; - } + return data; }; final Cursor ret = TranslatingCursor.query(config, translator, qb, db, projection, selection, selectionArgs, null, null, sort, null, null); @@ -1331,8 +1395,7 @@ public final class DownloadProvider extends ContentProvider { 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); + DownloadManager.COLUMN_LOCAL_FILENAME); } private void logVerboseQueryInfo(String[] projection, final String selection, @@ -1453,8 +1516,6 @@ public final class DownloadProvider extends ContentProvider { filteredValues = values; String filename = values.getAsString(Downloads.Impl._DATA); if (filename != null) { - filteredValues.put(Downloads.Impl._DATA, - translateAppToSystem(filename, getCallingPid(), getCallingUid())); Cursor c = null; try { c = query(uri, new String[] @@ -1466,9 +1527,6 @@ public final class DownloadProvider extends ContentProvider { IoUtils.closeQuietly(c); } } - filteredValues.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, translateAppToSystem( - filteredValues.getAsString(Downloads.Impl.COLUMN_FILE_NAME_HINT), - getCallingPid(), getCallingUid())); Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS); boolean isRestart = status != null && status == Downloads.Impl.STATUS_PENDING; @@ -1943,14 +2001,4 @@ 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; - } - } } diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java index 963ca9da..40fd3b87 100644 --- a/src/com/android/providers/downloads/Helpers.java +++ b/src/com/android/providers/downloads/Helpers.java @@ -17,9 +17,10 @@ package com.android.providers.downloads; import static android.os.Environment.buildExternalStorageAppCacheDirs; -import static android.os.Environment.buildExternalStorageAppFilesDirs; +import static android.os.Environment.buildExternalStorageAppDataDirs; import static android.os.Environment.buildExternalStorageAppMediaDirs; import static android.os.Environment.buildExternalStorageAppObbDirs; +import static android.os.Environment.buildExternalStoragePublicDirs; import static android.provider.Downloads.Impl.FLAG_REQUIRES_CHARGING; import static android.provider.Downloads.Impl.FLAG_REQUIRES_DEVICE_IDLE; @@ -488,7 +489,7 @@ public class Helpers { static boolean isFilenameValidInExternalPackage(Context context, File file, String packageName) { try { - if (containsCanonical(buildExternalStorageAppFilesDirs(packageName), file) || + if (containsCanonical(buildExternalStorageAppDataDirs(packageName), file) || containsCanonical(buildExternalStorageAppObbDirs(packageName), file) || containsCanonical(buildExternalStorageAppCacheDirs(packageName), file) || containsCanonical(buildExternalStorageAppMediaDirs(packageName), file)) { @@ -503,6 +504,21 @@ public class Helpers { return false; } + static boolean isFilenameValidInPublicDownloadsDir(File file) { + try { + if (containsCanonical(buildExternalStoragePublicDirs( + Environment.DIRECTORY_DOWNLOADS), file)) { + return true; + } + } catch (IOException e) { + Log.w(TAG, "Failed to resolve canonical path: " + e); + return false; + } + + Log.w(TAG, "Path appears to be invalid: " + file); + return false; + } + /** * Checks whether the filename looks legitimate for security purposes. This * prevents us from opening files that aren't actually downloads. diff --git a/ui/res/values-or/strings.xml b/ui/res/values-or/strings.xml index a9e6fdbf..c7a09650 100644 --- a/ui/res/values-or/strings.xml +++ b/ui/res/values-or/strings.xml @@ -47,5 +47,5 @@ <string name="deselect_all" msgid="6348198946254776764">"କିଛି ବି ଚୟନ କରନ୍ତୁ ନାହିଁ"</string> <string name="select_all" msgid="634074918366265804">"ସବୁ ଚୟନ କରନ୍ତୁ"</string> <string name="selected_count" msgid="2101564570019753277">"<xliff:g id="TOTAL">%2$d</xliff:g> ମଧ୍ୟରୁ <xliff:g id="NUMBER">%1$d</xliff:g> ଚୟନିତ"</string> - <string name="download_share_dialog" msgid="3355867339806448955">"ଏହା ମାଧ୍ୟମରେ ଶେୟାର୍ କରନ୍ତୁ"</string> + <string name="download_share_dialog" msgid="3355867339806448955">"ଏହା ମାଧ୍ୟମରେ ସେୟାର୍ କରନ୍ତୁ"</string> </resources> |