OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "chrome/browser/component_updater/background_downloader_win.h" | 5 #include "chrome/browser/component_updater/background_downloader_win.h" |
6 | 6 |
7 #include <atlbase.h> | 7 #include <atlbase.h> |
8 #include <atlcom.h> | 8 #include <atlcom.h> |
9 | 9 |
10 #include <functional> | 10 #include <functional> |
11 #include <iomanip> | 11 #include <iomanip> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
15 #include "base/message_loop/message_loop_proxy.h" | |
15 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
16 #include "base/win/scoped_co_mem.h" | 17 #include "base/win/scoped_co_mem.h" |
17 #include "chrome/browser/component_updater/component_updater_utils.h" | 18 #include "chrome/browser/component_updater/component_updater_utils.h" |
18 #include "content/public/browser/browser_thread.h" | |
19 #include "ui/base/win/atl_module.h" | 19 #include "ui/base/win/atl_module.h" |
20 #include "url/gurl.h" | 20 #include "url/gurl.h" |
21 | 21 |
22 using base::win::ScopedCoMem; | 22 using base::win::ScopedCoMem; |
23 using base::win::ScopedComPtr; | 23 using base::win::ScopedComPtr; |
24 using content::BrowserThread; | |
25 | 24 |
26 // The class BackgroundDownloader in this module is an adapter between | 25 // The class BackgroundDownloader in this module is an adapter between |
27 // the CrxDownloader interface and the BITS service interfaces. | 26 // the CrxDownloader interface and the BITS service interfaces. |
28 // The interface exposed on the CrxDownloader code runs on the UI thread, while | 27 // The interface exposed on the CrxDownloader code runs on the main thread, |
29 // the BITS specific code runs in a single threaded apartment on the FILE | 28 // while the BITS specific code runs on a single thread task runner. |
blundell
2014/07/15 08:45:20
I would say something like "a separate thread pass
tommycli
2014/07/15 18:58:25
Done.
| |
30 // thread. | |
31 // For every url to download, a BITS job is created, unless there is already | 29 // For every url to download, a BITS job is created, unless there is already |
32 // an existing job for that url, in which case, the downloader connects to it. | 30 // an existing job for that url, in which case, the downloader connects to it. |
33 // Once a job is associated with the url, the code looks for changes in the | 31 // Once a job is associated with the url, the code looks for changes in the |
34 // BITS job state. The checks are triggered by a timer. | 32 // BITS job state. The checks are triggered by a timer. |
35 // The BITS job contains just one file to download. There could only be one | 33 // The BITS job contains just one file to download. There could only be one |
36 // download in progress at a time. If Chrome closes down before the download is | 34 // download in progress at a time. If Chrome closes down before the download is |
37 // complete, the BITS job remains active and finishes in the background, without | 35 // complete, the BITS job remains active and finishes in the background, without |
38 // any intervention. The job can be completed next time the code runs, if the | 36 // any intervention. The job can be completed next time the code runs, if the |
39 // file is still needed, otherwise it will be cleaned up on a periodic basis. | 37 // file is still needed, otherwise it will be cleaned up on a periodic basis. |
40 // | 38 // |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 } | 378 } |
381 | 379 |
382 return S_OK; | 380 return S_OK; |
383 } | 381 } |
384 | 382 |
385 } // namespace | 383 } // namespace |
386 | 384 |
387 BackgroundDownloader::BackgroundDownloader( | 385 BackgroundDownloader::BackgroundDownloader( |
388 scoped_ptr<CrxDownloader> successor, | 386 scoped_ptr<CrxDownloader> successor, |
389 net::URLRequestContextGetter* context_getter, | 387 net::URLRequestContextGetter* context_getter, |
390 scoped_refptr<base::SequencedTaskRunner> task_runner) | 388 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
391 : CrxDownloader(successor.Pass()), | 389 : CrxDownloader(successor.Pass()), |
390 main_loop_(base::MessageLoopProxy::current()), | |
392 context_getter_(context_getter), | 391 context_getter_(context_getter), |
393 task_runner_(task_runner), | 392 task_runner_(task_runner), |
394 is_completed_(false) { | 393 is_completed_(false) { |
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 394 DCHECK(thread_checker_.CalledOnValidThread()); |
blundell
2014/07/15 08:45:20
this DCHECK is meaningless I think as thread_check
tommycli
2014/07/15 18:58:25
Done.
| |
396 } | 395 } |
397 | 396 |
398 BackgroundDownloader::~BackgroundDownloader() { | 397 BackgroundDownloader::~BackgroundDownloader() { |
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 398 DCHECK(thread_checker_.CalledOnValidThread()); |
400 | 399 |
401 // The following objects have thread affinity and can't be destroyed on the | 400 // The following objects have thread affinity and can't be destroyed on the |
402 // UI thread. The resources managed by these objects are acquired at the | 401 // main thread. The resources managed by these objects are acquired at the |
403 // beginning of a download and released at the end of the download. Most of | 402 // beginning of a download and released at the end of the download. Most of |
404 // the time, when this destructor is called, these resources have been already | 403 // the time, when this destructor is called, these resources have been already |
405 // disposed by. Releasing the ownership here is a NOP. However, if the browser | 404 // disposed by. Releasing the ownership here is a NOP. However, if the browser |
406 // is shutting down while a download is in progress, the timer is active and | 405 // is shutting down while a download is in progress, the timer is active and |
407 // the interface pointers are valid. Releasing the ownership means leaking | 406 // the interface pointers are valid. Releasing the ownership means leaking |
408 // these objects and their associated resources. | 407 // these objects and their associated resources. |
409 timer_.release(); | 408 timer_.release(); |
410 bits_manager_.Detach(); | 409 bits_manager_.Detach(); |
411 job_.Detach(); | 410 job_.Detach(); |
412 } | 411 } |
413 | 412 |
414 void BackgroundDownloader::DoStartDownload(const GURL& url) { | 413 void BackgroundDownloader::DoStartDownload(const GURL& url) { |
415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 414 DCHECK(thread_checker_.CalledOnValidThread()); |
416 | 415 |
417 BrowserThread::PostTask( | 416 task_runner_->PostTask( |
418 BrowserThread::FILE, | |
419 FROM_HERE, | 417 FROM_HERE, |
420 base::Bind( | 418 base::Bind( |
421 &BackgroundDownloader::BeginDownload, base::Unretained(this), url)); | 419 &BackgroundDownloader::BeginDownload, base::Unretained(this), url)); |
422 } | 420 } |
423 | 421 |
424 // Called once when this class is asked to do a download. Creates or opens | 422 // Called once when this class is asked to do a download. Creates or opens |
425 // an existing bits job, hooks up the notifications, and starts the timer. | 423 // an existing bits job, hooks up the notifications, and starts the timer. |
426 void BackgroundDownloader::BeginDownload(const GURL& url) { | 424 void BackgroundDownloader::BeginDownload(const GURL& url) { |
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 425 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
428 | 426 |
429 DCHECK(!timer_); | 427 DCHECK(!timer_); |
430 | 428 |
431 is_completed_ = false; | 429 is_completed_ = false; |
432 download_start_time_ = base::Time::Now(); | 430 download_start_time_ = base::Time::Now(); |
433 job_stuck_begin_time_ = download_start_time_; | 431 job_stuck_begin_time_ = download_start_time_; |
434 | 432 |
435 HRESULT hr = QueueBitsJob(url); | 433 HRESULT hr = QueueBitsJob(url); |
436 if (FAILED(hr)) { | 434 if (FAILED(hr)) { |
437 EndDownload(hr); | 435 EndDownload(hr); |
438 return; | 436 return; |
439 } | 437 } |
440 | 438 |
441 // A repeating timer retains the user task. This timer can be stopped and | 439 // A repeating timer retains the user task. This timer can be stopped and |
442 // reset multiple times. | 440 // reset multiple times. |
443 timer_.reset(new base::RepeatingTimer<BackgroundDownloader>); | 441 timer_.reset(new base::RepeatingTimer<BackgroundDownloader>); |
444 timer_->Start(FROM_HERE, | 442 timer_->Start(FROM_HERE, |
445 base::TimeDelta::FromSeconds(kJobPollingIntervalSec), | 443 base::TimeDelta::FromSeconds(kJobPollingIntervalSec), |
446 this, | 444 this, |
447 &BackgroundDownloader::OnDownloading); | 445 &BackgroundDownloader::OnDownloading); |
448 } | 446 } |
449 | 447 |
450 // Called any time the timer fires. | 448 // Called any time the timer fires. |
451 void BackgroundDownloader::OnDownloading() { | 449 void BackgroundDownloader::OnDownloading() { |
452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 450 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
453 | 451 |
454 DCHECK(job_); | 452 DCHECK(job_); |
455 | 453 |
456 DCHECK(!is_completed_); | 454 DCHECK(!is_completed_); |
457 if (is_completed_) | 455 if (is_completed_) |
458 return; | 456 return; |
459 | 457 |
460 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR; | 458 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR; |
461 HRESULT hr = job_->GetState(&job_state); | 459 HRESULT hr = job_->GetState(&job_state); |
462 if (FAILED(hr)) { | 460 if (FAILED(hr)) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 break; | 496 break; |
499 | 497 |
500 default: | 498 default: |
501 break; | 499 break; |
502 } | 500 } |
503 } | 501 } |
504 | 502 |
505 // Completes the BITS download, picks up the file path of the response, and | 503 // Completes the BITS download, picks up the file path of the response, and |
506 // notifies the CrxDownloader. The function should be called only once. | 504 // notifies the CrxDownloader. The function should be called only once. |
507 void BackgroundDownloader::EndDownload(HRESULT error) { | 505 void BackgroundDownloader::EndDownload(HRESULT error) { |
508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 506 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
509 | 507 |
510 DCHECK(!is_completed_); | 508 DCHECK(!is_completed_); |
511 is_completed_ = true; | 509 is_completed_ = true; |
512 | 510 |
513 timer_.reset(); | 511 timer_.reset(); |
514 | 512 |
515 const base::Time download_end_time(base::Time::Now()); | 513 const base::Time download_end_time(base::Time::Now()); |
516 const base::TimeDelta download_time = | 514 const base::TimeDelta download_time = |
517 download_end_time >= download_start_time_ | 515 download_end_time >= download_start_time_ |
518 ? download_end_time - download_start_time_ | 516 ? download_end_time - download_start_time_ |
(...skipping 26 matching lines...) Expand all Loading... | |
545 download_metrics.error = error_to_report; | 543 download_metrics.error = error_to_report; |
546 download_metrics.downloaded_bytes = downloaded_bytes; | 544 download_metrics.downloaded_bytes = downloaded_bytes; |
547 download_metrics.total_bytes = total_bytes; | 545 download_metrics.total_bytes = total_bytes; |
548 download_metrics.download_time_ms = download_time.InMilliseconds(); | 546 download_metrics.download_time_ms = download_time.InMilliseconds(); |
549 | 547 |
550 Result result; | 548 Result result; |
551 result.error = error_to_report; | 549 result.error = error_to_report; |
552 result.response = response_; | 550 result.response = response_; |
553 result.downloaded_bytes = downloaded_bytes; | 551 result.downloaded_bytes = downloaded_bytes; |
554 result.total_bytes = total_bytes; | 552 result.total_bytes = total_bytes; |
555 BrowserThread::PostTask(BrowserThread::UI, | 553 main_loop_->PostTask(FROM_HERE, |
556 FROM_HERE, | 554 base::Bind(&BackgroundDownloader::OnDownloadComplete, |
557 base::Bind(&BackgroundDownloader::OnDownloadComplete, | 555 base::Unretained(this), |
558 base::Unretained(this), | 556 is_handled, |
559 is_handled, | 557 result, |
560 result, | 558 download_metrics)); |
561 download_metrics)); | |
562 | 559 |
563 // Once the task is posted to the the UI thread, this object may be deleted | 560 // Once the task is posted to the the main thread, this object may be deleted |
564 // by its owner. It is not safe to access members of this object on the | 561 // by its owner. It is not safe to access members of this object on the |
565 // FILE thread from this point on. The timer is stopped and all BITS | 562 // task runner from this point on. The timer is stopped and all BITS |
566 // interface pointers have been released. | 563 // interface pointers have been released. |
567 } | 564 } |
568 | 565 |
569 // Called when the BITS job has been transferred successfully. Completes the | 566 // Called when the BITS job has been transferred successfully. Completes the |
570 // BITS job by removing it from the BITS queue and making the download | 567 // BITS job by removing it from the BITS queue and making the download |
571 // available to the caller. | 568 // available to the caller. |
572 void BackgroundDownloader::OnStateTransferred() { | 569 void BackgroundDownloader::OnStateTransferred() { |
573 EndDownload(CompleteJob()); | 570 EndDownload(CompleteJob()); |
574 } | 571 } |
575 | 572 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
618 int64 downloaded_bytes = -1; | 615 int64 downloaded_bytes = -1; |
619 int64 total_bytes = -1; | 616 int64 total_bytes = -1; |
620 HRESULT hr = GetJobByteCount(job_, &downloaded_bytes, &total_bytes); | 617 HRESULT hr = GetJobByteCount(job_, &downloaded_bytes, &total_bytes); |
621 if (FAILED(hr)) | 618 if (FAILED(hr)) |
622 return; | 619 return; |
623 | 620 |
624 Result result; | 621 Result result; |
625 result.downloaded_bytes = downloaded_bytes; | 622 result.downloaded_bytes = downloaded_bytes; |
626 result.total_bytes = total_bytes; | 623 result.total_bytes = total_bytes; |
627 | 624 |
628 BrowserThread::PostTask(BrowserThread::UI, | 625 main_loop_->PostTask(FROM_HERE, |
629 FROM_HERE, | 626 base::Bind(&BackgroundDownloader::OnDownloadProgress, |
630 base::Bind(&BackgroundDownloader::OnDownloadProgress, | 627 base::Unretained(this), |
631 base::Unretained(this), | 628 result)); |
632 result)); | |
633 } | 629 } |
634 | 630 |
635 // Called when the download was cancelled. Since the observer should have | 631 // Called when the download was cancelled. Since the observer should have |
636 // been disconnected by now, this notification must not be seen. | 632 // been disconnected by now, this notification must not be seen. |
637 void BackgroundDownloader::OnStateCancelled() { | 633 void BackgroundDownloader::OnStateCancelled() { |
638 EndDownload(E_UNEXPECTED); | 634 EndDownload(E_UNEXPECTED); |
639 } | 635 } |
640 | 636 |
641 // Called when the download was completed. Same as above. | 637 // Called when the download was completed. Same as above. |
642 void BackgroundDownloader::OnStateAcknowledged() { | 638 void BackgroundDownloader::OnStateAcknowledged() { |
643 EndDownload(E_UNEXPECTED); | 639 EndDownload(E_UNEXPECTED); |
644 } | 640 } |
645 | 641 |
646 // Creates or opens a job for the given url and queues it up. Tries to | 642 // Creates or opens a job for the given url and queues it up. Tries to |
647 // install a job observer but continues on if an observer can't be set up. | 643 // install a job observer but continues on if an observer can't be set up. |
648 HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url) { | 644 HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url) { |
649 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 645 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
650 | 646 |
651 HRESULT hr = S_OK; | 647 HRESULT hr = S_OK; |
652 if (bits_manager_ == NULL) { | 648 if (bits_manager_ == NULL) { |
653 hr = GetBitsManager(bits_manager_.Receive()); | 649 hr = GetBitsManager(bits_manager_.Receive()); |
654 if (FAILED(hr)) | 650 if (FAILED(hr)) |
655 return hr; | 651 return hr; |
656 } | 652 } |
657 | 653 |
658 hr = CreateOrOpenJob(url); | 654 hr = CreateOrOpenJob(url); |
659 if (FAILED(hr)) | 655 if (FAILED(hr)) |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
759 // must match as a job only contains one file. | 755 // must match as a job only contains one file. |
760 DCHECK(progress.Completed); | 756 DCHECK(progress.Completed); |
761 DCHECK_EQ(progress.BytesTotal, progress.BytesTransferred); | 757 DCHECK_EQ(progress.BytesTotal, progress.BytesTransferred); |
762 | 758 |
763 response_ = base::FilePath(local_name); | 759 response_ = base::FilePath(local_name); |
764 | 760 |
765 return S_OK; | 761 return S_OK; |
766 } | 762 } |
767 | 763 |
768 } // namespace component_updater | 764 } // namespace component_updater |
OLD | NEW |