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.java152
1 files changed, 98 insertions, 54 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index ad3cf7ac..2d914c41 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -39,7 +39,6 @@ import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.Process;
-import android.os.SELinux;
import android.provider.BaseColumns;
import android.provider.Downloads;
import android.provider.OpenableColumns;
@@ -178,7 +177,6 @@ public final class DownloadProvider extends ContentProvider {
/** List of uids that can access the downloads */
private int mSystemUid = -1;
private int mDefContainerUid = -1;
- private File mDownloadsDataDir;
@VisibleForTesting
SystemFacade mSystemFacade;
@@ -416,7 +414,7 @@ public final class DownloadProvider extends ContentProvider {
Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " +
Downloads.Impl.COLUMN_TITLE + " TEXT, " +
Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " +
- Constants.MEDIA_SCANNED + " BOOLEAN);");
+ Downloads.Impl.COLUMN_MEDIA_SCANNED + " BOOLEAN);");
} catch (SQLException ex) {
Log.e(Constants.TAG, "couldn't create table in downloads database");
throw ex;
@@ -464,12 +462,6 @@ public final class DownloadProvider extends ContentProvider {
// saves us by getting some initialization code in DownloadService out of the way.
Context context = getContext();
context.startService(new Intent(context, DownloadService.class));
- mDownloadsDataDir = StorageManager.getDownloadDataDirectory(getContext());
- try {
- SELinux.restorecon(mDownloadsDataDir.getCanonicalPath());
- } catch (IOException e) {
- Log.wtf(Constants.TAG, "Could not get canonical path for download directory", e);
- }
return true;
}
@@ -540,7 +532,7 @@ public final class DownloadProvider extends ContentProvider {
// validate the destination column
Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION);
if (dest != null) {
- if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
+ if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
!= PackageManager.PERMISSION_GRANTED
&& (dest == Downloads.Impl.DESTINATION_CACHE_PARTITION
|| dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING
@@ -551,7 +543,7 @@ public final class DownloadProvider extends ContentProvider {
// for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically
// switch to non-purgeable download
boolean hasNonPurgeablePermission =
- getContext().checkCallingPermission(
+ getContext().checkCallingOrSelfPermission(
Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE)
== PackageManager.PERMISSION_GRANTED;
if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE
@@ -638,7 +630,7 @@ public final class DownloadProvider extends ContentProvider {
copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues);
// UID, PID columns
- if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
+ if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
== PackageManager.PERMISSION_GRANTED) {
copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues);
}
@@ -829,6 +821,16 @@ public final class DownloadProvider extends ContentProvider {
throw new SecurityException("Invalid value for " + column + ": " + value);
}
+ private Cursor queryCleared(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sort) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return query(uri, projection, selection, selectionArgs, sort);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Starts a database query
*/
@@ -1051,12 +1053,16 @@ public final class DownloadProvider extends ContentProvider {
filteredValues = values;
String filename = values.getAsString(Downloads.Impl._DATA);
if (filename != null) {
- Cursor c = query(uri, new String[]
- { Downloads.Impl.COLUMN_TITLE }, null, null, null);
- if (!c.moveToFirst() || c.getString(0).isEmpty()) {
- values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName());
+ Cursor c = null;
+ try {
+ c = query(uri, new String[]
+ { Downloads.Impl.COLUMN_TITLE }, null, null, null);
+ if (!c.moveToFirst() || c.getString(0).isEmpty()) {
+ values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName());
+ }
+ } finally {
+ IoUtils.closeQuietly(c);
}
- c.close();
}
Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS);
@@ -1123,7 +1129,7 @@ public final class DownloadProvider extends ContentProvider {
selection.appendClause(Downloads.Impl._ID + " = ?", getDownloadIdFromUri(uri));
}
if ((uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID)
- && getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ALL)
+ && getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ALL)
!= PackageManager.PERMISSION_GRANTED) {
selection.appendClause(
Constants.UID + "= ? OR " + Downloads.Impl.COLUMN_OTHER_UID + "= ?",
@@ -1139,7 +1145,9 @@ public final class DownloadProvider extends ContentProvider {
public int delete(final Uri uri, final String where,
final String[] whereArgs) {
- Helpers.validateSelection(where, sAppReadableColumnsSet);
+ if (shouldRestrictVisibility()) {
+ Helpers.validateSelection(where, sAppReadableColumnsSet);
+ }
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
@@ -1184,8 +1192,12 @@ public final class DownloadProvider extends ContentProvider {
logVerboseOpenFileInfo(uri, mode);
}
- final Cursor cursor = query(uri, new String[] { Downloads.Impl._DATA }, null, null, null);
- String path;
+ final Cursor cursor = queryCleared(uri, new String[] {
+ Downloads.Impl._DATA, Downloads.Impl.COLUMN_STATUS,
+ Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.COLUMN_MEDIA_SCANNED }, null,
+ null, null);
+ final String path;
+ final boolean shouldScan;
try {
int count = (cursor != null) ? cursor.getCount() : 0;
if (count != 1) {
@@ -1196,8 +1208,20 @@ public final class DownloadProvider extends ContentProvider {
throw new FileNotFoundException("Multiple items at " + uri);
}
- cursor.moveToFirst();
- path = cursor.getString(0);
+ if (cursor.moveToFirst()) {
+ final int status = cursor.getInt(1);
+ final int destination = cursor.getInt(2);
+ final int mediaScanned = cursor.getInt(3);
+
+ path = cursor.getString(0);
+ shouldScan = Downloads.Impl.isStatusSuccess(status) && (
+ destination == Downloads.Impl.DESTINATION_EXTERNAL
+ || destination == Downloads.Impl.DESTINATION_FILE_URI
+ || destination == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD)
+ && mediaScanned != 2;
+ } else {
+ throw new FileNotFoundException("Failed moveToFirst");
+ }
} finally {
IoUtils.closeQuietly(cursor);
}
@@ -1205,27 +1229,41 @@ public final class DownloadProvider extends ContentProvider {
if (path == null) {
throw new FileNotFoundException("No filename found.");
}
- if (!Helpers.isFilenameValid(path, mDownloadsDataDir)) {
- throw new FileNotFoundException("Invalid filename: " + path);
+
+ final File file;
+ try {
+ file = new File(path).getCanonicalFile();
+ } catch (IOException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+
+ if (!Helpers.isFilenameValid(getContext(), file)) {
+ throw new FileNotFoundException("Invalid file path: " + file);
}
- final File file = new File(path);
- if ("r".equals(mode)) {
- return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ final int pfdMode = ParcelFileDescriptor.parseMode(mode);
+ if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY) {
+ return ParcelFileDescriptor.open(file, pfdMode);
} else {
try {
// When finished writing, update size and timestamp
- return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode),
- mHandler, new OnCloseListener() {
- @Override
- public void onClose(IOException e) {
- final ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, file.length());
- values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
- System.currentTimeMillis());
- update(uri, values, null, null);
- }
- });
+ return ParcelFileDescriptor.open(file, pfdMode, mHandler, new OnCloseListener() {
+ @Override
+ public void onClose(IOException e) {
+ final ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, file.length());
+ values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
+ System.currentTimeMillis());
+ update(uri, values, null, null);
+
+ if (shouldScan) {
+ final Intent intent = new Intent(
+ Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(Uri.fromFile(file));
+ getContext().sendBroadcast(intent);
+ }
+ }
+ });
} catch (IOException e) {
throw new FileNotFoundException("Failed to open for writing: " + e);
}
@@ -1275,29 +1313,35 @@ public final class DownloadProvider extends ContentProvider {
if (cursor == null) {
Log.v(Constants.TAG, "null cursor in openFile");
} else {
- if (!cursor.moveToFirst()) {
- Log.v(Constants.TAG, "empty cursor in openFile");
- } else {
- do {
- Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available");
- } while(cursor.moveToNext());
+ try {
+ if (!cursor.moveToFirst()) {
+ Log.v(Constants.TAG, "empty cursor in openFile");
+ } else {
+ do {
+ Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available");
+ } while(cursor.moveToNext());
+ }
+ } finally {
+ cursor.close();
}
- cursor.close();
}
cursor = query(uri, new String[] { "_data" }, null, null, null);
if (cursor == null) {
Log.v(Constants.TAG, "null cursor in openFile");
} else {
- if (!cursor.moveToFirst()) {
- Log.v(Constants.TAG, "empty cursor in openFile");
- } else {
- String filename = cursor.getString(0);
- Log.v(Constants.TAG, "filename in openFile: " + filename);
- if (new java.io.File(filename).isFile()) {
- Log.v(Constants.TAG, "file exists in openFile");
+ try {
+ if (!cursor.moveToFirst()) {
+ Log.v(Constants.TAG, "empty cursor in openFile");
+ } else {
+ String filename = cursor.getString(0);
+ Log.v(Constants.TAG, "filename in openFile: " + filename);
+ if (new java.io.File(filename).isFile()) {
+ Log.v(Constants.TAG, "file exists in openFile");
+ }
}
+ } finally {
+ cursor.close();
}
- cursor.close();
}
}