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.java252
1 files changed, 156 insertions, 96 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index f0190fd1..d7c24f9a 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -21,7 +21,9 @@ 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.content.pm.PackageManager.NameNotFoundException;
import android.database.CrossProcessCursor;
import android.database.Cursor;
import android.database.CursorWindow;
@@ -76,21 +78,21 @@ public final class DownloadProvider extends ContentProvider {
}
private static final String[] sAppReadableColumnsArray = new String[] {
- Downloads._ID,
- Downloads.COLUMN_APP_DATA,
- Downloads._DATA,
- Downloads.COLUMN_MIME_TYPE,
- Downloads.COLUMN_VISIBILITY,
- Downloads.COLUMN_DESTINATION,
- Downloads.COLUMN_CONTROL,
- Downloads.COLUMN_STATUS,
- Downloads.COLUMN_LAST_MODIFICATION,
- Downloads.COLUMN_NOTIFICATION_PACKAGE,
- Downloads.COLUMN_NOTIFICATION_CLASS,
- Downloads.COLUMN_TOTAL_BYTES,
- Downloads.COLUMN_CURRENT_BYTES,
- Downloads.COLUMN_TITLE,
- Downloads.COLUMN_DESCRIPTION
+ Downloads.Impl._ID,
+ Downloads.Impl.COLUMN_APP_DATA,
+ Downloads.Impl._DATA,
+ Downloads.Impl.COLUMN_MIME_TYPE,
+ Downloads.Impl.COLUMN_VISIBILITY,
+ Downloads.Impl.COLUMN_DESTINATION,
+ Downloads.Impl.COLUMN_CONTROL,
+ Downloads.Impl.COLUMN_STATUS,
+ Downloads.Impl.COLUMN_LAST_MODIFICATION,
+ Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
+ Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
+ Downloads.Impl.COLUMN_TOTAL_BYTES,
+ Downloads.Impl.COLUMN_CURRENT_BYTES,
+ Downloads.Impl.COLUMN_TITLE,
+ Downloads.Impl.COLUMN_DESCRIPTION
};
private static HashSet<String> sAppReadableColumnsSet;
@@ -104,6 +106,10 @@ public final class DownloadProvider extends ContentProvider {
/** The database that lies underneath this content provider */
private SQLiteOpenHelper mOpenHelper = null;
+ /** List of uids that can access the downloads */
+ private int mSystemUid = -1;
+ private int mDefContainerUid = -1;
+
/**
* Creates and updated database on demand when opening it.
* Helper class to create database the first time the provider is
@@ -167,6 +173,21 @@ public final class DownloadProvider extends ContentProvider {
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
+ // Initialize the system uid
+ mSystemUid = Process.SYSTEM_UID;
+ // Initialize the default container uid. Package name hardcoded
+ // for now.
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = getContext().getPackageManager().
+ getApplicationInfo("com.android.defcontainer", 0);
+ } catch (NameNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ if (appInfo != null) {
+ mDefContainerUid = appInfo.uid;
+ }
return true;
}
@@ -199,35 +220,35 @@ public final class DownloadProvider extends ContentProvider {
private void createTable(SQLiteDatabase db) {
try {
db.execSQL("CREATE TABLE " + DB_TABLE + "(" +
- Downloads._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Downloads.COLUMN_URI + " TEXT, " +
+ Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ Downloads.Impl.COLUMN_URI + " TEXT, " +
Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " +
- Downloads.COLUMN_APP_DATA + " TEXT, " +
- Downloads.COLUMN_NO_INTEGRITY + " BOOLEAN, " +
- Downloads.COLUMN_FILE_NAME_HINT + " TEXT, " +
+ Downloads.Impl.COLUMN_APP_DATA + " TEXT, " +
+ Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " +
+ Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " +
Constants.OTA_UPDATE + " BOOLEAN, " +
- Downloads._DATA + " TEXT, " +
- Downloads.COLUMN_MIME_TYPE + " TEXT, " +
- Downloads.COLUMN_DESTINATION + " INTEGER, " +
+ Downloads.Impl._DATA + " TEXT, " +
+ Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " +
+ Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " +
Constants.NO_SYSTEM_FILES + " BOOLEAN, " +
- Downloads.COLUMN_VISIBILITY + " INTEGER, " +
- Downloads.COLUMN_CONTROL + " INTEGER, " +
- Downloads.COLUMN_STATUS + " INTEGER, " +
+ Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " +
+ Downloads.Impl.COLUMN_CONTROL + " INTEGER, " +
+ Downloads.Impl.COLUMN_STATUS + " INTEGER, " +
Constants.FAILED_CONNECTIONS + " INTEGER, " +
- Downloads.COLUMN_LAST_MODIFICATION + " BIGINT, " +
- Downloads.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " +
- Downloads.COLUMN_NOTIFICATION_CLASS + " TEXT, " +
- Downloads.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " +
- Downloads.COLUMN_COOKIE_DATA + " TEXT, " +
- Downloads.COLUMN_USER_AGENT + " TEXT, " +
- Downloads.COLUMN_REFERER + " TEXT, " +
- Downloads.COLUMN_TOTAL_BYTES + " INTEGER, " +
- Downloads.COLUMN_CURRENT_BYTES + " INTEGER, " +
+ Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " +
+ Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " +
+ Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " +
+ Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " +
+ Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " +
+ Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " +
+ Downloads.Impl.COLUMN_REFERER + " TEXT, " +
+ Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " +
+ Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " +
Constants.ETAG + " TEXT, " +
Constants.UID + " INTEGER, " +
- Downloads.COLUMN_OTHER_UID + " INTEGER, " +
- Downloads.COLUMN_TITLE + " TEXT, " +
- Downloads.COLUMN_DESCRIPTION + " TEXT, " +
+ Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " +
+ Downloads.Impl.COLUMN_TITLE + " TEXT, " +
+ Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " +
Constants.MEDIA_SCANNED + " BOOLEAN);");
} catch (SQLException ex) {
Log.e(Constants.TAG, "couldn't create table in downloads database");
@@ -263,70 +284,71 @@ public final class DownloadProvider extends ContentProvider {
ContentValues filteredValues = new ContentValues();
- copyString(Downloads.COLUMN_URI, values, filteredValues);
- copyString(Downloads.COLUMN_APP_DATA, values, filteredValues);
- copyBoolean(Downloads.COLUMN_NO_INTEGRITY, values, filteredValues);
- copyString(Downloads.COLUMN_FILE_NAME_HINT, values, filteredValues);
- copyString(Downloads.COLUMN_MIME_TYPE, values, filteredValues);
- Integer dest = values.getAsInteger(Downloads.COLUMN_DESTINATION);
+ copyString(Downloads.Impl.COLUMN_URI, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues);
+ copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues);
+ Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION);
if (dest != null) {
- if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED)
+ if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
!= PackageManager.PERMISSION_GRANTED
- && dest != Downloads.DESTINATION_EXTERNAL
- && dest != Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) {
+ && dest != Downloads.Impl.DESTINATION_EXTERNAL
+ && dest != Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) {
throw new SecurityException("unauthorized destination code");
}
- filteredValues.put(Downloads.COLUMN_DESTINATION, dest);
+ filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest);
}
- Integer vis = values.getAsInteger(Downloads.COLUMN_VISIBILITY);
+ Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY);
if (vis == null) {
- if (dest == Downloads.DESTINATION_EXTERNAL) {
- filteredValues.put(Downloads.COLUMN_VISIBILITY,
- Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
+ if (dest == Downloads.Impl.DESTINATION_EXTERNAL) {
+ filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY,
+ Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
} else {
- filteredValues.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_HIDDEN);
+ filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY,
+ Downloads.Impl.VISIBILITY_HIDDEN);
}
} else {
- filteredValues.put(Downloads.COLUMN_VISIBILITY, vis);
+ filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis);
}
- copyInteger(Downloads.COLUMN_CONTROL, values, filteredValues);
- filteredValues.put(Downloads.COLUMN_STATUS, Downloads.STATUS_PENDING);
- filteredValues.put(Downloads.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
- String pckg = values.getAsString(Downloads.COLUMN_NOTIFICATION_PACKAGE);
- String clazz = values.getAsString(Downloads.COLUMN_NOTIFICATION_CLASS);
+ copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
+ filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
+ filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
+ String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE);
+ String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS);
if (pckg != null && clazz != null) {
int uid = Binder.getCallingUid();
try {
if (uid == 0 ||
getContext().getPackageManager().getApplicationInfo(pckg, 0).uid == uid) {
- filteredValues.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, pckg);
- filteredValues.put(Downloads.COLUMN_NOTIFICATION_CLASS, clazz);
+ filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg);
+ filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz);
}
} catch (PackageManager.NameNotFoundException ex) {
/* ignored for now */
}
}
- copyString(Downloads.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues);
- copyString(Downloads.COLUMN_COOKIE_DATA, values, filteredValues);
- copyString(Downloads.COLUMN_USER_AGENT, values, filteredValues);
- copyString(Downloads.COLUMN_REFERER, values, filteredValues);
- if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED)
+ copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues);
+ if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
== PackageManager.PERMISSION_GRANTED) {
- copyInteger(Downloads.COLUMN_OTHER_UID, values, filteredValues);
+ copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues);
}
filteredValues.put(Constants.UID, Binder.getCallingUid());
if (Binder.getCallingUid() == 0) {
copyInteger(Constants.UID, values, filteredValues);
}
- copyString(Downloads.COLUMN_TITLE, values, filteredValues);
- copyString(Downloads.COLUMN_DESCRIPTION, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues);
if (Constants.LOGVV) {
Log.v(Constants.TAG, "initiating download with UID "
+ filteredValues.getAsInteger(Constants.UID));
- if (filteredValues.containsKey(Downloads.COLUMN_OTHER_UID)) {
+ if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) {
Log.v(Constants.TAG, "other UID " +
- filteredValues.getAsInteger(Downloads.COLUMN_OTHER_UID));
+ filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID));
}
}
@@ -339,7 +361,7 @@ public final class DownloadProvider extends ContentProvider {
if (rowID != -1) {
context.startService(new Intent(context, DownloadService.class));
- ret = Uri.parse(Downloads.CONTENT_URI + "/" + rowID);
+ ret = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + rowID);
context.getContentResolver().notifyChange(uri, null);
} else {
if (Config.LOGD) {
@@ -373,7 +395,7 @@ public final class DownloadProvider extends ContentProvider {
}
case DOWNLOADS_ID: {
qb.setTables(DB_TABLE);
- qb.appendWhere(Downloads._ID + "=");
+ qb.appendWhere(Downloads.Impl._ID + "=");
qb.appendWhere(uri.getPathSegments().get(1));
emptyWhere = false;
break;
@@ -386,25 +408,45 @@ public final class DownloadProvider extends ContentProvider {
}
}
- if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0 &&
+ int callingUid = Binder.getCallingUid();
+ if (Binder.getCallingPid() != Process.myPid() &&
+ callingUid != mSystemUid &&
+ callingUid != mDefContainerUid &&
Process.supportsProcesses()) {
- if (!emptyWhere) {
- qb.appendWhere(" AND ");
- }
- qb.appendWhere("( " + Constants.UID + "=" + Binder.getCallingUid() + " OR "
- + Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )");
- emptyWhere = false;
-
+ boolean canSeeAllExternal;
if (projection == null) {
projection = sAppReadableColumnsArray;
+ // sAppReadableColumnsArray includes _DATA, which is not allowed
+ // to be seen except by the initiating application
+ canSeeAllExternal = false;
} else {
+ canSeeAllExternal = getContext().checkCallingPermission(
+ Downloads.Impl.PERMISSION_SEE_ALL_EXTERNAL)
+ == PackageManager.PERMISSION_GRANTED;
for (int i = 0; i < projection.length; ++i) {
if (!sAppReadableColumnsSet.contains(projection[i])) {
throw new IllegalArgumentException(
"column " + projection[i] + " is not allowed in queries");
}
+ canSeeAllExternal = canSeeAllExternal
+ && !projection[i].equals(Downloads.Impl._DATA);
}
}
+ if (!emptyWhere) {
+ qb.appendWhere(" AND ");
+ emptyWhere = false;
+ }
+ String validUid = "( " + Constants.UID + "="
+ + Binder.getCallingUid() + " OR "
+ + Downloads.Impl.COLUMN_OTHER_UID + "="
+ + Binder.getCallingUid() + " )";
+ if (canSeeAllExternal) {
+ qb.appendWhere("( " + validUid + " OR "
+ + Downloads.Impl.DESTINATION_EXTERNAL + " = "
+ + Downloads.Impl.COLUMN_DESTINATION + " )");
+ } else {
+ qb.appendWhere(validUid);
+ }
}
if (Constants.LOGVV) {
@@ -489,18 +531,28 @@ public final class DownloadProvider extends ContentProvider {
ContentValues filteredValues;
if (Binder.getCallingPid() != Process.myPid()) {
filteredValues = new ContentValues();
- copyString(Downloads.COLUMN_APP_DATA, values, filteredValues);
- copyInteger(Downloads.COLUMN_VISIBILITY, values, filteredValues);
- Integer i = values.getAsInteger(Downloads.COLUMN_CONTROL);
+ copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues);
+ copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues);
+ Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL);
if (i != null) {
- filteredValues.put(Downloads.COLUMN_CONTROL, i);
+ filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i);
startService = true;
}
- copyInteger(Downloads.COLUMN_CONTROL, values, filteredValues);
- copyString(Downloads.COLUMN_TITLE, values, filteredValues);
- copyString(Downloads.COLUMN_DESCRIPTION, values, filteredValues);
+ copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues);
+ copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues);
} else {
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) == null) {
+ values.put(Downloads.Impl.COLUMN_TITLE,
+ new File(filename).getName());
+ }
+ c.close();
+ }
}
int match = sURIMatcher.match(uri);
switch (match) {
@@ -519,11 +571,14 @@ public final class DownloadProvider extends ContentProvider {
if (match == DOWNLOADS_ID) {
String segment = uri.getPathSegments().get(1);
rowId = Long.parseLong(segment);
- myWhere += " ( " + Downloads._ID + " = " + rowId + " ) ";
+ myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) ";
}
- if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
+ int callingUid = Binder.getCallingUid();
+ if (Binder.getCallingPid() != Process.myPid() &&
+ callingUid != mSystemUid &&
+ callingUid != mDefContainerUid) {
myWhere += " AND ( " + Constants.UID + "=" + Binder.getCallingUid() + " OR "
- + Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )";
+ + Downloads.Impl.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )";
}
if (filteredValues.size() > 0) {
count = db.update(DB_TABLE, filteredValues, myWhere, whereArgs);
@@ -575,11 +630,15 @@ public final class DownloadProvider extends ContentProvider {
if (match == DOWNLOADS_ID) {
String segment = uri.getPathSegments().get(1);
long rowId = Long.parseLong(segment);
- myWhere += " ( " + Downloads._ID + " = " + rowId + " ) ";
+ myWhere += " ( " + Downloads.Impl._ID + " = " + rowId + " ) ";
}
- if (Binder.getCallingPid() != Process.myPid() && Binder.getCallingUid() != 0) {
+ int callingUid = Binder.getCallingUid();
+ if (Binder.getCallingPid() != Process.myPid() &&
+ callingUid != mSystemUid &&
+ callingUid != mDefContainerUid) {
myWhere += " AND ( " + Constants.UID + "=" + Binder.getCallingUid() + " OR "
- + Downloads.COLUMN_OTHER_UID + "=" + Binder.getCallingUid() + " )";
+ + Downloads.Impl.COLUMN_OTHER_UID + "="
+ + Binder.getCallingUid() + " )";
}
count = db.delete(DB_TABLE, myWhere, whereArgs);
break;
@@ -604,7 +663,8 @@ public final class DownloadProvider extends ContentProvider {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode
+ ", uid: " + Binder.getCallingUid());
- Cursor cursor = query(Downloads.CONTENT_URI, new String[] { "_id" }, null, null, "_id");
+ Cursor cursor = query(Downloads.Impl.CONTENT_URI,
+ new String[] { "_id" }, null, null, "_id");
if (cursor == null) {
Log.v(Constants.TAG, "null cursor in openFile");
} else {
@@ -673,7 +733,7 @@ public final class DownloadProvider extends ContentProvider {
throw new FileNotFoundException("couldn't open file");
} else {
ContentValues values = new ContentValues();
- values.put(Downloads.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
+ values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, System.currentTimeMillis());
update(uri, values, null, null);
}
return ret;