Commit 71aab521 authored by Steve Howard's avatar Steve Howard
Browse files

Support for non-purgeable downloads through the public API.

This change adds a permission,
android.permission.DOWNLOAD_CACHE_NON_PURGEABLE.  When an app has this
permission, any downloads it requests through the public API to the
download cache will automatically become non-purgeable, i.e. they'll
never be automatically deleted by the download manager to free up
space.  This is intended for use only by the system updater.

Change-Id: I35cdd44f7e5d46bc70443d1a9743f61a51395ddb
parent b06b739b
......@@ -21,6 +21,12 @@
android:description="@string/permdesc_downloadCompletedIntent"
android:protectionLevel="signature" />
<!-- Allows to download non-purgeable files to the cache partition through the public API -->
<permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE"
android:label="@string/permlab_downloadCacheNonPurgeable"
android:description="@string/permdesc_downloadCacheNonPurgeable"
android:protectionLevel="dangerous"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<uses-permission android:name="android.permission.ACCESS_DRM" />
......
......@@ -73,6 +73,15 @@
<string name="permdesc_seeAllExternal">Allows the application to see all
downloads to the SD card, regardless of which application downloaded
them.</string>
<string name="permlab_downloadCacheNonPurgeable">Download non-purgeable
files to the cache</string>
<string name="permdesc_downloadCacheNonPurgeable">Allows the application to
download files to the download cache through the public API which will not
be automatically deleted when the download manager needs more space.
Malicious applications can use this to block other applications from using
the download cache.</string>
<!-- This is the title that is used when displaying the notification
for a download that doesn't have a title associated with it. -->
<string name="download_unknown_title">&lt;Untitled&gt;</string>
......
......@@ -337,6 +337,11 @@ public final class DownloadProvider extends ContentProvider {
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);
copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues);
boolean isPublicApi =
values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE;
Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION);
if (dest != null) {
if (getContext().checkCallingPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED)
......@@ -346,6 +351,16 @@ public final class DownloadProvider extends ContentProvider {
&& dest != Downloads.Impl.DESTINATION_FILE_URI) {
throw new SecurityException("unauthorized destination code");
}
// for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically
// switch to non-purgeable download
boolean hasNonPurgeablePermission =
getContext().checkCallingPermission(
Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE)
== PackageManager.PERMISSION_GRANTED;
if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE
&& hasNonPurgeablePermission) {
dest = Downloads.Impl.DESTINATION_CACHE_PARTITION;
}
if (dest == Downloads.Impl.DESTINATION_FILE_URI) {
getContext().enforcePermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
......@@ -372,10 +387,6 @@ public final class DownloadProvider extends ContentProvider {
filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
mSystemFacade.currentTimeMillis());
copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues);
boolean isPublicApi =
values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE;
String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE);
String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS);
if (pckg != null && (clazz != null || isPublicApi)) {
......@@ -846,7 +857,7 @@ public final class DownloadProvider extends ContentProvider {
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
private void appendClause(StringBuilder whereClause, String newClause) {
if (whereClause.length() != 0) {
whereClause.append(" AND ");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment