Make downloads work when history database fails to initialize.
Previously all download calls will be stuck when history database fails
to initialize.
This CL assigns 1 as the first id when history database failed to load,
all downloads in this browser session will not be persisted to history
database.
Bug: 736511
Change-Id: If4db04ca518633a7dd999f45629e60e97fc78b1a
Reviewed-on: https://chromium-review.googlesource.com/587327
Reviewed-by: Robert Kaplow <rkaplow@chromium.org>
Reviewed-by: David Trainor <dtrainor@chromium.org>
Commit-Queue: Xing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#490540}
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index e6343383..57e7f29 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -88,6 +88,11 @@
namespace {
+// The first id assigned to a download when download database failed to
+// initialize.
+const uint32_t kFirstDownloadIdNoPersist =
+ content::DownloadItem::kInvalidId + 1;
+
#if defined(FULL_SAFE_BROWSING)
// String pointer used for identifying safebrowing data associated with
@@ -251,8 +256,18 @@
void ChromeDownloadManagerDelegate::SetNextId(uint32_t next_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!profile_->IsOffTheRecord());
- DCHECK_NE(content::DownloadItem::kInvalidId, next_id);
- next_download_id_ = next_id;
+
+ // |content::DownloadItem::kInvalidId| will be returned only when download
+ // database failed to initialize.
+ bool download_db_available = (next_id != content::DownloadItem::kInvalidId);
+ RecordDatabaseAvailability(download_db_available);
+ if (download_db_available) {
+ next_download_id_ = next_id;
+ } else {
+ // Still download files without download database, all download history in
+ // this browser session will not be persisted.
+ next_download_id_ = kFirstDownloadIdNoPersist;
+ }
IdCallbackVector callbacks;
id_callbacks_.swap(callbacks);
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index b19c7fa..731bff9 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -152,8 +152,11 @@
uint32_t download_id,
const base::Closure& user_complete_callback);
+ // Sets the next download id based on download database records, and runs all
+ // cached id callbacks.
void SetNextId(uint32_t id);
+ // Runs the |callback| with next id. Results in the download being started.
void ReturnNextId(const content::DownloadIdCallback& callback);
void OnDownloadTargetDetermined(
@@ -169,7 +172,14 @@
bool ShouldBlockFile(content::DownloadDangerType danger_type) const;
Profile* profile_;
+
+ // Incremented by one for each download, the first available download id is
+ // assigned from history database or 1 when history database fails to
+ // intialize.
uint32_t next_download_id_;
+
+ // The |GetNextId| callbacks that may be cached before loading the download
+ // database.
IdCallbackVector id_callbacks_;
std::unique_ptr<DownloadPrefs> download_prefs_;
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index 9661b63..bb93527 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -243,12 +243,16 @@
DownloadPrefs* download_prefs();
PrefService* pref_service();
+ const std::vector<uint32_t>& download_ids() const { return download_ids_; }
+ void GetNextId(uint32_t next_id) { download_ids_.emplace_back(next_id); }
+
private:
sync_preferences::TestingPrefServiceSyncable* pref_service_;
base::ScopedTempDir test_download_dir_;
std::unique_ptr<content::MockDownloadManager> download_manager_;
std::unique_ptr<TestChromeDownloadManagerDelegate> delegate_;
MockWebContentsDelegate web_contents_delegate_;
+ std::vector<uint32_t> download_ids_;
};
ChromeDownloadManagerDelegateTest::ChromeDownloadManagerDelegateTest()
@@ -615,6 +619,30 @@
VerifyAndClearExpectations();
}
+TEST_F(ChromeDownloadManagerDelegateTest, WithoutHistoryDbNextId) {
+ content::DownloadIdCallback id_callback = base::Bind(
+ &ChromeDownloadManagerDelegateTest::GetNextId, base::Unretained(this));
+ delegate()->GetNextId(id_callback);
+ delegate()->GetNextId(id_callback);
+ // When download database fails to initialize, id will be set to
+ // |content::DownloadItem::kInvalidId|.
+ delegate()->GetDownloadIdReceiverCallback().Run(
+ content::DownloadItem::kInvalidId);
+ std::vector<uint32_t> expected_ids = std::vector<uint32_t>{1u, 2u};
+ EXPECT_EQ(expected_ids, download_ids());
+}
+
+TEST_F(ChromeDownloadManagerDelegateTest, WithHistoryDbNextId) {
+ content::DownloadIdCallback id_callback = base::Bind(
+ &ChromeDownloadManagerDelegateTest::GetNextId, base::Unretained(this));
+ delegate()->GetNextId(id_callback);
+ delegate()->GetNextId(id_callback);
+ // Simulates a valid download database with no records.
+ delegate()->GetDownloadIdReceiverCallback().Run(1u);
+ std::vector<uint32_t> expected_ids = std::vector<uint32_t>{1u, 2u};
+ EXPECT_EQ(expected_ids, download_ids());
+}
+
#if defined(FULL_SAFE_BROWSING)
namespace {
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index 6477de7d..bed151aa 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -50,3 +50,7 @@
open_method,
DOWNLOAD_OPEN_METHOD_LAST_ENTRY);
}
+
+void RecordDatabaseAvailability(bool is_available) {
+ UMA_HISTOGRAM_BOOLEAN("Download.Database.IsAvailable", is_available);
+}
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index cec8776..495b783 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -90,4 +90,8 @@
// Record how a download was opened.
void RecordDownloadOpenMethod(ChromeDownloadOpenMethod open_method);
+// Record if the database is available to provide the next download id before
+// starting all downloads.
+void RecordDatabaseAvailability(bool is_available);
+
#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STATS_H_
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 713cef47..145bb90 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -14917,6 +14917,16 @@
<summary>Time taken to create a single download in the history DB.</summary>
</histogram>
+<histogram name="Download.Database.IsAvailable" enum="BooleanAvailable">
+ <owner>xingliu@chromium.org</owner>
+ <summary>
+ Records whether the download database is available when database startup
+ completes, before starting any pending downloads. If the database is
+ available, it will provide the next download id. Or no download history will
+ be persisted.
+ </summary>
+</histogram>
+
<histogram name="Download.Database.QueryDownloadDuration" units="ms">
<owner>asanka@chromium.org</owner>
<summary>Time taken to query all downloads from history DB.</summary>