Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / download / download_file_impl.cc
blob11e98cb726bc6bfc566686bdd281647cb8ebf7c8
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
3 // found in the LICENSE file.
5 #include "content/browser/download/download_file_impl.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/file_util.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "content/browser/byte_stream.h"
15 #include "content/browser/download/download_create_info.h"
16 #include "content/browser/download/download_interrupt_reasons_impl.h"
17 #include "content/browser/download/download_net_log_parameters.h"
18 #include "content/browser/download/download_stats.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/download_destination_observer.h"
21 #include "net/base/io_buffer.h"
23 namespace content {
25 const int kUpdatePeriodMs = 500;
26 const int kMaxTimeBlockingFileThreadMs = 1000;
28 int DownloadFile::number_active_objects_ = 0;
30 DownloadFileImpl::DownloadFileImpl(
31 scoped_ptr<DownloadSaveInfo> save_info,
32 const base::FilePath& default_download_directory,
33 const GURL& url,
34 const GURL& referrer_url,
35 bool calculate_hash,
36 scoped_ptr<ByteStreamReader> stream,
37 const net::BoundNetLog& bound_net_log,
38 base::WeakPtr<DownloadDestinationObserver> observer)
39 : file_(save_info->file_path,
40 url,
41 referrer_url,
42 save_info->offset,
43 calculate_hash,
44 save_info->hash_state,
45 save_info->file.Pass(),
46 bound_net_log),
47 default_download_directory_(default_download_directory),
48 stream_reader_(stream.Pass()),
49 bytes_seen_(0),
50 bound_net_log_(bound_net_log),
51 observer_(observer),
52 weak_factory_(this) {
55 DownloadFileImpl::~DownloadFileImpl() {
56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
57 --number_active_objects_;
60 void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
63 update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
64 DownloadInterruptReason result =
65 file_.Initialize(default_download_directory_);
66 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
67 BrowserThread::PostTask(
68 BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
69 return;
72 stream_reader_->RegisterCallback(
73 base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr()));
75 download_start_ = base::TimeTicks::Now();
77 // Primarily to make reset to zero in restart visible to owner.
78 SendUpdate();
80 // Initial pull from the straw.
81 StreamActive();
83 BrowserThread::PostTask(
84 BrowserThread::UI, FROM_HERE, base::Bind(
85 callback, DOWNLOAD_INTERRUPT_REASON_NONE));
87 ++number_active_objects_;
90 DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
91 const char* data, size_t data_len) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
94 if (!update_timer_->IsRunning()) {
95 update_timer_->Start(FROM_HERE,
96 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
97 this, &DownloadFileImpl::SendUpdate);
99 rate_estimator_.Increment(data_len);
100 return file_.AppendDataToFile(data, data_len);
103 void DownloadFileImpl::RenameAndUniquify(
104 const base::FilePath& full_path,
105 const RenameCompletionCallback& callback) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
108 base::FilePath new_path(full_path);
110 int uniquifier = base::GetUniquePathNumber(
111 new_path, base::FilePath::StringType());
112 if (uniquifier > 0) {
113 new_path = new_path.InsertBeforeExtensionASCII(
114 base::StringPrintf(" (%d)", uniquifier));
117 DownloadInterruptReason reason = file_.Rename(new_path);
118 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
119 // Make sure our information is updated, since we're about to
120 // error out.
121 SendUpdate();
123 // Null out callback so that we don't do any more stream processing.
124 stream_reader_->RegisterCallback(base::Closure());
126 new_path.clear();
129 BrowserThread::PostTask(
130 BrowserThread::UI, FROM_HERE,
131 base::Bind(callback, reason, new_path));
134 void DownloadFileImpl::RenameAndAnnotate(
135 const base::FilePath& full_path,
136 const RenameCompletionCallback& callback) {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
139 base::FilePath new_path(full_path);
141 DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
142 // Short circuit null rename.
143 if (full_path != file_.full_path())
144 reason = file_.Rename(new_path);
146 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
147 // Doing the annotation after the rename rather than before leaves
148 // a very small window during which the file has the final name but
149 // hasn't been marked with the Mark Of The Web. However, it allows
150 // anti-virus scanners on Windows to actually see the data
151 // (http://crbug.com/127999) under the correct name (which is information
152 // it uses).
153 reason = file_.AnnotateWithSourceInformation();
156 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
157 // Make sure our information is updated, since we're about to
158 // error out.
159 SendUpdate();
161 // Null out callback so that we don't do any more stream processing.
162 stream_reader_->RegisterCallback(base::Closure());
164 new_path.clear();
167 BrowserThread::PostTask(
168 BrowserThread::UI, FROM_HERE,
169 base::Bind(callback, reason, new_path));
172 void DownloadFileImpl::Detach() {
173 file_.Detach();
176 void DownloadFileImpl::Cancel() {
177 file_.Cancel();
180 base::FilePath DownloadFileImpl::FullPath() const {
181 return file_.full_path();
184 bool DownloadFileImpl::InProgress() const {
185 return file_.in_progress();
188 int64 DownloadFileImpl::CurrentSpeed() const {
189 return rate_estimator_.GetCountPerSecond();
192 bool DownloadFileImpl::GetHash(std::string* hash) {
193 return file_.GetHash(hash);
196 std::string DownloadFileImpl::GetHashState() {
197 return file_.GetHashState();
200 void DownloadFileImpl::SetClientGuid(const std::string& guid) {
201 file_.SetClientGuid(guid);
204 void DownloadFileImpl::StreamActive() {
205 base::TimeTicks start(base::TimeTicks::Now());
206 base::TimeTicks now;
207 scoped_refptr<net::IOBuffer> incoming_data;
208 size_t incoming_data_size = 0;
209 size_t total_incoming_data_size = 0;
210 size_t num_buffers = 0;
211 ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY);
212 DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
213 base::TimeDelta delta(
214 base::TimeDelta::FromMilliseconds(kMaxTimeBlockingFileThreadMs));
216 // Take care of any file local activity required.
217 do {
218 state = stream_reader_->Read(&incoming_data, &incoming_data_size);
220 switch (state) {
221 case ByteStreamReader::STREAM_EMPTY:
222 break;
223 case ByteStreamReader::STREAM_HAS_DATA:
225 ++num_buffers;
226 base::TimeTicks write_start(base::TimeTicks::Now());
227 reason = AppendDataToFile(
228 incoming_data.get()->data(), incoming_data_size);
229 disk_writes_time_ += (base::TimeTicks::Now() - write_start);
230 bytes_seen_ += incoming_data_size;
231 total_incoming_data_size += incoming_data_size;
233 break;
234 case ByteStreamReader::STREAM_COMPLETE:
236 reason = static_cast<DownloadInterruptReason>(
237 stream_reader_->GetStatus());
238 SendUpdate();
239 base::TimeTicks close_start(base::TimeTicks::Now());
240 file_.Finish();
241 base::TimeTicks now(base::TimeTicks::Now());
242 disk_writes_time_ += (now - close_start);
243 RecordFileBandwidth(
244 bytes_seen_, disk_writes_time_, now - download_start_);
245 update_timer_.reset();
247 break;
248 default:
249 NOTREACHED();
250 break;
252 now = base::TimeTicks::Now();
253 } while (state == ByteStreamReader::STREAM_HAS_DATA &&
254 reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
255 now - start <= delta);
257 // If we're stopping to yield the thread, post a task so we come back.
258 if (state == ByteStreamReader::STREAM_HAS_DATA &&
259 now - start > delta) {
260 BrowserThread::PostTask(
261 BrowserThread::FILE, FROM_HERE,
262 base::Bind(&DownloadFileImpl::StreamActive,
263 weak_factory_.GetWeakPtr()));
266 if (total_incoming_data_size)
267 RecordFileThreadReceiveBuffers(num_buffers);
269 RecordContiguousWriteTime(now - start);
271 // Take care of communication with our observer.
272 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
273 // Error case for both upstream source and file write.
274 // Shut down processing and signal an error to our observer.
275 // Our observer will clean us up.
276 stream_reader_->RegisterCallback(base::Closure());
277 weak_factory_.InvalidateWeakPtrs();
278 SendUpdate(); // Make info up to date before error.
279 BrowserThread::PostTask(
280 BrowserThread::UI, FROM_HERE,
281 base::Bind(&DownloadDestinationObserver::DestinationError,
282 observer_, reason));
283 } else if (state == ByteStreamReader::STREAM_COMPLETE) {
284 // Signal successful completion and shut down processing.
285 stream_reader_->RegisterCallback(base::Closure());
286 weak_factory_.InvalidateWeakPtrs();
287 std::string hash;
288 if (!GetHash(&hash) || file_.IsEmptyHash(hash))
289 hash.clear();
290 SendUpdate();
291 BrowserThread::PostTask(
292 BrowserThread::UI, FROM_HERE,
293 base::Bind(
294 &DownloadDestinationObserver::DestinationCompleted,
295 observer_, hash));
297 if (bound_net_log_.IsLogging()) {
298 bound_net_log_.AddEvent(
299 net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
300 base::Bind(&FileStreamDrainedNetLogCallback, total_incoming_data_size,
301 num_buffers));
305 void DownloadFileImpl::SendUpdate() {
306 BrowserThread::PostTask(
307 BrowserThread::UI, FROM_HERE,
308 base::Bind(&DownloadDestinationObserver::DestinationUpdate,
309 observer_, file_.bytes_so_far(), CurrentSpeed(),
310 GetHashState()));
313 // static
314 int DownloadFile::GetNumberOfDownloadFiles() {
315 return number_active_objects_;
318 } // namespace content