Chromium Code Reviews| Index: chrome/browser/download/download_manager.cc |
| diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc |
| index 7200ba8062f3c760cb7121b85749ec43dd216075..0f6151bd24508d8faf46af821589e8b969bcf05c 100644 |
| --- a/chrome/browser/download/download_manager.cc |
| +++ b/chrome/browser/download/download_manager.cc |
| @@ -242,7 +242,7 @@ bool DownloadManager::Init(Profile* profile) { |
| // history system of a new download. Since this method can be called while the |
| // history service thread is still reading the persistent state, we do not |
| // insert the new DownloadItem into 'history_downloads_' or inform our |
| -// observers at this point. OnCreateDatabaseEntryComplete() handles that |
| +// observers at this point. OnCreateDownloadEntryComplete() handles that |
| // finalization of the the download creation as a callback from the |
| // history thread. |
| void DownloadManager::StartDownload(DownloadCreateInfo* info) { |
| @@ -431,6 +431,8 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info) { |
| void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info, |
| const FilePath& target_path) { |
| + VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); |
| + |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| scoped_ptr<DownloadCreateInfo> infop(info); |
| @@ -451,29 +453,25 @@ void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info, |
| info->is_extension_install, |
| info->original_name); |
| in_progress_[info->download_id] = download; |
| + UpdateAppIcon(); // Reflect entry into in_progress_. |
| - bool download_finished = ContainsKey(pending_finished_downloads_, |
| - info->download_id); |
| - |
| - VLOG(20) << __FUNCTION__ << "()" |
| - << " target_path = \"" << target_path.value() << "\"" |
| - << " download_finished = " << download_finished |
| - << " info = " << info->DebugString() |
| - << " download = " << download->DebugString(true); |
| - |
| - if (download_finished || info->is_dangerous) { |
| - // The download has already finished or the download is not safe. |
| - // We can now rename the file to its final name (or its tentative name |
| - // in dangerous download cases). |
| + // Rename to intermediate name. |
| + if (info->is_dangerous) { |
| + // The download is not safe. We can now rename the file to its |
| + // tentative name using OnFinalDownloadName (the actual final |
| + // name after user confirmation will be set in |
| + // ProceedWithFinishedDangerousDownload). |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| NewRunnableMethod( |
| file_manager_, &DownloadFileManager::OnFinalDownloadName, |
| - download->id(), target_path, !info->is_dangerous, |
| + download->id(), target_path, false, |
| make_scoped_refptr(this))); |
| } else { |
| - // The download hasn't finished and it is a safe download. We need to |
| - // rename it to its intermediate '.crdownload' path. |
| + // The download is a safe download. We need to |
| + // rename it to its intermediate '.crdownload' path. The final |
| + // name after user confirmation will be set from |
| + // DownloadItem::OnSafeDownloadFinished. |
| FilePath download_path = download_util::GetCrDownloadPath(target_path); |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| @@ -483,17 +481,8 @@ void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info, |
| download->Rename(download_path); |
| } |
| - if (download_finished) { |
| - // If the download already completed by the time we reached this point, then |
| - // notify observers that it did. |
| - OnAllDataSaved(info->download_id, |
| - pending_finished_downloads_[info->download_id]); |
| - } |
| - |
| download_history_->AddEntry(*info, download, |
| NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete)); |
| - |
| - UpdateAppIcon(); |
| } |
| void DownloadManager::UpdateDownload(int32 download_id, int64 size) { |
| @@ -503,73 +492,95 @@ void DownloadManager::UpdateDownload(int32 download_id, int64 size) { |
| DownloadItem* download = it->second; |
| if (download->state() == DownloadItem::IN_PROGRESS) { |
| download->Update(size); |
| + UpdateAppIcon(); // Reflect size updates. |
|
ahendrickson
2011/01/13 03:15:17
Why not set a flag if we update a download, then c
Randy Smith (Not in Mondays)
2011/01/16 20:43:56
I'm very confused. What loop? We call find, get
|
| download_history_->UpdateEntry(download); |
| } |
| } |
| - UpdateAppIcon(); |
| } |
| void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) { |
| VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id |
| << " size = " << size; |
| - DownloadMap::iterator it = in_progress_.find(download_id); |
| - if (it == in_progress_.end()) { |
| - // The download is done, but the user hasn't selected a final location for |
| - // it yet (the Save As dialog box is probably still showing), so just keep |
| - // track of the fact that this download id is complete, when the |
| - // DownloadItem is constructed later we'll notify its completion then. |
| - DCHECK(!ContainsKey(pending_finished_downloads_, download_id)); |
| - pending_finished_downloads_[download_id] = size; |
| - VLOG(20) << __FUNCTION__ << "()" << " Added download_id = " << download_id |
| - << " to pending_finished_downloads_"; |
| - return; |
| - } |
| - // Remove the id from the list of pending ids. |
| - PendingFinishedMap::iterator erase_it = |
| - pending_finished_downloads_.find(download_id); |
| - if (erase_it != pending_finished_downloads_.end()) { |
| - pending_finished_downloads_.erase(erase_it); |
| - VLOG(20) << __FUNCTION__ << "()" << " Removed download_id = " << download_id |
| - << " from pending_finished_downloads_"; |
| - } |
| + DCHECK_EQ(0U, pending_finished_downloads_.count(download_id)); |
|
ahendrickson
2011/01/13 03:15:17
Would |ContainsKey()| work here, and in succeeding
Randy Smith (Not in Mondays)
2011/01/16 20:43:56
So if you ask me for this change again I'll do it.
|
| + pending_finished_downloads_[download_id] = size; |
| - DownloadItem* download = it->second; |
| + MaybeCompleteDownload(download_id); |
| +} |
| - VLOG(20) << __FUNCTION__ << "()" |
| - << " download = " << download->DebugString(true); |
| +bool DownloadManager::IsDownloadReadyForCompletion(int32 download_id) { |
| + // If we don't have all the data, the download is not ready for |
| + // completion. |
| + if (pending_finished_downloads_.count(download_id) == 0) |
| + return false; |
| - download->OnAllDataSaved(size); |
| + // If the download isn't active (e.g. has been cancelled) it's not |
| + // ready for completion. |
| + if (active_downloads_.count(download_id) == 0) |
| + return false; |
| - // 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); |
| - download_history_->UpdateEntry(download); |
| - } |
| + // If the download hasn't been inserted into the history system |
| + // (which occurs strictly after file name determination, intermediate |
| + // file rename, and UI display) then it's not ready for completion. |
| + return (active_downloads_[download_id]->db_handle() != |
| + DownloadHistory::kUninitializedHandle); |
| +} |
| - UpdateAppIcon(); |
| +void DownloadManager::MaybeCompleteDownload(int32 download_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + VLOG(20) << __FUNCTION__ << "()" << " download_id = " << download_id; |
| - // If this a dangerous download not yet validated by the user, don't do |
| - // anything. When the user notifies us, it will trigger a call to |
| - // ProceedWithFinishedDangerousDownload. |
| - if (download->safety_state() == DownloadItem::DANGEROUS) { |
| + if (!IsDownloadReadyForCompletion(download_id)) |
| return; |
| - } |
| - if (download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) { |
| - // We first need to rename the downloaded file from its temporary name to |
| - // its final name before we can continue. |
| - BrowserThread::PostTask( |
| - BrowserThread::FILE, FROM_HERE, |
| - NewRunnableMethod( |
| - this, &DownloadManager::ProceedWithFinishedDangerousDownload, |
| - download->db_handle(), |
| - download->full_path(), download->target_name())); |
| - return; |
| - } |
| + // TODO(rdsmith): DCHECK that we only pass through this point |
| + // once per download. The natural way to do this is by a state |
| + // transition on the DownloadItem. |
| + |
| + // Confirm we're in the proper set of states to be here; |
| + // in in_progress_, in pending_finished_, have a history handle. |
| + DCHECK_EQ(1u, in_progress_.count(download_id)); |
| + DCHECK_EQ(1u, pending_finished_downloads_.count(download_id)); |
| + DownloadItem* download = in_progress_[download_id]; |
| + DCHECK(download->db_handle() != DownloadHistory::kUninitializedHandle); |
| + DCHECK_EQ(1u, history_downloads_.count(download->db_handle())); |
| + |
| + VLOG(20) << __FUNCTION__ << "()" << " executing: download = " |
| + << download->DebugString(false); |
| - download->OnSafeDownloadFinished(file_manager_); |
| + // Remove the id from in_progress and pending_finished. |
| + int size = pending_finished_downloads_[download_id]; |
| + pending_finished_downloads_.erase(download_id); |
| + in_progress_.erase(download_id); |
| + UpdateAppIcon(); // Reflect removal from in_progress_. |
| + |
| + // Final update of download item and history. |
| + download->OnAllDataSaved(size); |
|
ahendrickson
2011/01/13 03:15:17
It seems odd not to call |download->OnAllDataSaved
Paweł Hajdan Jr.
2011/01/13 08:43:10
Yes, definitely. I thought that OnAllDataSaved sho
Randy Smith (Not in Mondays)
2011/01/16 20:43:56
Well, DownloadManager::OnAllDataSaved triggers Dow
Paweł Hajdan Jr.
2011/01/17 18:13:23
I'm sorry, I actually think that OnReadyToFinish i
Randy Smith (Not in Mondays)
2011/01/17 19:56:17
Sorry, now you've gotten me confused. download->O
|
| + download_history_->UpdateEntry(download); |
| + |
| + switch (download->safety_state()) { |
| + case DownloadItem::DANGEROUS: |
| + // If this a dangerous download not yet validated by the user, don't do |
| + // anything. When the user notifies us, it will trigger a call to |
| + // ProceedWithFinishedDangerousDownload. |
| + return; |
| + case DownloadItem::DANGEROUS_BUT_VALIDATED: |
| + // The dangerous download has been validated by the user. We first |
| + // need to rename the downloaded file from its temporary name to |
| + // its final name. We will continue the download processing in the |
| + // callback. |
| + BrowserThread::PostTask( |
| + BrowserThread::FILE, FROM_HERE, |
| + NewRunnableMethod( |
| + this, &DownloadManager::ProceedWithFinishedDangerousDownload, |
| + download->db_handle(), |
| + download->full_path(), download->target_name())); |
| + return; |
| + case DownloadItem::SAFE: |
| + // The download is safe; just finish it. |
| + download->OnSafeDownloadFinished(file_manager_); |
| + return; |
| + } |
| } |
| void DownloadManager::RemoveFromActiveList(int32 download_id) { |
| @@ -660,13 +671,13 @@ void DownloadManager::DownloadCancelled(int32 download_id) { |
| 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); |
| } |
| DownloadCancelledInternal(download_id, |
| download->render_process_id(), |
| download->request_id()); |
| - UpdateAppIcon(); |
| } |
| void DownloadManager::DownloadCancelledInternal(int download_id, |
| @@ -986,23 +997,21 @@ void DownloadManager::OnCreateDownloadEntryComplete( |
| // Inform interested objects about the new download. |
| NotifyModelChanged(); |
| - // If this download has been completed before we've received the db handle, |
| + // If this download has been cancelled before we've received the DB handle, |
| // 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. |
| + // |
| + // Otherwise, try to complete the download |
| if (download->state() != DownloadItem::IN_PROGRESS) { |
| + DCHECK_EQ(DownloadItem::CANCELLED, download->state()); |
| in_progress_.erase(it); |
| - // TODO(ahendrickson) -- We don't actually know whether or not we can |
| - // remove the download item from the |active_downloads_| map, as there |
| - // is no state in |DownloadItem::DownloadState| to indicate that the |
| - // downloads system is done with an item. Fix this when we have a |
| - // proper final state to check for. |
| active_downloads_.erase(info.download_id); |
| download_history_->UpdateEntry(download); |
| download->UpdateObservers(); |
| + } else { |
| + MaybeCompleteDownload(info.download_id); |
| } |
| - |
| - UpdateAppIcon(); |
| } |
| void DownloadManager::ShowDownloadInBrowser(const DownloadCreateInfo& info, |
| @@ -1050,9 +1059,9 @@ DownloadItem* DownloadManager::GetDownloadItem(int id) { |
| void DownloadManager::AssertContainersConsistent() const { |
| #if !defined(NDEBUG) |
| // Turn everything into sets. |
| - DownloadSet in_progress_set, history_set; |
| + DownloadSet active_set, history_set; |
| const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_}; |
| - DownloadSet* local_sets[] = {&in_progress_set, &history_set}; |
| + DownloadSet* local_sets[] = {&active_set, &history_set}; |
| DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets)); |
| for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { |
| for (DownloadMap::const_iterator it = input_maps[i]->begin(); |
| @@ -1062,7 +1071,7 @@ void DownloadManager::AssertContainersConsistent() const { |
| } |
| // Check if each set is fully present in downloads, and create a union. |
| - const DownloadSet* all_sets[] = {&in_progress_set, &history_set, |
| + const DownloadSet* all_sets[] = {&active_set, &history_set, |
| &save_page_as_downloads_}; |
| DownloadSet downloads_union; |
| for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) { |