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

Unified Diff: content/browser/download/download_item_impl.cc

Issue 10912173: Replace the DownloadFileManager with direct ownership of DownloadFileImpl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync to LKGR (r156083) Created 8 years, 3 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
Index: content/browser/download/download_item_impl.cc
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 053406902ba7e43d870827062f8ad9c0965bf599..7cc8db76c3fcbfbefa8087a4413f66c76e2293cd 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -4,7 +4,7 @@
// File method ordering: Methods in this file are in the same order
// as in download_item_impl.h, with the following exception: The public
-// interfaces DelayedDownloadOpened, OnDownloadTargetDetermined, and
+// interfaces Start, DelayedDownloadOpened, OnDownloadTargetDetermined, and
// OnDownloadCompleting are placed in chronological order with the other
// (private) routines that together define a DownloadItem's state transitions
// as the download progresses. See "Download progression cascade" later in
@@ -39,7 +39,6 @@
#include "base/utf_string_conversions.h"
#include "content/browser/download/download_create_info.h"
#include "content/browser/download/download_file.h"
-#include "content/browser/download/download_file_manager.h"
#include "content/browser/download/download_interrupt_reasons_impl.h"
#include "content/browser/download/download_item_impl_delegate.h"
#include "content/browser/download/download_request_handle.h"
@@ -122,6 +121,20 @@ class NullDownloadRequestHandle : public DownloadRequestHandleInterface {
}
};
+// Wrapper around DownloadFile::Detach and DownloadFile::Cancel that
+// takes ownership of the DownloadFile and hence implicitly destroys it
+// at the end of the function.
+static void DownloadFileDetach(
+ scoped_ptr<DownloadFile> download_file, base::Closure callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ download_file->Detach(callback);
+}
+
+static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ download_file->Cancel();
+}
+
} // namespace
namespace content {
@@ -147,7 +160,8 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
DownloadId download_id,
const DownloadPersistentStoreInfo& info,
const net::BoundNetLog& bound_net_log)
- : download_id_(download_id),
+ : is_save_package_download_(false),
+ download_id_(download_id),
current_path_(info.path),
target_path_(info.path),
target_disposition_(TARGET_DISPOSITION_OVERWRITE),
@@ -194,7 +208,8 @@ DownloadItemImpl::DownloadItemImpl(
const DownloadCreateInfo& info,
scoped_ptr<DownloadRequestHandleInterface> request_handle,
const net::BoundNetLog& bound_net_log)
- : request_handle_(request_handle.Pass()),
+ : is_save_package_download_(false),
+ request_handle_(request_handle.Pass()),
download_id_(info.download_id),
target_disposition_(
(info.prompt_user_for_save_location) ?
@@ -254,7 +269,8 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
DownloadId download_id,
const std::string& mime_type,
const net::BoundNetLog& bound_net_log)
- : request_handle_(new NullDownloadRequestHandle()),
+ : is_save_package_download_(true),
+ request_handle_(new NullDownloadRequestHandle()),
download_id_(download_id),
current_path_(path),
target_path_(path),
@@ -295,6 +311,11 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
DownloadItemImpl::~DownloadItemImpl() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Should always have been nuked before now, at worst in
+ // DownloadManager shutdown.
+ DCHECK(!download_file_.get());
+
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
delegate_->AssertStateConsistent(this);
delegate_->Detach();
@@ -367,6 +388,21 @@ void DownloadItemImpl::Cancel(bool user_cancel) {
download_stats::RecordDownloadCount(download_stats::CANCELLED_COUNT);
TransitionTo(CANCELLED);
+
+ // Cancel and remove the download file.
+ // TODO(rdsmith/benjhayden): Remove condition as part of
+ // SavePackage integration.
+ if (!is_save_package_download_) {
+ CHECK(download_file_.get());
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ // Will be deleted at end of task execution.
+ base::Bind(&DownloadFileCancel, base::Passed(download_file_.Pass())));
+ }
+
+ // Cancel the originating URL request.
+ request_handle_->CancelRequest();
+
if (user_cancel)
delegate_->DownloadStopped(this);
}
@@ -817,7 +853,8 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
" etag = '%s'"
" url_chain = \n\t\"%s\"\n\t"
" full_path = \"%" PRFilePath "\""
- " target_path = \"%" PRFilePath "\"",
+ " target_path = \"%" PRFilePath "\""
+ " has download file = %s",
GetDbHandle(),
GetTotalBytes(),
GetReceivedBytes(),
@@ -828,7 +865,8 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
GetETag().c_str(),
url_list.c_str(),
GetFullPath().value().c_str(),
- GetTargetFilePath().value().c_str());
+ GetTargetFilePath().value().c_str(),
+ download_file_.get() ? "true" : "false");
} else {
description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
}
@@ -851,16 +889,6 @@ void DownloadItemImpl::OnDownloadedFileRemoved() {
UpdateObservers();
}
-void DownloadItemImpl::OffThreadCancel() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- request_handle_->CancelRequest();
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::CancelDownload,
- delegate_->GetDownloadFileManager(), download_id_));
-}
-
// An error occurred somewhere.
void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) {
// Somewhat counter-intuitively, it is possible for us to receive an
@@ -878,11 +906,36 @@ void DownloadItemImpl::Interrupt(content::DownloadInterruptReason reason) {
last_reason_ = reason;
TransitionTo(INTERRUPTED);
+
+ // Cancel and remove the download file.
+ // TODO(rdsmith/benjhayden): Remove condition as part of
+ // SavePackage integration.
+ if (!is_save_package_download_) {
+ CHECK(download_file_.get());
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ // Will be deleted at end of task execution.
+ base::Bind(&DownloadFileCancel, base::Passed(download_file_.Pass())));
+ }
+
+ // Cancel the originating URL request.
+ request_handle_->CancelRequest();
+
download_stats::RecordDownloadInterrupted(
reason, received_bytes_, total_bytes_);
delegate_->DownloadStopped(this);
}
+base::WeakPtr<content::DownloadDestinationObserver>
+DownloadItemImpl::DestinationObserverAsWeakPtr() {
+ // Return does private downcast.
benjhayden 2012/09/12 21:01:01 Actually, this is up-casting. And also obvious.
Randy Smith (Not in Mondays) 2012/09/13 20:15:12 The fact that it's private wasn't completely obvio
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+bool DownloadItemImpl::IsSavePackageDownload() const {
+ return is_save_package_download_;
+}
+
void DownloadItemImpl::SetTotalBytes(int64 total_bytes) {
total_bytes_ = total_bytes;
}
@@ -925,13 +978,17 @@ void DownloadItemImpl::UpdateProgress(int64 bytes_so_far,
UpdateObservers();
}
-void DownloadItemImpl::OnAllDataSaved(
- int64 size, const std::string& final_hash) {
+void DownloadItemImpl::OnAllDataSaved(const std::string& final_hash) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_EQ(IN_PROGRESS, state_);
DCHECK(!all_data_saved_);
all_data_saved_ = true;
- ProgressComplete(size, final_hash);
+
+ // Store final hash and null out intermediate serialized hash state.
+ hash_ = final_hash;
+ hash_state_ = "";
+
UpdateObservers();
}
@@ -945,6 +1002,7 @@ void DownloadItemImpl::MarkAsComplete() {
void DownloadItemImpl::SetIsPersisted() {
is_persisted_ = true;
+ UpdateObservers();
}
void DownloadItemImpl::SetDbHandle(int64 handle) {
@@ -955,6 +1013,55 @@ void DownloadItemImpl::SetDbHandle(int64 handle) {
net::NetLog::Int64Callback("db_handle", db_handle_));
}
+void DownloadItemImpl::DestinationUpdate(int64 bytes_so_far,
+ int64 bytes_per_sec,
+ const std::string& hash_state) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!IsInProgress()) {
+ // Ignore if we're no longer in-progress. This can happen if we race a
+ // Cancel on the UI thread with an update on the FILE thread.
+ //
+ // TODO(rdsmith): Arguably we should let this go through, as this means
+ // the download really did get further than we know before it was
+ // cancelled. But the gain isn't very large, and the code is more
+ // fragile if it has to support in progress updates in a non-in-progress
+ // state. This issue should be readdressed when we revamp performance
+ // reporting.
+ return;
+ }
+ bytes_per_sec_ = bytes_per_sec;
+ hash_state_ = hash_state;
+ received_bytes_ = bytes_so_far;
+
+ // If we've received more data than we were expecting (bad server info?),
+ // revert to 'unknown size mode'.
+ if (received_bytes_ > total_bytes_)
+ total_bytes_ = 0;
+
+ if (bound_net_log_.IsLoggingAllEvents()) {
+ bound_net_log_.AddEvent(
+ net::NetLog::TYPE_DOWNLOAD_ITEM_UPDATED,
+ net::NetLog::Int64Callback("bytes_so_far", received_bytes_));
+ }
+
+ UpdateObservers();
+}
+
+void DownloadItemImpl::DestinationError(
+ content::DownloadInterruptReason reason) {
+ // The DestinationError and Interrupt routines are being kept separate
+ // to allow for a future merging of the Cancel and Interrupt routines..
+ Interrupt(reason);
+}
+
+void DownloadItemImpl::DestinationCompleted(const std::string& final_hash) {
+ if (!IsInProgress())
+ return;
+ OnAllDataSaved(final_hash);
+ delegate_->MaybeCompleteDownload(this);
+}
+
// **** Download progression cascade
void DownloadItemImpl::Init(bool active,
@@ -998,7 +1105,37 @@ void DownloadItemImpl::Init(bool active,
VLOG(20) << __FUNCTION__ << "() " << DebugString(true);
}
-// Called by DownloadManagerImpl when the download target path has been
+// We're starting the download.
+void DownloadItemImpl::Start(scoped_ptr<content::DownloadFile> download_file) {
+ DCHECK(!download_file_.get());
+ download_file_ = download_file.Pass();
benjhayden 2012/09/12 21:01:01 DCHECK(download_file_.get());?
Randy Smith (Not in Mondays) 2012/09/13 20:15:12 Equivalent done.
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DownloadFile::Initialize,
+ // Safe because we control download file lifetime.
+ base::Unretained(download_file_.get()),
+ base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void DownloadItemImpl::OnDownloadFileInitialized(
+ content::DownloadInterruptReason result) {
+ if (result != content::DOWNLOAD_INTERRUPT_REASON_NONE) {
+ Interrupt(result);
+ // TODO(rdsmith): It makes no sense to continue along the
+ // regular download path after we've gotten an error. But it's
+ // the way the code has historically worked, and this allows us
+ // to get the download persisted and observers of the download manager
+ // notified, so tests work. When we execute all side effects of cancel
+ // (including queue removal) immedately rather than waiting for
+ // persistence we should replace this comment with a "return;".
+ }
+
+ delegate_->DelegateStart(this);
+}
+
+// Called by delegate_ when the download target path has been
// determined.
void DownloadItemImpl::OnDownloadTargetDetermined(
const FilePath& target_path,
@@ -1024,18 +1161,31 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
// space/permission/availability constraints.
DCHECK(intermediate_path.DirName() == target_path.DirName());
+ if (!IsInProgress()) {
+ // If we've been cancelled or interrupted while the target was being
+ // determined, continue the cascade with a null name.
+ // The error doesn't matter as the cause of download stoppaged
+ // will already have been recorded.
+ OnDownloadRenamedToIntermediateName(
+ content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, FilePath());
+ return;
+ }
+
// Rename to intermediate name.
// TODO(asanka): Skip this rename if AllDataSaved() is true. This avoids a
// spurious rename when we can just rename to the final
// filename. Unnecessary renames may cause bugs like
// http://crbug.com/74187.
- DownloadFileManager::RenameCompletionCallback callback =
+ DCHECK(!is_save_package_download_);
+ CHECK(download_file_.get());
+ DownloadFile::RenameCompletionCallback callback =
base::Bind(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
weak_ptr_factory_.GetWeakPtr());
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::RenameDownloadFile,
- delegate_->GetDownloadFileManager(), GetGlobalId(),
+ base::Bind(&DownloadFile::Rename,
+ // Safe because we control download file lifetime.
+ base::Unretained(download_file_.get()),
intermediate_path, false, callback));
}
@@ -1063,29 +1213,35 @@ void DownloadItemImpl::MaybeCompleteDownload() {
void DownloadItemImpl::OnDownloadCompleting() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!IsInProgress())
+ return;
+
VLOG(20) << __FUNCTION__ << "()"
<< " needs rename = " << NeedsRename()
<< " " << DebugString(true);
DCHECK(!GetTargetName().empty());
DCHECK_NE(DANGEROUS, GetSafetyState());
+ // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
+ if (is_save_package_download_) {
+ // Avoid doing anything on the file thread; there's nothing we control
+ // there.
+ OnDownloadFileReleased();
+ return;
+ }
+
+ CHECK(download_file_.get());
if (NeedsRename()) {
- DownloadFileManager::RenameCompletionCallback callback =
+ content::DownloadFile::RenameCompletionCallback callback =
base::Bind(&DownloadItemImpl::OnDownloadRenamedToFinalName,
weak_ptr_factory_.GetWeakPtr());
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::RenameDownloadFile,
- delegate_->GetDownloadFileManager(), GetGlobalId(),
+ base::Bind(&DownloadFile::Rename,
+ base::Unretained(download_file_.get()),
GetTargetFilePath(), true, callback));
} else {
- // Complete the download and release the DownloadFile.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::CompleteDownload,
- delegate_->GetDownloadFileManager(), GetGlobalId(),
- base::Bind(&DownloadItemImpl::OnDownloadFileReleased,
- weak_ptr_factory_.GetWeakPtr())));
+ ReleaseDownloadFile();
}
}
@@ -1094,6 +1250,9 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
const FilePath& full_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!IsInProgress())
+ return;
+
VLOG(20) << __FUNCTION__ << "()"
<< " full_path = \"" << full_path.value() << "\""
<< " needed rename = " << NeedsRename()
@@ -1111,13 +1270,25 @@ void DownloadItemImpl::OnDownloadRenamedToFinalName(
SetFullPath(full_path);
delegate_->DownloadRenamedToFinalName(this);
+ ReleaseDownloadFile();
+}
+
+void DownloadItemImpl::ReleaseDownloadFile() {
// Complete the download and release the DownloadFile.
+ DCHECK(!is_save_package_download_);
+ CHECK(download_file_.get());
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
- base::Bind(&DownloadFileManager::CompleteDownload,
- delegate_->GetDownloadFileManager(), GetGlobalId(),
+ base::Bind(&DownloadFileDetach, base::Passed(download_file_.Pass()),
base::Bind(&DownloadItemImpl::OnDownloadFileReleased,
weak_ptr_factory_.GetWeakPtr())));
+
+ // We're not completely done with the download item yet, but at this
+ // point we're committed to complete the download. Cancels (or Interrupts,
+ // though it's not clear how they could happen) after this point will be
+ // ignored.
+ TransitionTo(COMPLETE);
+ delegate_->DownloadCompleted(this);
}
void DownloadItemImpl::OnDownloadFileReleased() {
@@ -1130,6 +1301,7 @@ void DownloadItemImpl::OnDownloadFileReleased() {
void DownloadItemImpl::DelayedDownloadOpened(bool auto_opened) {
auto_opened_ = auto_opened;
Completed();
+ UpdateObservers();
}
void DownloadItemImpl::Completed() {
@@ -1139,8 +1311,6 @@ void DownloadItemImpl::Completed() {
DCHECK(all_data_saved_);
end_time_ = base::Time::Now();
- TransitionTo(COMPLETE);
- delegate_->DownloadCompleted(this);
download_stats::RecordDownloadCompleted(start_tick_, received_bytes_);
if (auto_opened_) {
@@ -1166,21 +1336,6 @@ bool DownloadItemImpl::NeedsRename() const {
return target_path_ != current_path_;
}
-void DownloadItemImpl::ProgressComplete(int64 bytes_so_far,
- const std::string& final_hash) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- hash_ = final_hash;
- hash_state_ = "";
-
- received_bytes_ = bytes_so_far;
-
- // If we've received more data than we were expecting (bad server info?),
- // revert to 'unknown size mode'.
- if (received_bytes_ > total_bytes_)
- total_bytes_ = 0;
-}
-
void DownloadItemImpl::TransitionTo(DownloadState new_state) {
if (state_ == new_state)
return;
@@ -1249,7 +1404,3 @@ void DownloadItemImpl::SetFullPath(const FilePath& new_path) {
base::Bind(&download_net_logs::ItemRenamedCallback,
&current_path_, &new_path));
}
-
-
-
-

Powered by Google App Engine
This is Rietveld 408576698