157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/* 257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * 457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * you may not use this file except in compliance with the License. 657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * You may obtain a copy of the License at 757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * 857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * 1057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * See the License for the specific language governing permissions and 1457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * limitations under the License. 1557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 1657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpackage com.android.providers.downloads; 1857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 193a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkeyimport static android.provider.BaseColumns._ID; 20053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkeyimport static android.provider.Downloads.Impl.COLUMN_DESTINATION; 21053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkeyimport static android.provider.Downloads.Impl.COLUMN_MEDIA_SCANNED; 22053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkeyimport static android.provider.Downloads.Impl.COLUMN_MIME_TYPE; 23053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkeyimport static android.provider.Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD; 243a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkeyimport static android.provider.Downloads.Impl._DATA; 253a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey 26ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkeyimport android.app.AppOpsManager; 273ca67748bc92eac89f731796c5597ff1fbe9217bVasu Noriimport android.app.DownloadManager; 2851cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkeyimport android.app.DownloadManager.Request; 293a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkeyimport android.app.job.JobScheduler; 3057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentProvider; 31efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkeyimport android.content.ContentResolver; 323d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howardimport android.content.ContentUris; 3357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.ContentValues; 3457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Context; 3557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.Intent; 3657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.UriMatcher; 3791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.ApplicationInfo; 3857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.content.pm.PackageManager; 3991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapuimport android.content.pm.PackageManager.NameNotFoundException; 4057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.Cursor; 413ca67748bc92eac89f731796c5597ff1fbe9217bVasu Noriimport android.database.DatabaseUtils; 42c6f5aad265cfc36a64cd2bdb5adf3cc9736bbd80Jean-Baptiste Queruimport android.database.SQLException; 4357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 4457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 45b759707b80987d0cb4ad2a3a78c11702a45a36c2Ben Linimport android.database.sqlite.SQLiteQueryBuilder; 4657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.net.Uri; 4757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Binder; 4857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.ParcelFileDescriptor; 49c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkeyimport android.os.ParcelFileDescriptor.OnCloseListener; 5057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.os.Process; 511d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkeyimport android.provider.BaseColumns; 5257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport android.provider.Downloads; 539b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkeyimport android.provider.OpenableColumns; 54c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkeyimport android.text.TextUtils; 551d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkeyimport android.text.format.DateUtils; 569b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongkerimport android.util.Log; 5757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 583a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 593a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey 60ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkeyimport libcore.io.IoUtils; 61ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey 629b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkeyimport com.google.android.collect.Maps; 635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport com.google.common.annotations.VisibleForTesting; 645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.io.File; 661d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkeyimport java.io.FileDescriptor; 6757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectimport java.io.FileNotFoundException; 68d195a5c677e575ba7e96e9366d0823c3c822231dJeff Sharkeyimport java.io.IOException; 691d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkeyimport java.io.PrintWriter; 70e610c0502c00689411624c00c3f81497df93b202Steve Howardimport java.util.ArrayList; 7101d0182d86db003b2da5b831cb26820093888d9aVasu Noriimport java.util.Arrays; 729b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkeyimport java.util.HashMap; 731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Projectimport java.util.HashSet; 74e61798da80558450f580ed948d0d469bd6423d8eSteve Howardimport java.util.Iterator; 75e610c0502c00689411624c00c3f81497df93b202Steve Howardimport java.util.List; 765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howardimport java.util.Map; 771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 7857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project/** 7957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Allows application to interact with the download manager. 8057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 8157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Projectpublic final class DownloadProvider extends ContentProvider { 8257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Database filename */ 8357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_NAME = "downloads.db"; 841fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /** Current database version */ 853a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey private static final int DB_VERSION = 110; 8657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** Name of table in the database */ 8757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DB_TABLE = "downloads"; 88635e12dcdf24215246615c78c5de6b883cb00a0fFyodor Kupolov /** Memory optimization - close idle connections after 30s of inactivity */ 89635e12dcdf24215246615c78c5de6b883cb00a0fFyodor Kupolov private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000; 9057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 9157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for the entire download list */ 9257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download"; 9357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** MIME type for an individual download */ 9457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download"; 9557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 9657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher used to recognize URIs sent by applications */ 9757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 983d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads belonging to the calling UID */ 993d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS = 1; 1003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of an individual download belonging to the calling UID */ 1013d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int MY_DOWNLOADS_ID = 2; 1023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** URI matcher constant for the URI of all downloads in the system */ 1033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS = 3; 10457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** URI matcher constant for the URI of an individual download */ 1053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int ALL_DOWNLOADS_ID = 4; 1065224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** URI matcher constant for the URI of a download's request headers */ 1073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final int REQUEST_HEADERS_URI = 5; 1083ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori /** URI matcher constant for the public URI returned by 1093ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori * {@link DownloadManager#getUriForDownloadedFile(long)} if the given downloaded file 1103ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori * is publicly accessible. 1113ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori */ 1123ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori private static final int PUBLIC_DOWNLOAD_ID = 6; 11357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project static { 1143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads", MY_DOWNLOADS); 1153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "my_downloads/#", MY_DOWNLOADS_ID); 1163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads", ALL_DOWNLOADS); 1173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", "all_downloads/#", ALL_DOWNLOADS_ID); 1183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 1193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "my_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 1203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 1213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sURIMatcher.addURI("downloads", 1223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard "all_downloads/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 1233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard REQUEST_HEADERS_URI); 1244bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard // temporary, for backwards compatibility 1254bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download", MY_DOWNLOADS); 1264bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", "download/#", MY_DOWNLOADS_ID); 1274bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard sURIMatcher.addURI("downloads", 1284bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard "download/#/" + Downloads.Impl.RequestHeaders.URI_SEGMENT, 1294bebe75b3e2361d7fb0aa966598c41c45ad9317fSteve Howard REQUEST_HEADERS_URI); 1303ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori sURIMatcher.addURI("downloads", 1313ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori Downloads.Impl.PUBLICLY_ACCESSIBLE_DOWNLOADS_URI_SEGMENT + "/#", 1323ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori PUBLIC_DOWNLOAD_ID); 13357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 13457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 1353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** Different base URIs that could be used to access an individual download */ 1363d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private static final Uri[] BASE_URIS = new Uri[] { 1373d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.CONTENT_URI, 1383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 1393d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard }; 1403d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 1411fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final String[] sAppReadableColumnsArray = new String[] { 1427dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._ID, 1437dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_APP_DATA, 1447dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl._DATA, 1457dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_MIME_TYPE, 1467dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_VISIBILITY, 1477dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_DESTINATION, 1487dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CONTROL, 1497dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_STATUS, 1507dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_LAST_MODIFICATION, 1517dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, 1527dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_NOTIFICATION_CLASS, 1537dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TOTAL_BYTES, 1547dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_CURRENT_BYTES, 1557dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.COLUMN_TITLE, 1560a77c62a82503b38c484e0079648f0231dd85d53Steve Howard Downloads.Impl.COLUMN_DESCRIPTION, 1570d8d89105c00edbad95a268aaae65f2ff94ed5a1Steve Howard Downloads.Impl.COLUMN_URI, 15871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 159b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT, 160e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, 161e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori Downloads.Impl.COLUMN_DELETED, 1629b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey OpenableColumns.DISPLAY_NAME, 1639b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey OpenableColumns.SIZE, 1641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project }; 1651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1669b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey private static final HashSet<String> sAppReadableColumnsSet; 1679b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey private static final HashMap<String, String> sColumnsMap; 1689b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey 1691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project static { 1701fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet = new HashSet<String>(); 1711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < sAppReadableColumnsArray.length; ++i) { 1721fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]); 1731fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1749b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey 1759b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey sColumnsMap = Maps.newHashMap(); 1769b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey sColumnsMap.put(OpenableColumns.DISPLAY_NAME, 1779b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey Downloads.Impl.COLUMN_TITLE + " AS " + OpenableColumns.DISPLAY_NAME); 1789b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey sColumnsMap.put(OpenableColumns.SIZE, 1799b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + OpenableColumns.SIZE); 1801fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 18101d0182d86db003b2da5b831cb26820093888d9aVasu Nori private static final List<String> downloadManagerColumnsList = 18201d0182d86db003b2da5b831cb26820093888d9aVasu Nori Arrays.asList(DownloadManager.UNDERLYING_COLUMNS); 1831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1843a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey @VisibleForTesting 1853a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey SystemFacade mSystemFacade; 186c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey 18757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** The database that lies underneath this content provider */ 18857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private SQLiteOpenHelper mOpenHelper = null; 18957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 19091e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu /** List of uids that can access the downloads */ 19191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mSystemUid = -1; 19291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu private int mDefContainerUid = -1; 19391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu 19457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 195e610c0502c00689411624c00c3f81497df93b202Steve Howard * This class encapsulates a SQL where clause and its parameters. It makes it possible for 196e610c0502c00689411624c00c3f81497df93b202Steve Howard * shared methods (like {@link DownloadProvider#getWhereClause(Uri, String, String[], int)}) 197e610c0502c00689411624c00c3f81497df93b202Steve Howard * to return both pieces of information, and provides some utility logic to ease piece-by-piece 198e610c0502c00689411624c00c3f81497df93b202Steve Howard * construction of selections. 199e610c0502c00689411624c00c3f81497df93b202Steve Howard */ 200e610c0502c00689411624c00c3f81497df93b202Steve Howard private static class SqlSelection { 201e610c0502c00689411624c00c3f81497df93b202Steve Howard public StringBuilder mWhereClause = new StringBuilder(); 202e610c0502c00689411624c00c3f81497df93b202Steve Howard public List<String> mParameters = new ArrayList<String>(); 203e610c0502c00689411624c00c3f81497df93b202Steve Howard 204e610c0502c00689411624c00c3f81497df93b202Steve Howard public <T> void appendClause(String newClause, final T... parameters) { 205e610c0502c00689411624c00c3f81497df93b202Steve Howard if (newClause == null || newClause.isEmpty()) { 206e610c0502c00689411624c00c3f81497df93b202Steve Howard return; 207e610c0502c00689411624c00c3f81497df93b202Steve Howard } 208e610c0502c00689411624c00c3f81497df93b202Steve Howard if (mWhereClause.length() != 0) { 209e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(" AND "); 210e610c0502c00689411624c00c3f81497df93b202Steve Howard } 211e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append("("); 212e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(newClause); 213e610c0502c00689411624c00c3f81497df93b202Steve Howard mWhereClause.append(")"); 214e610c0502c00689411624c00c3f81497df93b202Steve Howard if (parameters != null) { 215e610c0502c00689411624c00c3f81497df93b202Steve Howard for (Object parameter : parameters) { 216e610c0502c00689411624c00c3f81497df93b202Steve Howard mParameters.add(parameter.toString()); 217e610c0502c00689411624c00c3f81497df93b202Steve Howard } 218e610c0502c00689411624c00c3f81497df93b202Steve Howard } 219e610c0502c00689411624c00c3f81497df93b202Steve Howard } 220e610c0502c00689411624c00c3f81497df93b202Steve Howard 221e610c0502c00689411624c00c3f81497df93b202Steve Howard public String getSelection() { 222e610c0502c00689411624c00c3f81497df93b202Steve Howard return mWhereClause.toString(); 223e610c0502c00689411624c00c3f81497df93b202Steve Howard } 224e610c0502c00689411624c00c3f81497df93b202Steve Howard 225e610c0502c00689411624c00c3f81497df93b202Steve Howard public String[] getParameters() { 226e610c0502c00689411624c00c3f81497df93b202Steve Howard String[] array = new String[mParameters.size()]; 227e610c0502c00689411624c00c3f81497df93b202Steve Howard return mParameters.toArray(array); 228e610c0502c00689411624c00c3f81497df93b202Steve Howard } 229e610c0502c00689411624c00c3f81497df93b202Steve Howard } 230e610c0502c00689411624c00c3f81497df93b202Steve Howard 231e610c0502c00689411624c00c3f81497df93b202Steve Howard /** 23257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates and updated database on demand when opening it. 23357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Helper class to create database the first time the provider is 23457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * initialized and upgrade it when a new version of the provider needs 23557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * an updated version of the database. 23657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 23757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project private final class DatabaseHelper extends SQLiteOpenHelper { 23857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public DatabaseHelper(final Context context) { 23957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project super(context, DB_NAME, null, DB_VERSION); 240635e12dcdf24215246615c78c5de6b883cb00a0fFyodor Kupolov setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); 24157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 24257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 24357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 24457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Creates database the first time we try to open it. 24557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 24657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 24757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public void onCreate(final SQLiteDatabase db) { 24857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 2499b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "populating new database"); 25057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 2515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard onUpgrade(db, 0, DB_VERSION); 25257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 25357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 25457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 25557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates the database format when a content provider is used 25657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * with a database that was created with a different format. 2575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * 2585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Note: to support downgrades, creating a table should always drop it first if it already 2595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * exists. 26057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 26157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 2621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public void onUpgrade(final SQLiteDatabase db, int oldV, final int newV) { 2635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (oldV == 31) { 2645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // 31 and 100 are identical, just in different codelines. Upgrading from 31 is the 2655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // same as upgrading from 100. 2665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 100; 2675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV < 100) { 2685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // no logic to upgrade from these older version, just recreate the DB 2699b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.i(Constants.TAG, "Upgrading downloads database from version " + oldV 2705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " to version " + newV + ", which will destroy all old data"); 2715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 2725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } else if (oldV > newV) { 2735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // user must have downgraded software; we have no way to know how to downgrade the 2745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard // DB, so just recreate it 2759b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.i(Constants.TAG, "Downgrading downloads database from version " + oldV 2765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + " (current version is " + newV + "), destroying all old data"); 2775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard oldV = 99; 2785224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2795224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (int version = oldV + 1; version <= newV; version++) { 2815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard upgradeTo(db, version); 2825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 2845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 2865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Upgrade database from (version - 1) to version. 2875224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 2885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void upgradeTo(SQLiteDatabase db, int version) { 2895224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard switch (version) { 2905224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 100: 2915224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createDownloadsTable(db); 2925224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2935224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard case 101: 2955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard createHeadersTable(db); 2965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard break; 2975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 2980a77c62a82503b38c484e0079648f0231dd85d53Steve Howard case 102: 2990a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_PUBLIC_API, 3000a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 3010a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_ROAMING, 3020a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 3030a77c62a82503b38c484e0079648f0231dd85d53Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, 3040a77c62a82503b38c484e0079648f0231dd85d53Steve Howard "INTEGER NOT NULL DEFAULT 0"); 3050a77c62a82503b38c484e0079648f0231dd85d53Steve Howard break; 3060a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 30771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard case 103: 30871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, 30971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard "INTEGER NOT NULL DEFAULT 1"); 31071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard makeCacheDownloadsInvisible(db); 31171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard break; 31271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 313d319729622da1893e895f2e35f41d01ecdca3705Steve Howard case 104: 314d319729622da1893e895f2e35f41d01ecdca3705Steve Howard addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT, 315d319729622da1893e895f2e35f41d01ecdca3705Steve Howard "INTEGER NOT NULL DEFAULT 0"); 316d319729622da1893e895f2e35f41d01ecdca3705Steve Howard break; 317d319729622da1893e895f2e35f41d01ecdca3705Steve Howard 31873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard case 105: 31973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValues(db); 32073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard break; 32173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 322e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori case 106: 323e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, "TEXT"); 324e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_DELETED, 325e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori "BOOLEAN NOT NULL DEFAULT 0"); 326e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori break; 327e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 3289d27069a5453574824860ad3db179599d044e7bdVasu Nori case 107: 3299d27069a5453574824860ad3db179599d044e7bdVasu Nori addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ERROR_MSG, "TEXT"); 3309d27069a5453574824860ad3db179599d044e7bdVasu Nori break; 3319d27069a5453574824860ad3db179599d044e7bdVasu Nori 332a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey case 108: 333a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_METERED, 334a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey "INTEGER NOT NULL DEFAULT 1"); 335a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey break; 336a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey 337c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey case 109: 338c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_WRITE, 339c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey "BOOLEAN NOT NULL DEFAULT 0"); 340c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey break; 341c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey 3423a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey case 110: 3433a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_FLAGS, 3443a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey "INTEGER NOT NULL DEFAULT 0"); 3453a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey break; 3463a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey 3475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard default: 3485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalStateException("Don't know how to upgrade to " + version); 3495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 3505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 3515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 3525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 35373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard * insert() now ensures these four columns are never null for new downloads, so this method 35473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard * makes that true for existing columns, so that code can rely on this assumption. 35573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard */ 35673f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard private void fillNullValues(SQLiteDatabase db) { 35773f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard ContentValues values = new ContentValues(); 35873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 35973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 36073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 36173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 36273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_TITLE, ""); 36373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 36473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.put(Downloads.Impl.COLUMN_DESCRIPTION, ""); 36573f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard fillNullValuesForColumn(db, values); 36673f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard } 36773f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 36873f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard private void fillNullValuesForColumn(SQLiteDatabase db, ContentValues values) { 36973f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard String column = values.valueSet().iterator().next().getKey(); 37073f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard db.update(DB_TABLE, values, column + " is null", null); 37173f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard values.clear(); 37273f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard } 37373f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard 37473f5f223477795e10079d25c1eb5f796af1f00a9Steve Howard /** 37571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard * Set all existing downloads to the cache partition to be invisible in the downloads UI. 37671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard */ 37771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard private void makeCacheDownloadsInvisible(SQLiteDatabase db) { 37871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard ContentValues values = new ContentValues(); 37971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, false); 38071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard String cacheSelection = Downloads.Impl.COLUMN_DESTINATION 38171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard + " != " + Downloads.Impl.DESTINATION_EXTERNAL; 38271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard db.update(DB_TABLE, values, cacheSelection, null); 38371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 38471e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 38571e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard /** 3860a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * Add a column to a table using ALTER TABLE. 3870a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param dbTable name of the table 3880a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnName name of the column to add 3890a77c62a82503b38c484e0079648f0231dd85d53Steve Howard * @param columnDefinition SQL for the column definition 3900a77c62a82503b38c484e0079648f0231dd85d53Steve Howard */ 3910a77c62a82503b38c484e0079648f0231dd85d53Steve Howard private void addColumn(SQLiteDatabase db, String dbTable, String columnName, 3920a77c62a82503b38c484e0079648f0231dd85d53Steve Howard String columnDefinition) { 3930a77c62a82503b38c484e0079648f0231dd85d53Steve Howard db.execSQL("ALTER TABLE " + dbTable + " ADD COLUMN " + columnName + " " 3940a77c62a82503b38c484e0079648f0231dd85d53Steve Howard + columnDefinition); 3950a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 3960a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 3970a77c62a82503b38c484e0079648f0231dd85d53Steve Howard /** 3985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Creates the table that'll hold the download information. 3995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 4005224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createDownloadsTable(SQLiteDatabase db) { 4015224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 4025224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE); 4035224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + DB_TABLE + "(" + 4045224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 4055224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_URI + " TEXT, " + 4065224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.RETRY_AFTER_X_REDIRECT_COUNT + " INTEGER, " + 4075224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_APP_DATA + " TEXT, " + 4085224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NO_INTEGRITY + " BOOLEAN, " + 4095224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_FILE_NAME_HINT + " TEXT, " + 410f20af91262fecce05928167123c8d335b4cfd33dVasu Nori Constants.OTA_UPDATE + " BOOLEAN, " + 4115224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl._DATA + " TEXT, " + 4125224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_MIME_TYPE + " TEXT, " + 4135224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESTINATION + " INTEGER, " + 4145224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.NO_SYSTEM_FILES + " BOOLEAN, " + 4155224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_VISIBILITY + " INTEGER, " + 4165224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CONTROL + " INTEGER, " + 4175224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_STATUS + " INTEGER, " + 41812f5dc46aaa8e28cabfbe25d55f0af68f24ab306Jeff Sharkey Downloads.Impl.COLUMN_FAILED_CONNECTIONS + " INTEGER, " + 4195224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_LAST_MODIFICATION + " BIGINT, " + 4205224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + " TEXT, " + 4215224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_CLASS + " TEXT, " + 4225224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + " TEXT, " + 4235224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_COOKIE_DATA + " TEXT, " + 4245224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_USER_AGENT + " TEXT, " + 4255224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_REFERER + " TEXT, " + 4265224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TOTAL_BYTES + " INTEGER, " + 4275224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_CURRENT_BYTES + " INTEGER, " + 4285224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.ETAG + " TEXT, " + 4295224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Constants.UID + " INTEGER, " + 4305224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_OTHER_UID + " INTEGER, " + 4315224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_TITLE + " TEXT, " + 4325224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.COLUMN_DESCRIPTION + " TEXT, " + 433495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey Downloads.Impl.COLUMN_MEDIA_SCANNED + " BOOLEAN);"); 4345224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } catch (SQLException ex) { 4359b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.e(Constants.TAG, "couldn't create table in downloads database"); 4365224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw ex; 4375224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 4385224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 4395224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 4405224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void createHeadersTable(SQLiteDatabase db) { 4415224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("DROP TABLE IF EXISTS " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE); 4425224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.execSQL("CREATE TABLE " + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE + "(" + 4435224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard "id INTEGER PRIMARY KEY AUTOINCREMENT," + 4445224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + " INTEGER NOT NULL," + 4455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_HEADER + " TEXT NOT NULL," + 4465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE + " TEXT NOT NULL" + 4475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ");"); 44857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 44957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 45057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 45157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 45257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Initializes the content provider when it is created. 45357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 45457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 45557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public boolean onCreate() { 4566d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (mSystemFacade == null) { 457af28400b74de05862b470412a5c92f68e99f59f8Steve Howard mSystemFacade = new RealSystemFacade(getContext()); 4586d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 4596d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard 46057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project mOpenHelper = new DatabaseHelper(getContext()); 46191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the system uid 46291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mSystemUid = Process.SYSTEM_UID; 46391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // Initialize the default container uid. Package name hardcoded 46491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu // for now. 46591e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu ApplicationInfo appInfo = null; 46691e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu try { 46791e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu appInfo = getContext().getPackageManager(). 46891e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu getApplicationInfo("com.android.defcontainer", 0); 46991e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } catch (NameNotFoundException e) { 4709b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.wtf(Constants.TAG, "Could not get ApplicationInfo for com.android.defconatiner", e); 47191e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 47291e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu if (appInfo != null) { 47391e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu mDefContainerUid = appInfo.uid; 47491e4522fa90d969a596058756c24e173df1a6196Suchi Amalapurapu } 4757c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey 4767c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey // Grant access permissions for all known downloads to the owning apps 4777c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 4787c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey final Cursor cursor = db.query(DB_TABLE, new String[] { 4797c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey Downloads.Impl._ID, Constants.UID }, null, null, null, null, null); 4802ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final ArrayList<Long> idsToDelete = new ArrayList<>(); 4817c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey try { 4827c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey while (cursor.moveToNext()) { 4832ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final long downloadId = cursor.getLong(0); 4842ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final int uid = cursor.getInt(1); 4852ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final String ownerPackage = getPackageForUid(uid); 4862ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla if (ownerPackage == null) { 4872ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla idsToDelete.add(downloadId); 4882ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } else { 4892ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla grantAllDownloadsPermission(ownerPackage, downloadId); 4902ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 4917c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } 4927c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } finally { 4937c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey cursor.close(); 4947c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } 4952ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla if (idsToDelete.size() > 0) { 4962ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla Log.i(Constants.TAG, 4972ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla "Deleting downloads with ids " + idsToDelete + " as owner package is missing"); 4982ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla deleteDownloadsWithIds(idsToDelete); 4992ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 50057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return true; 50157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 50257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5032ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla private void deleteDownloadsWithIds(ArrayList<Long> downloadIds) { 5042ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final int N = downloadIds.size(); 5052ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla if (N == 0) { 5062ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla return; 5072ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 5082ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final StringBuilder queryBuilder = new StringBuilder(Downloads.Impl._ID + " in ("); 5092ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla for (int i = 0; i < N; i++) { 5102ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla queryBuilder.append(downloadIds.get(i)); 5112ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla queryBuilder.append((i == N - 1) ? ")" : ","); 5122ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 5132ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla delete(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, queryBuilder.toString(), null); 5142ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 5152ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla 51657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 51757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Returns the content-provider-style MIME types of the various 51857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * types accessible through this content provider. 51957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 52057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 52157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public String getType(final Uri uri) { 52257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 52357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 5249b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey case MY_DOWNLOADS: 5259b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey case ALL_DOWNLOADS: { 52657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return DOWNLOAD_LIST_TYPE; 52757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 5289b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey case MY_DOWNLOADS_ID: 529c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey case ALL_DOWNLOADS_ID: 5303ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori case PUBLIC_DOWNLOAD_ID: { 5313ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori // return the mimetype of this id from the database 5323ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori final String id = getDownloadIdFromUri(uri); 5333ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 534c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey final String mimeType = DatabaseUtils.stringForQuery(db, 5353ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori "SELECT " + Downloads.Impl.COLUMN_MIME_TYPE + " FROM " + DB_TABLE + 5363ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori " WHERE " + Downloads.Impl._ID + " = ?", 5373ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori new String[]{id}); 538c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey if (TextUtils.isEmpty(mimeType)) { 539c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey return DOWNLOAD_TYPE; 540c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey } else { 541c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey return mimeType; 542c3f3d992e415185a8e2d89ab8f8dfbcb538ec21eJeff Sharkey } 5433ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori } 54457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project default: { 54557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 5469b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri); 54757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 54857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown URI: " + uri); 54957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 55057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 55157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 55257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 55357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 55457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Inserts a row in the database 55557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 55657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 55757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public Uri insert(final Uri uri, final ContentValues values) { 558b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkInsertPermissions(values); 55957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 56057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 5613d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // note we disallow inserting into ALL_DOWNLOADS 5623d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int match = sURIMatcher.match(uri); 5633d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match != MY_DOWNLOADS) { 5649b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri); 56557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new IllegalArgumentException("Unknown/Invalid URI " + uri); 56657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 56757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 568b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // copy some of the input values as it 5691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues = new ContentValues(); 5707dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_URI, values, filteredValues); 5717dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 5727dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyBoolean(Downloads.Impl.COLUMN_NO_INTEGRITY, values, filteredValues); 5737dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_FILE_NAME_HINT, values, filteredValues); 5747dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_MIME_TYPE, values, filteredValues); 57571aab521efba9b28779541440c797220ec98ac97Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API, values, filteredValues); 576b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 57771aab521efba9b28779541440c797220ec98ac97Steve Howard boolean isPublicApi = 57871aab521efba9b28779541440c797220ec98ac97Steve Howard values.getAsBoolean(Downloads.Impl.COLUMN_IS_PUBLIC_API) == Boolean.TRUE; 57971aab521efba9b28779541440c797220ec98ac97Steve Howard 580b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // validate the destination column 5817dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer dest = values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION); 582ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (dest != null) { 583dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 5841fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project != PackageManager.PERMISSION_GRANTED 585b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori && (dest == Downloads.Impl.DESTINATION_CACHE_PARTITION 586d635ac295850ba23d528c02b1e5c6eb44b64b22bJeff Sharkey || dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING)) { 5879aadb4b3f2b3c914166ebfae8851fbecaf536f4fVasu Nori throw new SecurityException("setting destination to : " + dest + 5889aadb4b3f2b3c914166ebfae8851fbecaf536f4fVasu Nori " not allowed, unless PERMISSION_ACCESS_ADVANCED is granted"); 5891fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 59071aab521efba9b28779541440c797220ec98ac97Steve Howard // for public API behavior, if an app has CACHE_NON_PURGEABLE permission, automatically 59171aab521efba9b28779541440c797220ec98ac97Steve Howard // switch to non-purgeable download 59271aab521efba9b28779541440c797220ec98ac97Steve Howard boolean hasNonPurgeablePermission = 593dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey getContext().checkCallingOrSelfPermission( 59471aab521efba9b28779541440c797220ec98ac97Steve Howard Downloads.Impl.PERMISSION_CACHE_NON_PURGEABLE) 59571aab521efba9b28779541440c797220ec98ac97Steve Howard == PackageManager.PERMISSION_GRANTED; 59671aab521efba9b28779541440c797220ec98ac97Steve Howard if (isPublicApi && dest == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE 59771aab521efba9b28779541440c797220ec98ac97Steve Howard && hasNonPurgeablePermission) { 59871aab521efba9b28779541440c797220ec98ac97Steve Howard dest = Downloads.Impl.DESTINATION_CACHE_PARTITION; 59971aab521efba9b28779541440c797220ec98ac97Steve Howard } 6006d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard if (dest == Downloads.Impl.DESTINATION_FILE_URI) { 601b06b739b078ce4b00600487cfec31659647bf31fSteve Howard checkFileUriDestination(values); 602ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey 603ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey } else if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { 604ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey getContext().enforceCallingOrSelfPermission( 605ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 606ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey "No permission to write"); 607ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey 608ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class); 609b8bc2a76ddaa0c59d681913dba10fd7ec0a2a22bJeff Sharkey if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, 610ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey getCallingPackage()) != AppOpsManager.MODE_ALLOWED) { 611ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey throw new SecurityException("No permission to write"); 612ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey } 6136d9b98282c817b86a00f9c19a705da4cb19bc3a6Steve Howard } 6147dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_DESTINATION, dest); 615ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } 616b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 617b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // validate the visibility column 6187dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer vis = values.getAsInteger(Downloads.Impl.COLUMN_VISIBILITY); 619ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru if (vis == null) { 6207dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (dest == Downloads.Impl.DESTINATION_EXTERNAL) { 6217dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 6227dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 623ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 6247dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, 6257dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Downloads.Impl.VISIBILITY_HIDDEN); 6261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 627ce8813afb256269e9e223f72ebced92560201bbbJean-Baptiste Queru } else { 6287dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_VISIBILITY, vis); 62957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 630b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // copy the control column as is 6317dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 632b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 633b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori /* 634b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori * requests coming from 6359b2576f9181fc177dbbc9033c435b1d4049fc2e0Vasu Nori * DownloadManager.addCompletedDownload(String, String, String, 6369b2576f9181fc177dbbc9033c435b1d4049fc2e0Vasu Nori * boolean, String, String, long) need special treatment 637b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori */ 638b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori if (values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION) == 639b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) { 640b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // these requests always are marked as 'completed' 641b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_SUCCESS); 642b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, 643b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori values.getAsLong(Downloads.Impl.COLUMN_TOTAL_BYTES)); 644b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori filteredValues.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 645b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori copyInteger(Downloads.Impl.COLUMN_MEDIA_SCANNED, values, filteredValues); 646b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori copyString(Downloads.Impl._DATA, values, filteredValues); 647c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey copyBoolean(Downloads.Impl.COLUMN_ALLOW_WRITE, values, filteredValues); 648b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori } else { 649b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING); 650b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1); 651b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori filteredValues.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0); 652b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori } 653b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 654b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // set lastupdate to current time 6552c02577af19bf11714220d14cfc96d2c017ac1abVasu Nori long lastMod = mSystemFacade.currentTimeMillis(); 6562c02577af19bf11714220d14cfc96d2c017ac1abVasu Nori filteredValues.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, lastMod); 6570a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 658b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // use packagename of the caller to set the notification columns 6597dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String pckg = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); 6607dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru String clazz = values.getAsString(Downloads.Impl.COLUMN_NOTIFICATION_CLASS); 6610a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (pckg != null && (clazz != null || isPublicApi)) { 6621fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project int uid = Binder.getCallingUid(); 6631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project try { 6640a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (uid == 0 || mSystemFacade.userOwnsPackage(uid, pckg)) { 6657dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, pckg); 6660a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (clazz != null) { 6670a77c62a82503b38c484e0079648f0231dd85d53Steve Howard filteredValues.put(Downloads.Impl.COLUMN_NOTIFICATION_CLASS, clazz); 6680a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 6691fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 6701fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } catch (PackageManager.NameNotFoundException ex) { 6711fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project /* ignored for now */ 67257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 67357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 674b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 675b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // copy some more columns as is 6767dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, values, filteredValues); 6777dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_COOKIE_DATA, values, filteredValues); 6787dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_USER_AGENT, values, filteredValues); 6797dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_REFERER, values, filteredValues); 680b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 681b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // UID, PID columns 682dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ADVANCED) 6831fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project == PackageManager.PERMISSION_GRANTED) { 6847dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_OTHER_UID, values, filteredValues); 68557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 6861fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues.put(Constants.UID, Binder.getCallingUid()); 6871fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingUid() == 0) { 6881fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project copyInteger(Constants.UID, values, filteredValues); 68957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 690b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 691b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // copy some more columns as is 692a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_TITLE, values, filteredValues, ""); 693a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyStringWithDefault(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues, ""); 69457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 695b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // is_visible_in_downloads_ui column 69671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard if (values.containsKey(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI)) { 69771e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard copyBoolean(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, values, filteredValues); 69871e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } else { 69971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard // by default, make external downloads visible in the UI 70071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isExternal = (dest == null || dest == Downloads.Impl.DESTINATION_EXTERNAL); 70171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard filteredValues.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, isExternal); 70271e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 70371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 704b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // public api requests and networktypes/roaming columns 7050a77c62a82503b38c484e0079648f0231dd85d53Steve Howard if (isPublicApi) { 7060a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyInteger(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, values, filteredValues); 7070a77c62a82503b38c484e0079648f0231dd85d53Steve Howard copyBoolean(Downloads.Impl.COLUMN_ALLOW_ROAMING, values, filteredValues); 708a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey copyBoolean(Downloads.Impl.COLUMN_ALLOW_METERED, values, filteredValues); 7093a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey copyInteger(Downloads.Impl.COLUMN_FLAGS, values, filteredValues); 7100a77c62a82503b38c484e0079648f0231dd85d53Steve Howard } 7110a77c62a82503b38c484e0079648f0231dd85d53Steve Howard 7121fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Constants.LOGVV) { 7139b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "initiating download with UID " 7141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project + filteredValues.getAsInteger(Constants.UID)); 7157dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru if (filteredValues.containsKey(Downloads.Impl.COLUMN_OTHER_UID)) { 7169b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "other UID " + 7177dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.getAsInteger(Downloads.Impl.COLUMN_OTHER_UID)); 7181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 71957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 72057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project long rowID = db.insert(DB_TABLE, null, filteredValues); 7223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (rowID == -1) { 7239b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.d(Constants.TAG, "couldn't insert into downloads database"); 7243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return null; 72557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 72657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard insertRequestHeaders(db, rowID, values); 7282ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla 7292ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla final String callingPackage = getPackageForUid(Binder.getCallingUid()); 7302ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla if (callingPackage == null) { 7312ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla Log.e(Constants.TAG, "Package does not exist for calling uid"); 7322ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla return null; 7332ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 7342ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla grantAllDownloadsPermission(callingPackage, rowID); 7353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 7361225c34df262ece7a9f95ee5fe61c1985bf16df1Jeff Sharkey 7373a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey final long token = Binder.clearCallingIdentity(); 7383a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey try { 7393a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey Helpers.scheduleJob(getContext(), rowID); 7403a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } finally { 7413a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey Binder.restoreCallingIdentity(token); 7423a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } 7431225c34df262ece7a9f95ee5fe61c1985bf16df1Jeff Sharkey 744053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkey if (values.getAsInteger(COLUMN_DESTINATION) == DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD 745053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkey && values.getAsInteger(COLUMN_MEDIA_SCANNED) == 0) { 746053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkey DownloadScanner.requestScanBlocking(getContext(), rowID, values.getAsString(_DATA), 747053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkey values.getAsString(COLUMN_MIME_TYPE)); 748053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkey } 749053674aa4d0ecd7e37dadb8ee37a9cafbdf2f16cJeff Sharkey 7503d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID); 75157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 75257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 7532ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla private String getPackageForUid(int uid) { 7542ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla String[] packages = getContext().getPackageManager().getPackagesForUid(uid); 7552ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla if (packages == null || packages.length == 0) { 7562ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla return null; 7572ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 7582ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla // For permission related purposes, any package belonging to the given uid should work. 7592ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla return packages[0]; 7602ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla } 7612ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla 76257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 763b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Check that the file URI provided for DESTINATION_FILE_URI is valid. 764b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 765b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkFileUriDestination(ContentValues values) { 766b06b739b078ce4b00600487cfec31659647bf31fSteve Howard String fileUri = values.getAsString(Downloads.Impl.COLUMN_FILE_NAME_HINT); 767b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (fileUri == null) { 768b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException( 769b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "DESTINATION_FILE_URI must include a file URI under COLUMN_FILE_NAME_HINT"); 770b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 771b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Uri uri = Uri.parse(fileUri); 7725d81e2447ed77860afecd71583e137178c2c6807Steve Howard String scheme = uri.getScheme(); 7735d81e2447ed77860afecd71583e137178c2c6807Steve Howard if (scheme == null || !scheme.equals("file")) { 774b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new IllegalArgumentException("Not a file URI: " + uri); 775b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 776d195a5c677e575ba7e96e9366d0823c3c822231dJeff Sharkey final String path = uri.getPath(); 777b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard if (path == null) { 778b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard throw new IllegalArgumentException("Invalid file URI: " + uri); 779b9a0ad7182209d4aca708e13e876e9b1b43ffafcSteve Howard } 780ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey 7818c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey final File file; 7828c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey try { 7838c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey file = new File(path).getCanonicalFile(); 7848c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey } catch (IOException e) { 7858c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey throw new SecurityException(e); 7868c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey } 7878c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey 788ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey if (Helpers.isFilenameValidInExternalPackage(getContext(), file, getCallingPackage())) { 789ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey // No permissions required for paths belonging to calling package 790ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey return; 791ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey } else if (Helpers.isFilenameValidInExternal(getContext(), file)) { 792ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey // Otherwise we require write permission 793ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey getContext().enforceCallingOrSelfPermission( 794ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 795ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey "No permission to write to " + file); 796ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey 797ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey final AppOpsManager appOps = getContext().getSystemService(AppOpsManager.class); 798b8bc2a76ddaa0c59d681913dba10fd7ec0a2a22bJeff Sharkey if (appOps.noteProxyOp(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, 799ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey getCallingPackage()) != AppOpsManager.MODE_ALLOWED) { 800ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey throw new SecurityException("No permission to write to " + file); 801d195a5c677e575ba7e96e9366d0823c3c822231dJeff Sharkey } 802ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey 803ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey } else { 804ed30deae5fe5b9de142b44933001c9b098c47712Jeff Sharkey throw new SecurityException("Unsupported path " + file); 805b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 806b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 807b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 808b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 809b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Apps with the ACCESS_DOWNLOAD_MANAGER permission can access this provider freely, subject to 810b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * constraints in the rest of the code. Apps without that may still access this provider through 811b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * the public API, but additional restrictions are imposed. We check those restrictions here. 812b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * 813b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @param values ContentValues provided to insert() 814b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * @throws SecurityException if the caller has insufficient permissions 815b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 816b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void checkInsertPermissions(ContentValues values) { 817b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS) 818b06b739b078ce4b00600487cfec31659647bf31fSteve Howard == PackageManager.PERMISSION_GRANTED) { 819b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 820b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 821b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 822b06b739b078ce4b00600487cfec31659647bf31fSteve Howard getContext().enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, 823b06b739b078ce4b00600487cfec31659647bf31fSteve Howard "INTERNET permission is required to use the download manager"); 824b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 825b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // ensure the request fits within the bounds of a public API request 826b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // first copy so we can remove values 827b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values = new ContentValues(values); 828b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 829b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // check columns whose values are restricted 830b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_IS_PUBLIC_API, Boolean.TRUE); 831b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori 832b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori // validate the destination column 833b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori if (values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION) == 834b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) { 835b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori /* this row is inserted by 8369b2576f9181fc177dbbc9033c435b1d4049fc2e0Vasu Nori * DownloadManager.addCompletedDownload(String, String, String, 8379b2576f9181fc177dbbc9033c435b1d4049fc2e0Vasu Nori * boolean, String, String, long) 838b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori */ 839b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori values.remove(Downloads.Impl.COLUMN_TOTAL_BYTES); 840b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori values.remove(Downloads.Impl._DATA); 841b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori values.remove(Downloads.Impl.COLUMN_STATUS); 842b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori } 843b06b739b078ce4b00600487cfec31659647bf31fSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_DESTINATION, 844b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE, 845b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori Downloads.Impl.DESTINATION_FILE_URI, 846b18ed519040c1ecd98f8cb139adcc315a3f4eedcVasu Nori Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD); 8479da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard 8489da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard if (getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_NO_NOTIFICATION) 8499da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard == PackageManager.PERMISSION_GRANTED) { 8509da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 85151cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_HIDDEN, 85251cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_VISIBLE, 85351cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED, 85451cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION); 8559da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } else { 8569da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard enforceAllowedValues(values, Downloads.Impl.COLUMN_VISIBILITY, 85751cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_VISIBLE, 85851cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED, 85951cc2143feeed748c62544c7f1a57415bd90c7afJeff Sharkey Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION); 8609da9df3d6e84a3c4b04dd22d277e0e6d8f7f1ccbSteve Howard } 861b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 862b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // remove the rest of the columns that are allowed (with any value) 863b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_URI); 864b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_TITLE); 865b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_DESCRIPTION); 866b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_MIME_TYPE); 867b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_FILE_NAME_HINT); // checked later in insert() 868b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE); // checked later in insert() 869b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES); 870b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(Downloads.Impl.COLUMN_ALLOW_ROAMING); 871a7ae77fdae69bcc6d6609d4639fed5d96e55eeaaJeff Sharkey values.remove(Downloads.Impl.COLUMN_ALLOW_METERED); 8723a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey values.remove(Downloads.Impl.COLUMN_FLAGS); 87371e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard values.remove(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI); 8743002e1870d4ad76c260b4729a8d86212c8db3e78Vasu Nori values.remove(Downloads.Impl.COLUMN_MEDIA_SCANNED); 875c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey values.remove(Downloads.Impl.COLUMN_ALLOW_WRITE); 876e61798da80558450f580ed948d0d469bd6423d8eSteve Howard Iterator<Map.Entry<String, Object>> iterator = values.valueSet().iterator(); 877e61798da80558450f580ed948d0d469bd6423d8eSteve Howard while (iterator.hasNext()) { 878e61798da80558450f580ed948d0d469bd6423d8eSteve Howard String key = iterator.next().getKey(); 879e61798da80558450f580ed948d0d469bd6423d8eSteve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 880e61798da80558450f580ed948d0d469bd6423d8eSteve Howard iterator.remove(); 881e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 882e61798da80558450f580ed948d0d469bd6423d8eSteve Howard } 883b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 884b06b739b078ce4b00600487cfec31659647bf31fSteve Howard // any extra columns are extraneous and disallowed 885b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (values.size() > 0) { 886b06b739b078ce4b00600487cfec31659647bf31fSteve Howard StringBuilder error = new StringBuilder("Invalid columns in request: "); 887b06b739b078ce4b00600487cfec31659647bf31fSteve Howard boolean first = true; 888b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 889b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (!first) { 890b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(", "); 891b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 892b06b739b078ce4b00600487cfec31659647bf31fSteve Howard error.append(entry.getKey()); 893b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 894b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException(error.toString()); 895b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 896b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 897b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 898b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 899b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * Remove column from values, and throw a SecurityException if the value isn't within the 900b06b739b078ce4b00600487cfec31659647bf31fSteve Howard * specified allowedValues. 901b06b739b078ce4b00600487cfec31659647bf31fSteve Howard */ 902b06b739b078ce4b00600487cfec31659647bf31fSteve Howard private void enforceAllowedValues(ContentValues values, String column, 903b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object... allowedValues) { 904b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Object value = values.get(column); 905b06b739b078ce4b00600487cfec31659647bf31fSteve Howard values.remove(column); 906b06b739b078ce4b00600487cfec31659647bf31fSteve Howard for (Object allowedValue : allowedValues) { 907b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value == null && allowedValue == null) { 908b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 909b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 910b06b739b078ce4b00600487cfec31659647bf31fSteve Howard if (value != null && value.equals(allowedValue)) { 911b06b739b078ce4b00600487cfec31659647bf31fSteve Howard return; 912b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 913b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 914b06b739b078ce4b00600487cfec31659647bf31fSteve Howard throw new SecurityException("Invalid value for " + column + ": " + value); 915b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 916b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 9172e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey private Cursor queryCleared(Uri uri, String[] projection, String selection, 9182e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey String[] selectionArgs, String sort) { 9192e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey final long token = Binder.clearCallingIdentity(); 9202e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey try { 9212e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey return query(uri, projection, selection, selectionArgs, sort); 9222e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey } finally { 9232e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey Binder.restoreCallingIdentity(token); 9242e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey } 9252e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey } 9262e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey 927b06b739b078ce4b00600487cfec31659647bf31fSteve Howard /** 92857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Starts a database query 92957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 93057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 9311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project public Cursor query(final Uri uri, String[] projection, 93257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String selection, final String[] selectionArgs, 93357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String sort) { 9341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 93557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 93657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 93757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 9383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == -1) { 9393d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (Constants.LOGV) { 9409b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "querying unknown URI: " + uri); 94157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9423d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new IllegalArgumentException("Unknown URI: " + uri); 9433d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9443d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 9453d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (match == REQUEST_HEADERS_URI) { 9463d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection != null || selection != null || sort != null) { 9473d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new UnsupportedOperationException("Request header queries do not support " 9483d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + "projections, selections or sorting"); 94957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 9503d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard return queryRequestHeaders(db, uri); 9513d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 9523d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 953e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection fullSelection = getWhereClause(uri, selection, selectionArgs, match); 95457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 9555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (shouldRestrictVisibility()) { 9561fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (projection == null) { 9579b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey projection = sAppReadableColumnsArray.clone(); 9581fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 95901d0182d86db003b2da5b831cb26820093888d9aVasu Nori // check the validity of the columns in projection 9601fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project for (int i = 0; i < projection.length; ++i) { 96101d0182d86db003b2da5b831cb26820093888d9aVasu Nori if (!sAppReadableColumnsSet.contains(projection[i]) && 96201d0182d86db003b2da5b831cb26820093888d9aVasu Nori !downloadManagerColumnsList.contains(projection[i])) { 9631fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new IllegalArgumentException( 9641fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project "column " + projection[i] + " is not allowed in queries"); 9651fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9661fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9671fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 9689b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey 9699b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey for (int i = 0; i < projection.length; i++) { 9709b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey final String newColumn = sColumnsMap.get(projection[i]); 9719b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey if (newColumn != null) { 9729b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey projection[i] = newColumn; 9739b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey } 9749b606340a0b5b88436505651dbe3cdaf60117604Jeff Sharkey } 97557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 97657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 97757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 9783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseQueryInfo(projection, selection, selectionArgs, sort, db); 97957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 98057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 981b759707b80987d0cb4ad2a3a78c11702a45a36c2Ben Lin SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); 982b759707b80987d0cb4ad2a3a78c11702a45a36c2Ben Lin builder.setTables(DB_TABLE); 983b759707b80987d0cb4ad2a3a78c11702a45a36c2Ben Lin builder.setStrict(true); 984b759707b80987d0cb4ad2a3a78c11702a45a36c2Ben Lin Cursor ret = builder.query(db, projection, fullSelection.getSelection(), 985e610c0502c00689411624c00c3f81497df93b202Steve Howard fullSelection.getParameters(), null, null, sort); 98657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 98757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (ret != null) { 98857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project ret.setNotificationUri(getContext().getContentResolver(), uri); 98957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 9909b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, 99157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project "created cursor " + ret + " on behalf of " + Binder.getCallingPid()); 99257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 99357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } else { 99457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGV) { 9959b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "query failed in downloads database"); 99657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 99757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 99857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 99957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return ret; 100057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 100157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 10023d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseQueryInfo(String[] projection, final String selection, 10033d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard final String[] selectionArgs, final String sort, SQLiteDatabase db) { 10043d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard java.lang.StringBuilder sb = new java.lang.StringBuilder(); 10053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("starting query, database is "); 10063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (db != null) { 10073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("not "); 10083d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10093d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("null; "); 10103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (projection == null) { 10113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is null; "); 10123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (projection.length == 0) { 10133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection is empty; "); 10143d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < projection.length; ++i) { 10163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("projection["); 10173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 10183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 10193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(projection[i]); 10203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 10213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selection is "); 10243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selection); 10253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 10263d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (selectionArgs == null) { 10273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is null; "); 10283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else if (selectionArgs.length == 0) { 10293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs is empty; "); 10303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 10313d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (int i = 0; i < selectionArgs.length; ++i) { 10323d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("selectionArgs["); 10333d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(i); 10343d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("] is "); 10353d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(selectionArgs[i]); 10363d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("; "); 10373d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10383d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10393d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("sort is "); 10403d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append(sort); 10413d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard sb.append("."); 10429b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, sb.toString()); 10433d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 10443d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 10455224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private String getDownloadIdFromUri(final Uri uri) { 10465224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return uri.getPathSegments().get(1); 10475224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10485224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 10495224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 10505224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Insert request headers for a download into the DB. 10515224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 10525224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void insertRequestHeaders(SQLiteDatabase db, long downloadId, ContentValues values) { 10535224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard ContentValues rowValues = new ContentValues(); 10545224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID, downloadId); 10555224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (Map.Entry<String, Object> entry : values.valueSet()) { 10565224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String key = entry.getKey(); 10575224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (key.startsWith(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX)) { 10585224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String headerLine = entry.getValue().toString(); 10595224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard if (!headerLine.contains(":")) { 10605224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard throw new IllegalArgumentException("Invalid HTTP header line: " + headerLine); 10615224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10625224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] parts = headerLine.split(":", 2); 10635224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_HEADER, parts[0].trim()); 10645224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard rowValues.put(Downloads.Impl.RequestHeaders.COLUMN_VALUE, parts[1].trim()); 10655224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.insert(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, null, rowValues); 10665224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10675224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10685224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10695224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 10705224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 10715224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Handle a query for the custom request headers registered for a download. 10725224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 10735224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private Cursor queryRequestHeaders(SQLiteDatabase db, Uri uri) { 10745224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String where = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" 10755224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard + getDownloadIdFromUri(uri); 10765224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl.RequestHeaders.COLUMN_HEADER, 10775224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard Downloads.Impl.RequestHeaders.COLUMN_VALUE}; 107853356ad554f53a093434161cb494b8e818c294fbSteve Howard return db.query(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, projection, where, 107953356ad554f53a093434161cb494b8e818c294fbSteve Howard null, null, null, null); 10805224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10815224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 10825224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 10835224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard * Delete request headers for downloads matching the given query. 10845224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 10855224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private void deleteRequestHeaders(SQLiteDatabase db, String where, String[] whereArgs) { 10865224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String[] projection = new String[] {Downloads.Impl._ID}; 1087b06b739b078ce4b00600487cfec31659647bf31fSteve Howard Cursor cursor = db.query(DB_TABLE, projection, where, whereArgs, null, null, null, null); 10885224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard try { 10895224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 10905224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard long id = cursor.getLong(0); 10915224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard String idWhere = Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + "=" + id; 10925224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard db.delete(Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE, idWhere, null); 10935224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10945224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } finally { 10955224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard cursor.close(); 10965224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10975224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 10985224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 10995224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard /** 11003d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @return true if we should restrict the columns readable by this caller 11015224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard */ 11025224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard private boolean shouldRestrictVisibility() { 11035224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard int callingUid = Binder.getCallingUid(); 11045224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard return Binder.getCallingPid() != Process.myPid() && 11055224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard callingUid != mSystemUid && 110612c7bd488afe3a611d665e364e361f04f4a8c8d8Jeff Brown callingUid != mDefContainerUid; 11075224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard } 11085224c6fbf20b4803a580ef449ab87ebfbbfedb78Steve Howard 110957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 111057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Updates a row in the database 111157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 111257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 111357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project public int update(final Uri uri, final ContentValues values, 111457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project final String where, final String[] whereArgs) { 111550522c738bf68d2784ce4f52dd34188a491065b8Jeff Sharkey if (shouldRestrictVisibility()) { 111650522c738bf68d2784ce4f52dd34188a491065b8Jeff Sharkey Helpers.validateSelection(where, sAppReadableColumnsSet); 111750522c738bf68d2784ce4f52dd34188a491065b8Jeff Sharkey } 11181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 111916ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey final Context context = getContext(); 112016ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey final ContentResolver resolver = context.getContentResolver(); 112116ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey 112216ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 112357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 112457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 11253a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey boolean updateSchedule = false; 112616ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey boolean isCompleting = false; 1127e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 11281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project ContentValues filteredValues; 11291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (Binder.getCallingPid() != Process.myPid()) { 11301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = new ContentValues(); 11317dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_APP_DATA, values, filteredValues); 11327dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_VISIBILITY, values, filteredValues); 11337dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru Integer i = values.getAsInteger(Downloads.Impl.COLUMN_CONTROL); 11341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 11357dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru filteredValues.put(Downloads.Impl.COLUMN_CONTROL, i); 11363a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey updateSchedule = true; 11371fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 1138e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori 11397dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyInteger(Downloads.Impl.COLUMN_CONTROL, values, filteredValues); 11407dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_TITLE, values, filteredValues); 1141e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori copyString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI, values, filteredValues); 11427dd92fa94df0a13b4592ee636b7aa2b605f6b473Jean-Baptiste Queru copyString(Downloads.Impl.COLUMN_DESCRIPTION, values, filteredValues); 1143e00c31208405bd2e4c88e069df7a2b15237f70bfVasu Nori copyInteger(Downloads.Impl.COLUMN_DELETED, values, filteredValues); 11441fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } else { 11451fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project filteredValues = values; 1146a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins String filename = values.getAsString(Downloads.Impl._DATA); 1147a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins if (filename != null) { 1148a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson Cursor c = null; 1149a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson try { 1150a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson c = query(uri, new String[] 1151a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson { Downloads.Impl.COLUMN_TITLE }, null, null, null); 1152a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson if (!c.moveToFirst() || c.getString(0).isEmpty()) { 1153a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson values.put(Downloads.Impl.COLUMN_TITLE, new File(filename).getName()); 1154a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } 1155a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } finally { 1156a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson IoUtils.closeQuietly(c); 1157a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 1158a2028ed4141075da8199ba04a499be77734a85aeLeon Scroggins } 115971e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard 116071e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard Integer status = values.getAsInteger(Downloads.Impl.COLUMN_STATUS); 116171e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard boolean isRestart = status != null && status == Downloads.Impl.STATUS_PENDING; 1162d319729622da1893e895f2e35f41d01ecdca3705Steve Howard boolean isUserBypassingSizeLimit = 1163d319729622da1893e895f2e35f41d01ecdca3705Steve Howard values.containsKey(Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT); 1164d319729622da1893e895f2e35f41d01ecdca3705Steve Howard if (isRestart || isUserBypassingSizeLimit) { 11653a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey updateSchedule = true; 116671e7fda9135a0915af1fd419d07ebf85ad09beb4Steve Howard } 116716ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey isCompleting = status != null && Downloads.Impl.isStatusCompleted(status); 116857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 11693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 117057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 117157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 11723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 11733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 11743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 11753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 11763a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey if (filteredValues.size() == 0) { 11771fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project count = 0; 11783a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey break; 11793a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } 11803a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey 11813a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey final SqlSelection selection = getWhereClause(uri, where, whereArgs, match); 11823a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey count = db.update(DB_TABLE, filteredValues, selection.getSelection(), 11833a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey selection.getParameters()); 118416ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey if (updateSchedule || isCompleting) { 11853a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey final long token = Binder.clearCallingIdentity(); 118616ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey try (Cursor cursor = db.query(DB_TABLE, null, selection.getSelection(), 118716ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey selection.getParameters(), null, null, null)) { 118816ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver, 118916ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey cursor); 119016ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey final DownloadInfo info = new DownloadInfo(context); 119116ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey while (cursor.moveToNext()) { 119216ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey reader.updateFromDatabase(info); 119316ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey if (updateSchedule) { 119416ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey Helpers.scheduleJob(context, info); 119516ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey } 119616ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey if (isCompleting) { 119716ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey info.sendIntentIfRequested(); 11983a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } 11993a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } 12003a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } finally { 12013a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey Binder.restoreCallingIdentity(token); 12023a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } 12031fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 120457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 12053d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 12063d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 12079b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.d(Constants.TAG, "updating unknown/invalid URI: " + uri); 120857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot update URI: " + uri); 120957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 12103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 12113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 121257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 121357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 121457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 12153d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard /** 12163d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * Notify of a change through both URIs (/my_downloads and /all_downloads) 12173d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uri either URI for the changed download(s) 12183d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard * @param uriMatch the match ID from {@link #sURIMatcher} 12193d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard */ 12203d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void notifyContentChanged(final Uri uri, int uriMatch) { 12213d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Long downloadId = null; 12223d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID) { 12233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard downloadId = Long.parseLong(getDownloadIdFromUri(uri)); 12243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 12253d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard for (Uri uriToNotify : BASE_URIS) { 12263d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (downloadId != null) { 12273d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard uriToNotify = ContentUris.withAppendedId(uriToNotify, downloadId); 12283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 12293d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard getContext().getContentResolver().notifyChange(uriToNotify, null); 12303d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 12313d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 12323d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 1233e610c0502c00689411624c00c3f81497df93b202Steve Howard private SqlSelection getWhereClause(final Uri uri, final String where, final String[] whereArgs, 1234e610c0502c00689411624c00c3f81497df93b202Steve Howard int uriMatch) { 1235e610c0502c00689411624c00c3f81497df93b202Steve Howard SqlSelection selection = new SqlSelection(); 1236e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause(where, whereArgs); 12373ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori if (uriMatch == MY_DOWNLOADS_ID || uriMatch == ALL_DOWNLOADS_ID || 12383ca67748bc92eac89f731796c5597ff1fbe9217bVasu Nori uriMatch == PUBLIC_DOWNLOAD_ID) { 1239e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause(Downloads.Impl._ID + " = ?", getDownloadIdFromUri(uri)); 1240b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 1241e1823c84698006aa26a8c5dcfa5c4034858dfbe3Kenny Root if ((uriMatch == MY_DOWNLOADS || uriMatch == MY_DOWNLOADS_ID) 1242dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey && getContext().checkCallingOrSelfPermission(Downloads.Impl.PERMISSION_ACCESS_ALL) 1243e1823c84698006aa26a8c5dcfa5c4034858dfbe3Kenny Root != PackageManager.PERMISSION_GRANTED) { 1244e610c0502c00689411624c00c3f81497df93b202Steve Howard selection.appendClause( 1245e610c0502c00689411624c00c3f81497df93b202Steve Howard Constants.UID + "= ? OR " + Downloads.Impl.COLUMN_OTHER_UID + "= ?", 1246bff4fe9b858d95e984298d4863a5199f1ee2c54eJeff Sharkey Binder.getCallingUid(), Binder.getCallingUid()); 1247b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 1248e610c0502c00689411624c00c3f81497df93b202Steve Howard return selection; 1249b06b739b078ce4b00600487cfec31659647bf31fSteve Howard } 1250b06b739b078ce4b00600487cfec31659647bf31fSteve Howard 125157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 125257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Deletes a row in the database 125357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 125457f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 1255e3960ea97d5ddee80e5237796d577892e42a28cbJeff Sharkey public int delete(final Uri uri, final String where, final String[] whereArgs) { 12561f2c2c560400ba60c5b9dfd6fd4f5e73b232803aJeff Sharkey if (shouldRestrictVisibility()) { 12571f2c2c560400ba60c5b9dfd6fd4f5e73b232803aJeff Sharkey Helpers.validateSelection(where, sAppReadableColumnsSet); 12581f2c2c560400ba60c5b9dfd6fd4f5e73b232803aJeff Sharkey } 12591fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1260efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final Context context = getContext(); 1261efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final ContentResolver resolver = context.getContentResolver(); 1262efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final JobScheduler scheduler = context.getSystemService(JobScheduler.class); 1263efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey 12643a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 126557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int count; 126657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project int match = sURIMatcher.match(uri); 126757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project switch (match) { 12683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS: 12693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case MY_DOWNLOADS_ID: 12703d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS: 12713d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard case ALL_DOWNLOADS_ID: 12723a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey final SqlSelection selection = getWhereClause(uri, where, whereArgs, match); 1273e610c0502c00689411624c00c3f81497df93b202Steve Howard deleteRequestHeaders(db, selection.getSelection(), selection.getParameters()); 1274afaf53bd2b1322167b6f31eda941e38335c4a952Jeff Sharkey 1275efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey try (Cursor cursor = db.query(DB_TABLE, null, selection.getSelection(), 1276efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey selection.getParameters(), null, null, null)) { 1277efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final DownloadInfo.Reader reader = new DownloadInfo.Reader(resolver, cursor); 1278efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final DownloadInfo info = new DownloadInfo(context); 1279afaf53bd2b1322167b6f31eda941e38335c4a952Jeff Sharkey while (cursor.moveToNext()) { 1280efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey reader.updateFromDatabase(info); 1281efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey scheduler.cancel((int) info.mId); 12823a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey 1283e2c5d91b95a39a1e5028581bd72bd0e0ea907cafJeff Sharkey revokeAllDownloadsPermission(info.mId); 1284efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey DownloadStorageProvider.onDownloadProviderDelete(getContext(), info.mId); 1285e3960ea97d5ddee80e5237796d577892e42a28cbJeff Sharkey 1286efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final String path = info.mFileName; 1287e3960ea97d5ddee80e5237796d577892e42a28cbJeff Sharkey if (!TextUtils.isEmpty(path)) { 12888c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey try { 12898c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey final File file = new File(path).getCanonicalFile(); 12908c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey if (Helpers.isFilenameValid(getContext(), file)) { 12918c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey Log.v(Constants.TAG, 12928c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey "Deleting " + file + " via provider delete"); 12938c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey file.delete(); 12948c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey } 12958c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey } catch (IOException ignored) { 1296e3960ea97d5ddee80e5237796d577892e42a28cbJeff Sharkey } 1297e3960ea97d5ddee80e5237796d577892e42a28cbJeff Sharkey } 12983a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey 1299efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey final String mediaUri = info.mMediaProviderUri; 13003a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey if (!TextUtils.isEmpty(mediaUri)) { 130101dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey final long token = Binder.clearCallingIdentity(); 130201dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey try { 130301dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey getContext().getContentResolver().delete(Uri.parse(mediaUri), null, 130401dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey null); 1305d635ac295850ba23d528c02b1e5c6eb44b64b22bJeff Sharkey } catch (Exception e) { 1306d635ac295850ba23d528c02b1e5c6eb44b64b22bJeff Sharkey Log.w(Constants.TAG, "Failed to delete media entry: " + e); 130701dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey } finally { 130801dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey Binder.restoreCallingIdentity(token); 130901dee865054aedb9aa7e90a8ef2c556e19af95e1Jeff Sharkey } 13103a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey } 1311efb1ac6b49692e62fde6830c3d20953c8632d2baJeff Sharkey 131216ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey // If the download wasn't completed yet, we're 131316ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey // effectively completing it now, and we need to send 131416ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey // any requested broadcasts 131516ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey if (!Downloads.Impl.isStatusCompleted(info.mStatus)) { 131616ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey info.sendIntentIfRequested(); 131716ee9158a395f3f67be12062d7f870f76e2677a5Jeff Sharkey } 1318afaf53bd2b1322167b6f31eda941e38335c4a952Jeff Sharkey } 1319afaf53bd2b1322167b6f31eda941e38335c4a952Jeff Sharkey } 1320afaf53bd2b1322167b6f31eda941e38335c4a952Jeff Sharkey 1321e610c0502c00689411624c00c3f81497df93b202Steve Howard count = db.delete(DB_TABLE, selection.getSelection(), selection.getParameters()); 132257f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project break; 13233d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 13243d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard default: 13259b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.d(Constants.TAG, "deleting unknown/invalid URI: " + uri); 132657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project throw new UnsupportedOperationException("Cannot delete URI: " + uri); 132757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 13283d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard notifyContentChanged(uri, match); 13293b7e099588a2697305fd52c342f404a03ec9a9abJeff Sharkey final long token = Binder.clearCallingIdentity(); 13303b7e099588a2697305fd52c342f404a03ec9a9abJeff Sharkey try { 13313b7e099588a2697305fd52c342f404a03ec9a9abJeff Sharkey Helpers.getDownloadNotifier(getContext()).update(); 13323b7e099588a2697305fd52c342f404a03ec9a9abJeff Sharkey } finally { 13333b7e099588a2697305fd52c342f404a03ec9a9abJeff Sharkey Binder.restoreCallingIdentity(token); 13343b7e099588a2697305fd52c342f404a03ec9a9abJeff Sharkey } 133557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project return count; 133657f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 133771aab521efba9b28779541440c797220ec98ac97Steve Howard 133857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project /** 133957f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project * Remotely opens a file 134057f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project */ 134157f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project @Override 1342c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey public ParcelFileDescriptor openFile(final Uri uri, String mode) throws FileNotFoundException { 134357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project if (Constants.LOGVV) { 13443d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard logVerboseOpenFileInfo(uri, mode); 134557f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 13461fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 13477c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey // Perform normal query to enforce caller identity access before 13487c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey // clearing it to reach internal-only columns 13497c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey final Cursor probeCursor = query(uri, new String[] { 13507c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey Downloads.Impl._DATA }, null, null, null); 13517c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey try { 13527c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey if ((probeCursor == null) || (probeCursor.getCount() == 0)) { 13537c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey throw new FileNotFoundException( 13547c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey "No file found for " + uri + " as UID " + Binder.getCallingUid()); 13557c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } 13567c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } finally { 13577c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey IoUtils.closeQuietly(probeCursor); 13587c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } 13597c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey 13602e16979a9133ef83f6e513eaa4b84de40350a2ddJeff Sharkey final Cursor cursor = queryCleared(uri, new String[] { 1361495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey Downloads.Impl._DATA, Downloads.Impl.COLUMN_STATUS, 1362495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.COLUMN_MEDIA_SCANNED }, null, 1363495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey null, null); 1364495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final String path; 1365495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final boolean shouldScan; 13663d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard try { 13673d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard int count = (cursor != null) ? cursor.getCount() : 0; 13683d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count != 1) { 13693d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard // If there is not exactly one result, throw an appropriate exception. 13703d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (count == 0) { 13713d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("No entry for " + uri); 13723d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 13733d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard throw new FileNotFoundException("Multiple items at " + uri); 13741fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 13753d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 1376495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey if (cursor.moveToFirst()) { 1377495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final int status = cursor.getInt(1); 1378495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final int destination = cursor.getInt(2); 1379495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final int mediaScanned = cursor.getInt(3); 1380495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey 1381495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey path = cursor.getString(0); 1382495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey shouldScan = Downloads.Impl.isStatusSuccess(status) && ( 1383495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey destination == Downloads.Impl.DESTINATION_EXTERNAL 1384495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey || destination == Downloads.Impl.DESTINATION_FILE_URI 1385495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey || destination == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) 1386495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey && mediaScanned != 2; 1387495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey } else { 1388495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey throw new FileNotFoundException("Failed moveToFirst"); 1389495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey } 13903d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } finally { 1391c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey IoUtils.closeQuietly(cursor); 13921fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 13931fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 13941fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (path == null) { 13951fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project throw new FileNotFoundException("No filename found."); 13961fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 13973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 13988c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey final File file; 13998c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey try { 14008c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey file = new File(path).getCanonicalFile(); 14018c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey } catch (IOException e) { 14028c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey throw new FileNotFoundException(e.getMessage()); 14038c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey } 14048c088f73a53813869e68a5c4671c09e8732da6d3Jeff Sharkey 1405dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey if (!Helpers.isFilenameValid(getContext(), file)) { 1406a4af46faac3ed68540d634e25f311cb7e071e6a5Jeff Sharkey throw new FileNotFoundException("Invalid file: " + file); 1407dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey } 1408dffbb9c4567e9d29d19964a83129e38dceab7055Jeff Sharkey 1409495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final int pfdMode = ParcelFileDescriptor.parseMode(mode); 1410495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY) { 1411495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey return ParcelFileDescriptor.open(file, pfdMode); 1412c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey } else { 1413c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey try { 1414c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey // When finished writing, update size and timestamp 14153a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey return ParcelFileDescriptor.open(file, pfdMode, Helpers.getAsyncHandler(), 14163a5f5eafb34eaa4963c801882148e8f61514a61bJeff Sharkey new OnCloseListener() { 1417495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey @Override 1418495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey public void onClose(IOException e) { 1419495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final ContentValues values = new ContentValues(); 1420495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, file.length()); 1421495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, 1422495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey System.currentTimeMillis()); 1423495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey update(uri, values, null, null); 1424495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey 1425495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey if (shouldScan) { 1426495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey final Intent intent = new Intent( 1427495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); 1428495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey intent.setData(Uri.fromFile(file)); 1429495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey getContext().sendBroadcast(intent); 1430495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey } 1431495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey } 1432495edec1d9f7659923c71b009db66c1bd4782034Jeff Sharkey }); 1433c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey } catch (IOException e) { 1434c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey throw new FileNotFoundException("Failed to open for writing: " + e); 1435c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey } 1436c067c8be21dc4a6dc5f49b2b1aed7f91aab47063Jeff Sharkey } 143757f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project } 143857f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project 14391d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey @Override 14401d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 14411d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 120); 14421d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey 14431d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.println("Downloads updated in last hour:"); 14441d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.increaseIndent(); 14451d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey 14461d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 14471d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey final long modifiedAfter = mSystemFacade.currentTimeMillis() - DateUtils.HOUR_IN_MILLIS; 14481d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey final Cursor cursor = db.query(DB_TABLE, null, 14491d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey Downloads.Impl.COLUMN_LAST_MODIFICATION + ">" + modifiedAfter, null, null, null, 14501d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey Downloads.Impl._ID + " ASC"); 14511d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey try { 14521d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey final String[] cols = cursor.getColumnNames(); 14531d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey final int idCol = cursor.getColumnIndex(BaseColumns._ID); 14541d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey while (cursor.moveToNext()) { 14551d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.println("Download #" + cursor.getInt(idCol) + ":"); 14561d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.increaseIndent(); 14571d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey for (int i = 0; i < cols.length; i++) { 14581d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey // Omit sensitive data when dumping 14591d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey if (Downloads.Impl.COLUMN_COOKIE_DATA.equals(cols[i])) { 14601d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey continue; 14611d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey } 14621d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.printPair(cols[i], cursor.getString(i)); 14631d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey } 14641d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.println(); 14651d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.decreaseIndent(); 14661d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey } 14671d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey } finally { 14681d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey cursor.close(); 14691d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey } 14701d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey 14711d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey pw.decreaseIndent(); 14721d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey } 14731d0a0aa2cc5bfed8107aa70f7e890fde9a7ea2b4Jeff Sharkey 14743d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard private void logVerboseOpenFileInfo(Uri uri, String mode) { 14759b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "openFile uri: " + uri + ", mode: " + mode 14763d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard + ", uid: " + Binder.getCallingUid()); 14773d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard Cursor cursor = query(Downloads.Impl.CONTENT_URI, 14783d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard new String[] { "_id" }, null, null, "_id"); 14793d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 14809b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "null cursor in openFile"); 14813d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 1482a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson try { 1483a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson if (!cursor.moveToFirst()) { 1484a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson Log.v(Constants.TAG, "empty cursor in openFile"); 1485a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } else { 1486a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson do { 1487a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson Log.v(Constants.TAG, "row " + cursor.getInt(0) + " available"); 1488a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } while(cursor.moveToNext()); 1489a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } 1490a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } finally { 1491a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson cursor.close(); 14923d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 14933d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 14943d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard cursor = query(uri, new String[] { "_data" }, null, null, null); 14953d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard if (cursor == null) { 14969b731a5521f569c91aeb419d43fa098a34cf78cbDoug Zongker Log.v(Constants.TAG, "null cursor in openFile"); 14973d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } else { 1498a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson try { 1499a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson if (!cursor.moveToFirst()) { 1500a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson Log.v(Constants.TAG, "empty cursor in openFile"); 1501a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } else { 1502a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson String filename = cursor.getString(0); 1503a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson Log.v(Constants.TAG, "filename in openFile: " + filename); 1504a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson if (new java.io.File(filename).isFile()) { 1505a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson Log.v(Constants.TAG, "file exists in openFile"); 1506a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } 15073d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 1508a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson } finally { 1509a2aad3aa41402afe88a2bf7b820f3459f795d079Mattias Nilsson cursor.close(); 15103d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 15113d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 15123d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard } 15133d55d829c03fe78ad8cdab119293efb6c6e49c64Steve Howard 15141fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyInteger(String key, ContentValues from, ContentValues to) { 15151fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Integer i = from.getAsInteger(key); 15161fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (i != null) { 15171fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, i); 15181fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 15191fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 15201fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 15211fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyBoolean(String key, ContentValues from, ContentValues to) { 15221fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project Boolean b = from.getAsBoolean(key); 15231fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (b != null) { 15241fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, b); 15251fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 15261fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 15271fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 15281fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project private static final void copyString(String key, ContentValues from, ContentValues to) { 15291fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project String s = from.getAsString(key); 15301fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project if (s != null) { 15311fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project to.put(key, s); 15321fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 15331fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project } 15341fbad9cfa532f13f6cf03f542febf2e4689edec5The Android Open Source Project 1535a89321ea04ced76d06f60f5909be203cb654a830Steve Howard private static final void copyStringWithDefault(String key, ContentValues from, 1536a89321ea04ced76d06f60f5909be203cb654a830Steve Howard ContentValues to, String defaultValue) { 1537a89321ea04ced76d06f60f5909be203cb654a830Steve Howard copyString(key, from, to); 1538a89321ea04ced76d06f60f5909be203cb654a830Steve Howard if (!to.containsKey(key)) { 1539a89321ea04ced76d06f60f5909be203cb654a830Steve Howard to.put(key, defaultValue); 1540a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 1541a89321ea04ced76d06f60f5909be203cb654a830Steve Howard } 15427c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey 15432ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla private void grantAllDownloadsPermission(String toPackage, long id) { 15447c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey final Uri uri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id); 15452ab9a2d15c63cd567805adb8fa4b9c524afc5cebSuprabh Shukla getContext().grantUriPermission(toPackage, uri, 15467c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 15477c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } 15487c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey 15497c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey private void revokeAllDownloadsPermission(long id) { 15507c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey final Uri uri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id); 15517c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey getContext().revokeUriPermission(uri, ~0); 15527c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1Jeff Sharkey } 155357f55b3cb4f7e4136cde8d1ea12c1e70ec90336The Android Open Source Project} 1554