OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/download/download_file_impl.h" | 5 #include "content/browser/download/download_file_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/threading/sequenced_task_runner_handle.h" |
14 #include "base/time/time.h" | 15 #include "base/time/time.h" |
15 #include "base/values.h" | 16 #include "base/values.h" |
16 #include "content/browser/byte_stream.h" | 17 #include "content/browser/byte_stream.h" |
17 #include "content/browser/download/download_create_info.h" | 18 #include "content/browser/download/download_create_info.h" |
18 #include "content/browser/download/download_destination_observer.h" | 19 #include "content/browser/download/download_destination_observer.h" |
19 #include "content/browser/download/download_interrupt_reasons_impl.h" | 20 #include "content/browser/download/download_interrupt_reasons_impl.h" |
20 #include "content/browser/download/download_net_log_parameters.h" | 21 #include "content/browser/download/download_net_log_parameters.h" |
21 #include "content/browser/download/download_stats.h" | 22 #include "content/browser/download/download_stats.h" |
22 #include "content/browser/download/parallel_download_utils.h" | 23 #include "content/browser/download/parallel_download_utils.h" |
23 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 weak_factory_(this) { | 114 weak_factory_(this) { |
114 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( | 115 source_streams_[save_info_->offset] = base::MakeUnique<SourceStream>( |
115 save_info_->offset, save_info_->length, std::move(stream_reader)); | 116 save_info_->offset, save_info_->length, std::move(stream_reader)); |
116 | 117 |
117 download_item_net_log.AddEvent( | 118 download_item_net_log.AddEvent( |
118 net::NetLogEventType::DOWNLOAD_FILE_CREATED, | 119 net::NetLogEventType::DOWNLOAD_FILE_CREATED, |
119 net_log_.source().ToEventParametersCallback()); | 120 net_log_.source().ToEventParametersCallback()); |
120 net_log_.BeginEvent( | 121 net_log_.BeginEvent( |
121 net::NetLogEventType::DOWNLOAD_FILE_ACTIVE, | 122 net::NetLogEventType::DOWNLOAD_FILE_ACTIVE, |
122 download_item_net_log.source().ToEventParametersCallback()); | 123 download_item_net_log.source().ToEventParametersCallback()); |
| 124 |
| 125 DETACH_FROM_SEQUENCE(sequence_checker_); |
123 } | 126 } |
124 | 127 |
125 DownloadFileImpl::~DownloadFileImpl() { | 128 DownloadFileImpl::~DownloadFileImpl() { |
126 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 129 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 130 |
127 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE); | 131 net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE); |
128 } | 132 } |
129 | 133 |
130 void DownloadFileImpl::Initialize( | 134 void DownloadFileImpl::Initialize( |
131 const InitializeCallback& initialize_callback, | 135 const InitializeCallback& initialize_callback, |
132 const CancelRequestCallback& cancel_request_callback, | 136 const CancelRequestCallback& cancel_request_callback, |
133 const DownloadItem::ReceivedSlices& received_slices, | 137 const DownloadItem::ReceivedSlices& received_slices, |
134 bool is_parallelizable) { | 138 bool is_parallelizable) { |
135 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 139 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
136 | 140 |
137 update_timer_.reset(new base::RepeatingTimer()); | 141 update_timer_.reset(new base::RepeatingTimer()); |
138 int64_t bytes_so_far = 0; | 142 int64_t bytes_so_far = 0; |
139 cancel_request_callback_ = cancel_request_callback; | 143 cancel_request_callback_ = cancel_request_callback; |
140 received_slices_ = received_slices; | 144 received_slices_ = received_slices; |
141 if (IsSparseFile()) { | 145 if (IsSparseFile()) { |
142 for (const auto& received_slice : received_slices_) { | 146 for (const auto& received_slice : received_slices_) { |
143 bytes_so_far += received_slice.received_bytes; | 147 bytes_so_far += received_slice.received_bytes; |
144 } | 148 } |
145 } else { | 149 } else { |
(...skipping 23 matching lines...) Expand all Loading... |
169 | 173 |
170 // Initial pull from the straw from all source streams. | 174 // Initial pull from the straw from all source streams. |
171 for (auto& source_stream : source_streams_) | 175 for (auto& source_stream : source_streams_) |
172 RegisterAndActivateStream(source_stream.second.get()); | 176 RegisterAndActivateStream(source_stream.second.get()); |
173 } | 177 } |
174 | 178 |
175 void DownloadFileImpl::AddByteStream( | 179 void DownloadFileImpl::AddByteStream( |
176 std::unique_ptr<ByteStreamReader> stream_reader, | 180 std::unique_ptr<ByteStreamReader> stream_reader, |
177 int64_t offset, | 181 int64_t offset, |
178 int64_t length) { | 182 int64_t length) { |
179 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 183 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
180 | 184 |
181 source_streams_[offset] = | 185 source_streams_[offset] = |
182 base::MakeUnique<SourceStream>(offset, length, std::move(stream_reader)); | 186 base::MakeUnique<SourceStream>(offset, length, std::move(stream_reader)); |
183 | 187 |
184 // There are writers at different offsets now, create the received slices | 188 // There are writers at different offsets now, create the received slices |
185 // vector if necessary. | 189 // vector if necessary. |
186 if (received_slices_.empty() && TotalBytesReceived() > 0) { | 190 if (received_slices_.empty() && TotalBytesReceived() > 0) { |
187 size_t index = AddOrMergeReceivedSliceIntoSortedArray( | 191 size_t index = AddOrMergeReceivedSliceIntoSortedArray( |
188 DownloadItem::ReceivedSlice(0, TotalBytesReceived()), received_slices_); | 192 DownloadItem::ReceivedSlice(0, TotalBytesReceived()), received_slices_); |
189 DCHECK_EQ(index, 0u); | 193 DCHECK_EQ(index, 0u); |
190 } | 194 } |
191 // If the file is initialized, start to write data, or wait until file opened. | 195 // If the file is initialized, start to write data, or wait until file opened. |
192 if (file_.in_progress()) | 196 if (file_.in_progress()) |
193 RegisterAndActivateStream(source_streams_[offset].get()); | 197 RegisterAndActivateStream(source_streams_[offset].get()); |
194 } | 198 } |
195 | 199 |
196 DownloadInterruptReason DownloadFileImpl::WriteDataToFile(int64_t offset, | 200 DownloadInterruptReason DownloadFileImpl::WriteDataToFile(int64_t offset, |
197 const char* data, | 201 const char* data, |
198 size_t data_len) { | 202 size_t data_len) { |
199 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 203 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 204 |
200 WillWriteToDisk(data_len); | 205 WillWriteToDisk(data_len); |
201 return file_.WriteDataToFile(offset, data, data_len); | 206 return file_.WriteDataToFile(offset, data, data_len); |
202 } | 207 } |
203 | 208 |
204 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, | 209 bool DownloadFileImpl::CalculateBytesToWrite(SourceStream* source_stream, |
205 size_t bytes_available_to_write, | 210 size_t bytes_available_to_write, |
206 size_t* bytes_to_write) { | 211 size_t* bytes_to_write) { |
207 if (source_stream->length() == kNoBytesToWrite) { | 212 if (source_stream->length() == kNoBytesToWrite) { |
208 *bytes_to_write = 0; | 213 *bytes_to_write = 0; |
209 return true; | 214 return true; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) * | 272 return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) * |
268 (1 << attempt_number); | 273 (1 << attempt_number); |
269 } | 274 } |
270 | 275 |
271 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) { | 276 bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) { |
272 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR; | 277 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR; |
273 } | 278 } |
274 | 279 |
275 void DownloadFileImpl::RenameWithRetryInternal( | 280 void DownloadFileImpl::RenameWithRetryInternal( |
276 std::unique_ptr<RenameParameters> parameters) { | 281 std::unique_ptr<RenameParameters> parameters) { |
277 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 282 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
278 | 283 |
279 base::FilePath new_path = parameters->new_path; | 284 base::FilePath new_path = parameters->new_path; |
280 | 285 |
281 if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) { | 286 if ((parameters->option & UNIQUIFY) && new_path != file_.full_path()) { |
282 int uniquifier = | 287 int uniquifier = |
283 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); | 288 base::GetUniquePathNumber(new_path, base::FilePath::StringType()); |
284 if (uniquifier > 0) | 289 if (uniquifier > 0) |
285 new_path = new_path.InsertBeforeExtensionASCII( | 290 new_path = new_path.InsertBeforeExtensionASCII( |
286 base::StringPrintf(" (%d)", uniquifier)); | 291 base::StringPrintf(" (%d)", uniquifier)); |
287 } | 292 } |
288 | 293 |
289 DownloadInterruptReason reason = file_.Rename(new_path); | 294 DownloadInterruptReason reason = file_.Rename(new_path); |
290 | 295 |
291 // Attempt to retry the rename if possible. If the rename failed and the | 296 // Attempt to retry the rename if possible. If the rename failed and the |
292 // subsequent open also failed, then in_progress() would be false. We don't | 297 // subsequent open also failed, then in_progress() would be false. We don't |
293 // try to retry renames if the in_progress() was false to begin with since we | 298 // try to retry renames if the in_progress() was false to begin with since we |
294 // have less assurance that the file at file_.full_path() was the one we were | 299 // have less assurance that the file at file_.full_path() was the one we were |
295 // working with. | 300 // working with. |
296 if (ShouldRetryFailedRename(reason) && file_.in_progress() && | 301 if (ShouldRetryFailedRename(reason) && file_.in_progress() && |
297 parameters->retries_left > 0) { | 302 parameters->retries_left > 0) { |
298 int attempt_number = kMaxRenameRetries - parameters->retries_left; | 303 int attempt_number = kMaxRenameRetries - parameters->retries_left; |
299 --parameters->retries_left; | 304 --parameters->retries_left; |
300 if (parameters->time_of_first_failure.is_null()) | 305 if (parameters->time_of_first_failure.is_null()) |
301 parameters->time_of_first_failure = base::TimeTicks::Now(); | 306 parameters->time_of_first_failure = base::TimeTicks::Now(); |
302 BrowserThread::PostDelayedTask( | 307 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
303 BrowserThread::FILE, | |
304 FROM_HERE, | 308 FROM_HERE, |
305 base::Bind(&DownloadFileImpl::RenameWithRetryInternal, | 309 base::Bind(&DownloadFileImpl::RenameWithRetryInternal, |
306 weak_factory_.GetWeakPtr(), | 310 weak_factory_.GetWeakPtr(), |
307 base::Passed(std::move(parameters))), | 311 base::Passed(std::move(parameters))), |
308 GetRetryDelayForFailedRename(attempt_number)); | 312 GetRetryDelayForFailedRename(attempt_number)); |
309 return; | 313 return; |
310 } | 314 } |
311 | 315 |
312 if (!parameters->time_of_first_failure.is_null()) | 316 if (!parameters->time_of_first_failure.is_null()) |
313 RecordDownloadFileRenameResultAfterRetry( | 317 RecordDownloadFileRenameResultAfterRetry( |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 | 383 |
380 bool DownloadFileImpl::InProgress() const { | 384 bool DownloadFileImpl::InProgress() const { |
381 return file_.in_progress(); | 385 return file_.in_progress(); |
382 } | 386 } |
383 | 387 |
384 void DownloadFileImpl::WasPaused() { | 388 void DownloadFileImpl::WasPaused() { |
385 record_stream_bandwidth_ = false; | 389 record_stream_bandwidth_ = false; |
386 } | 390 } |
387 | 391 |
388 void DownloadFileImpl::StreamActive(SourceStream* source_stream) { | 392 void DownloadFileImpl::StreamActive(SourceStream* source_stream) { |
| 393 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
389 DCHECK(source_stream->stream_reader()); | 394 DCHECK(source_stream->stream_reader()); |
390 base::TimeTicks start(base::TimeTicks::Now()); | 395 base::TimeTicks start(base::TimeTicks::Now()); |
391 base::TimeTicks now; | 396 base::TimeTicks now; |
392 scoped_refptr<net::IOBuffer> incoming_data; | 397 scoped_refptr<net::IOBuffer> incoming_data; |
393 size_t incoming_data_size = 0; | 398 size_t incoming_data_size = 0; |
394 size_t total_incoming_data_size = 0; | 399 size_t total_incoming_data_size = 0; |
395 size_t num_buffers = 0; | 400 size_t num_buffers = 0; |
396 size_t bytes_to_write = 0; | 401 size_t bytes_to_write = 0; |
397 bool should_terminate = false; | 402 bool should_terminate = false; |
398 ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY); | 403 ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 break; | 466 break; |
462 } | 467 } |
463 now = base::TimeTicks::Now(); | 468 now = base::TimeTicks::Now(); |
464 } while (state == ByteStreamReader::STREAM_HAS_DATA && | 469 } while (state == ByteStreamReader::STREAM_HAS_DATA && |
465 reason == DOWNLOAD_INTERRUPT_REASON_NONE && now - start <= delta && | 470 reason == DOWNLOAD_INTERRUPT_REASON_NONE && now - start <= delta && |
466 !should_terminate); | 471 !should_terminate); |
467 | 472 |
468 // If we're stopping to yield the thread, post a task so we come back. | 473 // If we're stopping to yield the thread, post a task so we come back. |
469 if (state == ByteStreamReader::STREAM_HAS_DATA && now - start > delta && | 474 if (state == ByteStreamReader::STREAM_HAS_DATA && now - start > delta && |
470 !should_terminate) { | 475 !should_terminate) { |
471 BrowserThread::PostTask( | 476 base::SequencedTaskRunnerHandle::Get()->PostTask( |
472 BrowserThread::FILE, FROM_HERE, | 477 FROM_HERE, base::Bind(&DownloadFileImpl::StreamActive, |
473 base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr(), | 478 weak_factory_.GetWeakPtr(), source_stream)); |
474 source_stream)); | |
475 } | 479 } |
476 | 480 |
477 if (total_incoming_data_size) | 481 if (total_incoming_data_size) |
478 RecordFileThreadReceiveBuffers(num_buffers); | 482 RecordFileThreadReceiveBuffers(num_buffers); |
479 | 483 |
480 RecordContiguousWriteTime(now - start); | 484 RecordContiguousWriteTime(now - start); |
481 | 485 |
482 // Take care of communication with our observer. | 486 // Take care of communication with our observer. |
483 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { | 487 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) { |
484 HandleStreamError(source_stream, reason); | 488 HandleStreamError(source_stream, reason); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 } | 523 } |
520 } | 524 } |
521 if (net_log_.IsCapturing()) { | 525 if (net_log_.IsCapturing()) { |
522 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED, | 526 net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED, |
523 base::Bind(&FileStreamDrainedNetLogCallback, | 527 base::Bind(&FileStreamDrainedNetLogCallback, |
524 total_incoming_data_size, num_buffers)); | 528 total_incoming_data_size, num_buffers)); |
525 } | 529 } |
526 } | 530 } |
527 | 531 |
528 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { | 532 void DownloadFileImpl::RegisterAndActivateStream(SourceStream* source_stream) { |
529 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 533 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 534 |
530 ByteStreamReader* stream_reader = source_stream->stream_reader(); | 535 ByteStreamReader* stream_reader = source_stream->stream_reader(); |
531 if (stream_reader) { | 536 if (stream_reader) { |
532 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, | 537 stream_reader->RegisterCallback(base::Bind(&DownloadFileImpl::StreamActive, |
533 weak_factory_.GetWeakPtr(), | 538 weak_factory_.GetWeakPtr(), |
534 source_stream)); | 539 source_stream)); |
535 // Truncate |source_stream|'s length if necessary. | 540 // Truncate |source_stream|'s length if necessary. |
536 for (const auto& received_slice : received_slices_) { | 541 for (const auto& received_slice : received_slices_) { |
537 source_stream->TruncateLengthWithWrittenDataBlock( | 542 source_stream->TruncateLengthWithWrittenDataBlock( |
538 received_slice.offset, received_slice.received_bytes); | 543 received_slice.offset, received_slice.received_bytes); |
539 } | 544 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 if (slices_to_download.size() > 1) { | 614 if (slices_to_download.size() > 1) { |
610 // If there are 1 or more holes in the file, download is not finished. | 615 // If there are 1 or more holes in the file, download is not finished. |
611 // Some streams might not have been added to |source_streams_| yet. | 616 // Some streams might not have been added to |source_streams_| yet. |
612 return false; | 617 return false; |
613 } | 618 } |
614 return TotalBytesReceived() == potential_file_length_; | 619 return TotalBytesReceived() == potential_file_length_; |
615 } | 620 } |
616 | 621 |
617 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, | 622 void DownloadFileImpl::HandleStreamError(SourceStream* source_stream, |
618 DownloadInterruptReason reason) { | 623 DownloadInterruptReason reason) { |
619 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 624 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| 625 |
620 source_stream->stream_reader()->RegisterCallback(base::Closure()); | 626 source_stream->stream_reader()->RegisterCallback(base::Closure()); |
621 source_stream->set_finished(true); | 627 source_stream->set_finished(true); |
622 num_active_streams_--; | 628 num_active_streams_--; |
623 | 629 |
624 bool can_recover_from_error = (source_stream->length() == kNoBytesToWrite); | 630 bool can_recover_from_error = (source_stream->length() == kNoBytesToWrite); |
625 | 631 |
626 if (IsSparseFile() && !can_recover_from_error) { | 632 if (IsSparseFile() && !can_recover_from_error) { |
627 // If a neighboring stream request is available, check if it can help | 633 // If a neighboring stream request is available, check if it can help |
628 // download all the data left by |source stream| or has already done so. We | 634 // download all the data left by |source stream| or has already done so. We |
629 // want to avoid the situation that a server always fail additional requests | 635 // want to avoid the situation that a server always fail additional requests |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 const base::FilePath& new_path, | 732 const base::FilePath& new_path, |
727 const RenameCompletionCallback& completion_callback) | 733 const RenameCompletionCallback& completion_callback) |
728 : option(option), | 734 : option(option), |
729 new_path(new_path), | 735 new_path(new_path), |
730 retries_left(kMaxRenameRetries), | 736 retries_left(kMaxRenameRetries), |
731 completion_callback(completion_callback) {} | 737 completion_callback(completion_callback) {} |
732 | 738 |
733 DownloadFileImpl::RenameParameters::~RenameParameters() {} | 739 DownloadFileImpl::RenameParameters::~RenameParameters() {} |
734 | 740 |
735 } // namespace content | 741 } // namespace content |
OLD | NEW |