Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Unified Diff: chrome/browser/download/download_manager.cc

Issue 7294013: Modified cancel and interrupt processing to avoid race with history. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merged to TOT. Again :-}. Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/download/download_manager.h ('k') | chrome/browser/download/download_manager_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/download/download_manager.cc
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index 3e0cf36d329f2a897fe524d8b1a254d356f60238..3970475986f7f5904c43b3422e4e24189d9aad1d 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -105,8 +105,7 @@ void DownloadManager::Shutdown() {
// from all queues.
download->Delete(DownloadItem::DELETE_DUE_TO_BROWSER_SHUTDOWN);
} else if (download->IsPartialDownload()) {
- download->Cancel(false);
- download_history_->UpdateEntry(download);
+ download->Cancel();
}
}
@@ -648,6 +647,15 @@ void DownloadManager::OnResponseCompleted(int32 download_id,
}
}
+void DownloadManager::CancelDownload(int32 download_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DownloadMap::iterator it = active_downloads_.find(download_id);
+ if (it == active_downloads_.end())
+ return;
+
+ it->second->Cancel();
+}
+
void DownloadManager::OnAllDataSaved(int32 download_id,
int64 size,
const std::string& hash) {
@@ -728,8 +736,8 @@ void DownloadManager::AssertQueueStateConsistent(DownloadItem* download) {
CHECK(ContainsKey(active_downloads_, download->id()) ==
(download->state() == DownloadItem::IN_PROGRESS));
- CHECK(ContainsKey(in_progress_, download->id()) ==
- (download->state() == DownloadItem::IN_PROGRESS));
+ // Would check in_progress_, but removal from that queue happens
+ // before transition from IN_PROGRESS for legacy reasons, so skipping.
}
bool DownloadManager::IsDownloadReadyForCompletion(DownloadItem* download) {
@@ -826,32 +834,24 @@ void DownloadManager::OnDownloadRenamedToFinalName(int download_id,
download_history_->UpdateDownloadPath(item, full_path);
}
-void DownloadManager::DownloadCancelled(int32 download_id) {
+void DownloadManager::DownloadStopped(int32 download_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DownloadMap::iterator it = in_progress_.find(download_id);
- if (it == in_progress_.end())
+ DownloadMap::iterator it = active_downloads_.find(download_id);
+ if (it == active_downloads_.end())
return;
DownloadItem* download = it->second;
VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id
<< " download = " << download->DebugString(true);
- // Clean up will happen when the history system create callback runs if we
- // don't have a valid db_handle yet.
- if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
- in_progress_.erase(it);
- active_downloads_.erase(download_id);
- UpdateAppIcon(); // Reflect removal from in_progress_.
- download_history_->UpdateEntry(download);
- }
+ in_progress_.erase(download_id);
+ active_downloads_.erase(download_id);
+ UpdateAppIcon(); // Reflect removal from in_progress_.
- DownloadCancelledInternal(download_id, download->request_handle());
-}
+ // The history service should always outlive the DownloadManager.
+ download_history_->UpdateEntry(download);
-void DownloadManager::DownloadCancelledInternal(
- int download_id, const DownloadRequestHandle& request_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- request_handle.CancelRequest();
+ download->request_handle().CancelRequest();
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
@@ -875,24 +875,7 @@ void DownloadManager::OnDownloadError(int32 download_id,
<< " at offset " << download->received_bytes()
<< " for download = " << download->DebugString(true);
- download->Interrupted(size, os_error);
-
- // TODO(ahendrickson) - Remove this when we add resuming of interrupted
- // downloads, as we will keep the download item around in that case.
- //
- // Clean up will happen when the history system create callback runs if we
- // don't have a valid db_handle yet.
- if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
- in_progress_.erase(download_id);
- active_downloads_.erase(download_id);
- UpdateAppIcon(); // Reflect removal from in_progress_.
- download_history_->UpdateEntry(download);
- }
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- file_manager_, &DownloadFileManager::CancelDownload, download_id));
+ download->Interrupt(size, os_error);
}
void DownloadManager::UpdateAppIcon() {
@@ -900,17 +883,15 @@ void DownloadManager::UpdateAppIcon() {
status_updater_->Update();
}
-void DownloadManager::RemoveDownload(int64 download_handle) {
- DownloadMap::iterator it = history_downloads_.find(download_handle);
- if (it == history_downloads_.end())
- return;
-
- // Make history update.
- DownloadItem* download = it->second;
- download_history_->RemoveEntry(download);
+void DownloadManager::RemoveDownload(DownloadItem* download) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Silently ignores request if db handle indicates that the download
+ // isn't in the history.
+ download_history_->RemoveEntry(download->db_handle());
// Remove from our tables and delete.
- history_downloads_.erase(it);
+ if (download->db_handle() != DownloadHistory::kUninitializedHandle)
+ history_downloads_.erase(download->db_handle());
int downloads_count = downloads_.erase(download);
DCHECK_EQ(1, downloads_count);
@@ -1061,6 +1042,11 @@ int64 DownloadManager::GetInProgressDownloadCount() {
return in_progress_.size();
}
+void DownloadManager::SetSelectFileDialog(
+ scoped_refptr<SelectFileDialog> file_dialog) {
+ select_file_dialog_ = file_dialog;
+}
+
int64 DownloadManager::GetReceivedDownloadBytes() {
DCHECK(IsDownloadProgressKnown());
int64 received_bytes = 0;
@@ -1119,7 +1105,7 @@ void DownloadManager::FileSelectionCanceled(void* params) {
VLOG(20) << __FUNCTION__ << "()"
<< " download = " << download->DebugString(true);
- DownloadCancelledInternal(download_id, download->request_handle());
+ download->Cancel();
}
// TODO(phajdan.jr): This is apparently not being exercised in tests.
@@ -1180,6 +1166,9 @@ void DownloadManager::AddDownloadItemToHistory(DownloadItem* download,
int64 db_handle) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
+ << " download = " << download->DebugString(false);
+
// It's not immediately obvious, but HistoryBackend::CreateDownload() can
// call this function with an invalid |db_handle|. For instance, this can
// happen when the history database is offline. We cannot have multiple
@@ -1188,9 +1177,10 @@ void DownloadManager::AddDownloadItemToHistory(DownloadItem* download,
if (db_handle == DownloadHistory::kUninitializedHandle)
db_handle = download_history_->GetNextFakeDbHandle();
+ // We shouldn't be here if the download is no longer in progress.
// TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508
// is fixed.
- CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle);
+ CHECK(download->IsInProgress());
DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle);
download->set_db_handle(db_handle);
@@ -1205,13 +1195,25 @@ void DownloadManager::AddDownloadItemToHistory(DownloadItem* download,
void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id,
int64 db_handle) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
+ << " download_id = " << download_id;
DownloadItem* download = GetActiveDownloadItem(download_id);
- if (!download)
+ if (!download) {
+ // The download was cancelled while the history system was entering it.
+ // We resolve this race by turning around and deleting it in the
+ // history system (implicitly treating it as a failure in download
+ // initiation, which is appropriate as the only places the cancel could
+ // have come from were in resolving issues (like the file name) which
+ // we need to have resolved for history system insertion).
+
+ // Make sure we haven't already been shutdown (the callback raced
+ // with shutdown), as that would mean that the history service has
+ // also been shutdown. In that case, the history will be cleaned up
+ // on next browser start.
+ if (download_history_.get())
+ download_history_->RemoveEntry(db_handle);
return;
-
- VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle
- << " download_id = " << download_id
- << " download = " << download->DebugString(true);
+ }
AddDownloadItemToHistory(download, db_handle);
@@ -1222,23 +1224,7 @@ void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id,
// Inform interested objects about the new download.
NotifyModelChanged();
- // If the download is still in progress, try to complete it.
- //
- // Otherwise, download has been cancelled or interrupted before we've
- // received the DB handle. We post one final message to the history
- // service so that it can be properly in sync with the DownloadItem's
- // completion status, and also inform any observers so that they get
- // more than just the start notification.
- if (download->IsInProgress()) {
- MaybeCompleteDownload(download);
- } else {
- DCHECK(download->IsCancelled())
- << " download = " << download->DebugString(true);
- in_progress_.erase(download_id);
- active_downloads_.erase(download_id);
- download_history_->UpdateEntry(download);
- download->UpdateObservers();
- }
+ MaybeCompleteDownload(download);
}
void DownloadManager::ShowDownloadInBrowser(DownloadItem* download) {
@@ -1283,6 +1269,16 @@ DownloadItem* DownloadManager::GetDownloadItem(int download_id) {
return NULL;
}
+void DownloadManager::GetInProgressDownloads(
+ std::vector<DownloadItem*>* result) {
+ DCHECK(result);
+
+ for (DownloadMap::iterator it = active_downloads_.begin();
+ it != active_downloads_.end(); ++it) {
+ result->push_back(it->second);
+ }
+}
+
DownloadItem* DownloadManager::GetActiveDownloadItem(int download_id) {
DCHECK(ContainsKey(active_downloads_, download_id));
DownloadItem* download = active_downloads_[download_id];
« no previous file with comments | « chrome/browser/download/download_manager.h ('k') | chrome/browser/download/download_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698