OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/component_updater/background_downloader_win.h" | 5 #include "components/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 <stdint.h> | 10 #include <stdint.h> |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 if (FAILED(hr)) | 147 if (FAILED(hr)) |
148 return hr; | 148 return hr; |
149 | 149 |
150 ULONG num_files = 0; | 150 ULONG num_files = 0; |
151 hr = enum_files->GetCount(&num_files); | 151 hr = enum_files->GetCount(&num_files); |
152 if (FAILED(hr)) | 152 if (FAILED(hr)) |
153 return hr; | 153 return hr; |
154 | 154 |
155 for (ULONG i = 0; i != num_files; ++i) { | 155 for (ULONG i = 0; i != num_files; ++i) { |
156 ScopedComPtr<IBackgroundCopyFile> file; | 156 ScopedComPtr<IBackgroundCopyFile> file; |
157 if (enum_files->Next(1, file.Receive(), NULL) == S_OK && file) | 157 if (enum_files->Next(1, file.Receive(), NULL) == S_OK && file.get()) |
158 files->push_back(file); | 158 files->push_back(file); |
159 } | 159 } |
160 | 160 |
161 return S_OK; | 161 return S_OK; |
162 } | 162 } |
163 | 163 |
164 // Returns the file name, the url, and some per-file progress information. | 164 // Returns the file name, the url, and some per-file progress information. |
165 // The function out parameters can be NULL if that data is not requested. | 165 // The function out parameters can be NULL if that data is not requested. |
166 HRESULT GetJobFileProperties(IBackgroundCopyFile* file, | 166 HRESULT GetJobFileProperties(IBackgroundCopyFile* file, |
167 base::string16* local_name, | 167 base::string16* local_name, |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 ULONG job_count = 0; | 268 ULONG job_count = 0; |
269 hr = enum_jobs->GetCount(&job_count); | 269 hr = enum_jobs->GetCount(&job_count); |
270 if (FAILED(hr)) | 270 if (FAILED(hr)) |
271 return hr; | 271 return hr; |
272 | 272 |
273 // Iterate over jobs, run the predicate, and select the job only if | 273 // Iterate over jobs, run the predicate, and select the job only if |
274 // the job description matches the component updater jobs. | 274 // the job description matches the component updater jobs. |
275 for (ULONG i = 0; i != job_count; ++i) { | 275 for (ULONG i = 0; i != job_count; ++i) { |
276 ScopedComPtr<IBackgroundCopyJob> current_job; | 276 ScopedComPtr<IBackgroundCopyJob> current_job; |
277 if (enum_jobs->Next(1, current_job.Receive(), NULL) == S_OK && | 277 if (enum_jobs->Next(1, current_job.Receive(), NULL) == S_OK && |
278 pred(current_job)) { | 278 pred(current_job.get())) { |
279 base::string16 job_description; | 279 base::string16 job_description; |
280 hr = GetJobDescription(current_job, &job_description); | 280 hr = GetJobDescription(current_job.get(), &job_description); |
281 if (job_description.compare(kJobDescription) == 0) | 281 if (job_description.compare(kJobDescription) == 0) |
282 jobs->push_back(current_job); | 282 jobs->push_back(current_job); |
283 } | 283 } |
284 } | 284 } |
285 | 285 |
286 return jobs->empty() ? S_FALSE : S_OK; | 286 return jobs->empty() ? S_FALSE : S_OK; |
287 } | 287 } |
288 | 288 |
289 // Compares the job creation time and returns true if the job creation time | 289 // Compares the job creation time and returns true if the job creation time |
290 // is older than |num_days|. | 290 // is older than |num_days|. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 *bits_manager = object.Detach(); | 342 *bits_manager = object.Detach(); |
343 return S_OK; | 343 return S_OK; |
344 } | 344 } |
345 | 345 |
346 void CleanupJobFiles(IBackgroundCopyJob* job) { | 346 void CleanupJobFiles(IBackgroundCopyJob* job) { |
347 std::vector<ScopedComPtr<IBackgroundCopyFile> > files; | 347 std::vector<ScopedComPtr<IBackgroundCopyFile> > files; |
348 if (FAILED(GetFilesInJob(job, &files))) | 348 if (FAILED(GetFilesInJob(job, &files))) |
349 return; | 349 return; |
350 for (size_t i = 0; i != files.size(); ++i) { | 350 for (size_t i = 0; i != files.size(); ++i) { |
351 base::string16 local_name; | 351 base::string16 local_name; |
352 HRESULT hr(GetJobFileProperties(files[i], &local_name, NULL, NULL)); | 352 HRESULT hr(GetJobFileProperties(files[i].get(), &local_name, NULL, NULL)); |
353 if (SUCCEEDED(hr)) | 353 if (SUCCEEDED(hr)) |
354 DeleteFileAndEmptyParentDirectory(base::FilePath(local_name)); | 354 DeleteFileAndEmptyParentDirectory(base::FilePath(local_name)); |
355 } | 355 } |
356 } | 356 } |
357 | 357 |
358 // Cleans up incompleted jobs that are too old. | 358 // Cleans up incompleted jobs that are too old. |
359 HRESULT CleanupStaleJobs( | 359 HRESULT CleanupStaleJobs( |
360 base::win::ScopedComPtr<IBackgroundCopyManager> bits_manager) { | 360 base::win::ScopedComPtr<IBackgroundCopyManager> bits_manager) { |
361 if (!bits_manager) | 361 if (!bits_manager.get()) |
362 return E_FAIL; | 362 return E_FAIL; |
363 | 363 |
364 static base::Time last_sweep; | 364 static base::Time last_sweep; |
365 | 365 |
366 const base::TimeDelta time_delta( | 366 const base::TimeDelta time_delta( |
367 base::TimeDelta::FromDays(kPurgeStaleJobsIntervalBetweenChecksDays)); | 367 base::TimeDelta::FromDays(kPurgeStaleJobsIntervalBetweenChecksDays)); |
368 const base::Time current_time(base::Time::Now()); | 368 const base::Time current_time(base::Time::Now()); |
369 if (last_sweep + time_delta > current_time) | 369 if (last_sweep + time_delta > current_time) |
370 return S_OK; | 370 return S_OK; |
371 | 371 |
372 last_sweep = current_time; | 372 last_sweep = current_time; |
373 | 373 |
374 std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs; | 374 std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs; |
375 HRESULT hr = FindBitsJobIf( | 375 HRESULT hr = FindBitsJobIf( |
376 std::bind2nd(JobCreationOlderThanDays(), kPurgeStaleJobsAfterDays), | 376 std::bind2nd(JobCreationOlderThanDays(), kPurgeStaleJobsAfterDays), |
377 bits_manager, | 377 bits_manager.get(), &jobs); |
378 &jobs); | |
379 if (FAILED(hr)) | 378 if (FAILED(hr)) |
380 return hr; | 379 return hr; |
381 | 380 |
382 for (size_t i = 0; i != jobs.size(); ++i) { | 381 for (size_t i = 0; i != jobs.size(); ++i) { |
383 jobs[i]->Cancel(); | 382 jobs[i]->Cancel(); |
384 CleanupJobFiles(jobs[i]); | 383 CleanupJobFiles(jobs[i].get()); |
385 } | 384 } |
386 | 385 |
387 return S_OK; | 386 return S_OK; |
388 } | 387 } |
389 | 388 |
390 } // namespace | 389 } // namespace |
391 | 390 |
392 BackgroundDownloader::BackgroundDownloader( | 391 BackgroundDownloader::BackgroundDownloader( |
393 scoped_ptr<CrxDownloader> successor, | 392 scoped_ptr<CrxDownloader> successor, |
394 net::URLRequestContextGetter* context_getter, | 393 net::URLRequestContextGetter* context_getter, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 timer_->Start(FROM_HERE, | 447 timer_->Start(FROM_HERE, |
449 base::TimeDelta::FromSeconds(kJobPollingIntervalSec), | 448 base::TimeDelta::FromSeconds(kJobPollingIntervalSec), |
450 this, | 449 this, |
451 &BackgroundDownloader::OnDownloading); | 450 &BackgroundDownloader::OnDownloading); |
452 } | 451 } |
453 | 452 |
454 // Called any time the timer fires. | 453 // Called any time the timer fires. |
455 void BackgroundDownloader::OnDownloading() { | 454 void BackgroundDownloader::OnDownloading() { |
456 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 455 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
457 | 456 |
458 DCHECK(job_); | 457 DCHECK(job_.get()); |
459 | 458 |
460 DCHECK(!is_completed_); | 459 DCHECK(!is_completed_); |
461 if (is_completed_) | 460 if (is_completed_) |
462 return; | 461 return; |
463 | 462 |
464 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR; | 463 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR; |
465 HRESULT hr = job_->GetState(&job_state); | 464 HRESULT hr = job_->GetState(&job_state); |
466 if (FAILED(hr)) { | 465 if (FAILED(hr)) { |
467 EndDownload(hr); | 466 EndDownload(hr); |
468 return; | 467 return; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 timer_.reset(); | 516 timer_.reset(); |
518 | 517 |
519 const base::Time download_end_time(base::Time::Now()); | 518 const base::Time download_end_time(base::Time::Now()); |
520 const base::TimeDelta download_time = | 519 const base::TimeDelta download_time = |
521 download_end_time >= download_start_time_ | 520 download_end_time >= download_start_time_ |
522 ? download_end_time - download_start_time_ | 521 ? download_end_time - download_start_time_ |
523 : base::TimeDelta(); | 522 : base::TimeDelta(); |
524 | 523 |
525 int64_t downloaded_bytes = -1; | 524 int64_t downloaded_bytes = -1; |
526 int64_t total_bytes = -1; | 525 int64_t total_bytes = -1; |
527 GetJobByteCount(job_, &downloaded_bytes, &total_bytes); | 526 GetJobByteCount(job_.get(), &downloaded_bytes, &total_bytes); |
528 | 527 |
529 if (FAILED(error) && job_) { | 528 if (FAILED(error) && job_.get()) { |
530 job_->Cancel(); | 529 job_->Cancel(); |
531 CleanupJobFiles(job_); | 530 CleanupJobFiles(job_.get()); |
532 } | 531 } |
533 | 532 |
534 job_ = NULL; | 533 job_ = NULL; |
535 | 534 |
536 CleanupStaleJobs(bits_manager_); | 535 CleanupStaleJobs(bits_manager_); |
537 bits_manager_ = NULL; | 536 bits_manager_ = NULL; |
538 | 537 |
539 // Consider the url handled if it has been successfully downloaded or a | 538 // Consider the url handled if it has been successfully downloaded or a |
540 // 5xx has been received. | 539 // 5xx has been received. |
541 const bool is_handled = | 540 const bool is_handled = |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 // BITS job by removing it from the BITS queue and making the download | 573 // BITS job by removing it from the BITS queue and making the download |
575 // available to the caller. | 574 // available to the caller. |
576 void BackgroundDownloader::OnStateTransferred() { | 575 void BackgroundDownloader::OnStateTransferred() { |
577 EndDownload(CompleteJob()); | 576 EndDownload(CompleteJob()); |
578 } | 577 } |
579 | 578 |
580 // Called when the job has encountered an error and no further progress can | 579 // Called when the job has encountered an error and no further progress can |
581 // be made. Cancels this job and removes it from the BITS queue. | 580 // be made. Cancels this job and removes it from the BITS queue. |
582 void BackgroundDownloader::OnStateError() { | 581 void BackgroundDownloader::OnStateError() { |
583 HRESULT error_code = S_OK; | 582 HRESULT error_code = S_OK; |
584 HRESULT hr = GetJobError(job_, &error_code); | 583 HRESULT hr = GetJobError(job_.get(), &error_code); |
585 if (FAILED(hr)) | 584 if (FAILED(hr)) |
586 error_code = hr; | 585 error_code = hr; |
587 DCHECK(FAILED(error_code)); | 586 DCHECK(FAILED(error_code)); |
588 EndDownload(error_code); | 587 EndDownload(error_code); |
589 } | 588 } |
590 | 589 |
591 // Called when the job has encountered a transient error, such as a | 590 // Called when the job has encountered a transient error, such as a |
592 // network disconnect, a server error, or some other recoverable error. | 591 // network disconnect, a server error, or some other recoverable error. |
593 void BackgroundDownloader::OnStateTransientError() { | 592 void BackgroundDownloader::OnStateTransientError() { |
594 // If the job appears to be stuck, handle the transient error as if | 593 // If the job appears to be stuck, handle the transient error as if |
595 // it were a final error. This causes the job to be cancelled and a specific | 594 // it were a final error. This causes the job to be cancelled and a specific |
596 // error be returned, if the error was available. | 595 // error be returned, if the error was available. |
597 if (IsStuck()) { | 596 if (IsStuck()) { |
598 OnStateError(); | 597 OnStateError(); |
599 return; | 598 return; |
600 } | 599 } |
601 | 600 |
602 // Don't retry at all if the transient error was a 5xx. | 601 // Don't retry at all if the transient error was a 5xx. |
603 HRESULT error_code = S_OK; | 602 HRESULT error_code = S_OK; |
604 HRESULT hr = GetJobError(job_, &error_code); | 603 HRESULT hr = GetJobError(job_.get(), &error_code); |
605 if (SUCCEEDED(hr) && | 604 if (SUCCEEDED(hr) && |
606 IsHttpServerError(GetHttpStatusFromBitsError(error_code))) { | 605 IsHttpServerError(GetHttpStatusFromBitsError(error_code))) { |
607 OnStateError(); | 606 OnStateError(); |
608 return; | 607 return; |
609 } | 608 } |
610 } | 609 } |
611 | 610 |
612 void BackgroundDownloader::OnStateQueued() { | 611 void BackgroundDownloader::OnStateQueued() { |
613 if (IsStuck()) | 612 if (IsStuck()) |
614 EndDownload(E_ABORT); // Return a generic error for now. | 613 EndDownload(E_ABORT); // Return a generic error for now. |
615 } | 614 } |
616 | 615 |
617 void BackgroundDownloader::OnStateTransferring() { | 616 void BackgroundDownloader::OnStateTransferring() { |
618 // Resets the baseline for detecting a stuck job since the job is transferring | 617 // Resets the baseline for detecting a stuck job since the job is transferring |
619 // data and it is making progress. | 618 // data and it is making progress. |
620 job_stuck_begin_time_ = base::Time::Now(); | 619 job_stuck_begin_time_ = base::Time::Now(); |
621 | 620 |
622 int64_t downloaded_bytes = -1; | 621 int64_t downloaded_bytes = -1; |
623 int64_t total_bytes = -1; | 622 int64_t total_bytes = -1; |
624 HRESULT hr = GetJobByteCount(job_, &downloaded_bytes, &total_bytes); | 623 HRESULT hr = GetJobByteCount(job_.get(), &downloaded_bytes, &total_bytes); |
625 if (FAILED(hr)) | 624 if (FAILED(hr)) |
626 return; | 625 return; |
627 | 626 |
628 Result result; | 627 Result result; |
629 result.downloaded_bytes = downloaded_bytes; | 628 result.downloaded_bytes = downloaded_bytes; |
630 result.total_bytes = total_bytes; | 629 result.total_bytes = total_bytes; |
631 | 630 |
632 main_task_runner_->PostTask( | 631 main_task_runner_->PostTask( |
633 FROM_HERE, | 632 FROM_HERE, |
634 base::Bind(&BackgroundDownloader::OnDownloadProgress, | 633 base::Bind(&BackgroundDownloader::OnDownloadProgress, |
(...skipping 11 matching lines...) Expand all Loading... |
646 void BackgroundDownloader::OnStateAcknowledged() { | 645 void BackgroundDownloader::OnStateAcknowledged() { |
647 EndDownload(E_UNEXPECTED); | 646 EndDownload(E_UNEXPECTED); |
648 } | 647 } |
649 | 648 |
650 // Creates or opens a job for the given url and queues it up. Tries to | 649 // Creates or opens a job for the given url and queues it up. Tries to |
651 // install a job observer but continues on if an observer can't be set up. | 650 // install a job observer but continues on if an observer can't be set up. |
652 HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url) { | 651 HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url) { |
653 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 652 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
654 | 653 |
655 HRESULT hr = S_OK; | 654 HRESULT hr = S_OK; |
656 if (bits_manager_ == NULL) { | 655 if (bits_manager_.get() == NULL) { |
657 hr = GetBitsManager(bits_manager_.Receive()); | 656 hr = GetBitsManager(bits_manager_.Receive()); |
658 if (FAILED(hr)) | 657 if (FAILED(hr)) |
659 return hr; | 658 return hr; |
660 } | 659 } |
661 | 660 |
662 hr = CreateOrOpenJob(url); | 661 hr = CreateOrOpenJob(url); |
663 if (FAILED(hr)) | 662 if (FAILED(hr)) |
664 return hr; | 663 return hr; |
665 | 664 |
666 if (hr == S_OK) { | 665 if (hr == S_OK) { |
667 hr = InitializeNewJob(url); | 666 hr = InitializeNewJob(url); |
668 if (FAILED(hr)) | 667 if (FAILED(hr)) |
669 return hr; | 668 return hr; |
670 } | 669 } |
671 | 670 |
672 return job_->Resume(); | 671 return job_->Resume(); |
673 } | 672 } |
674 | 673 |
675 HRESULT BackgroundDownloader::CreateOrOpenJob(const GURL& url) { | 674 HRESULT BackgroundDownloader::CreateOrOpenJob(const GURL& url) { |
676 std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs; | 675 std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs; |
677 HRESULT hr = FindBitsJobIf( | 676 HRESULT hr = FindBitsJobIf( |
678 std::bind2nd(JobFileUrlEqual(), base::SysUTF8ToWide(url.spec())), | 677 std::bind2nd(JobFileUrlEqual(), base::SysUTF8ToWide(url.spec())), |
679 bits_manager_, | 678 bits_manager_.get(), &jobs); |
680 &jobs); | |
681 if (SUCCEEDED(hr) && !jobs.empty()) { | 679 if (SUCCEEDED(hr) && !jobs.empty()) { |
682 job_ = jobs.front(); | 680 job_ = jobs.front(); |
683 return S_FALSE; | 681 return S_FALSE; |
684 } | 682 } |
685 | 683 |
686 // Use kJobDescription as a temporary job display name until the proper | 684 // Use kJobDescription as a temporary job display name until the proper |
687 // display name is initialized later on. | 685 // display name is initialized later on. |
688 GUID guid = {0}; | 686 GUID guid = {0}; |
689 ScopedComPtr<IBackgroundCopyJob> job; | 687 ScopedComPtr<IBackgroundCopyJob> job; |
690 hr = bits_manager_->CreateJob( | 688 hr = bits_manager_->CreateJob( |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 base::TimeDelta::FromMinutes(kJobStuckTimeoutMin)); | 736 base::TimeDelta::FromMinutes(kJobStuckTimeoutMin)); |
739 return job_stuck_begin_time_ + job_stuck_timeout < base::Time::Now(); | 737 return job_stuck_begin_time_ + job_stuck_timeout < base::Time::Now(); |
740 } | 738 } |
741 | 739 |
742 HRESULT BackgroundDownloader::CompleteJob() { | 740 HRESULT BackgroundDownloader::CompleteJob() { |
743 HRESULT hr = job_->Complete(); | 741 HRESULT hr = job_->Complete(); |
744 if (FAILED(hr) && hr != BG_S_UNABLE_TO_DELETE_FILES) | 742 if (FAILED(hr) && hr != BG_S_UNABLE_TO_DELETE_FILES) |
745 return hr; | 743 return hr; |
746 | 744 |
747 std::vector<ScopedComPtr<IBackgroundCopyFile> > files; | 745 std::vector<ScopedComPtr<IBackgroundCopyFile> > files; |
748 hr = GetFilesInJob(job_, &files); | 746 hr = GetFilesInJob(job_.get(), &files); |
749 if (FAILED(hr)) | 747 if (FAILED(hr)) |
750 return hr; | 748 return hr; |
751 | 749 |
752 if (files.empty()) | 750 if (files.empty()) |
753 return E_UNEXPECTED; | 751 return E_UNEXPECTED; |
754 | 752 |
755 base::string16 local_name; | 753 base::string16 local_name; |
756 BG_FILE_PROGRESS progress = {0}; | 754 BG_FILE_PROGRESS progress = {0}; |
757 hr = GetJobFileProperties(files.front(), &local_name, NULL, &progress); | 755 hr = GetJobFileProperties(files.front().get(), &local_name, NULL, &progress); |
758 if (FAILED(hr)) | 756 if (FAILED(hr)) |
759 return hr; | 757 return hr; |
760 | 758 |
761 // Sanity check the post-conditions of a successful download, including | 759 // Sanity check the post-conditions of a successful download, including |
762 // the file and job invariants. The byte counts for a job and its file | 760 // the file and job invariants. The byte counts for a job and its file |
763 // must match as a job only contains one file. | 761 // must match as a job only contains one file. |
764 DCHECK(progress.Completed); | 762 DCHECK(progress.Completed); |
765 DCHECK_EQ(progress.BytesTotal, progress.BytesTransferred); | 763 DCHECK_EQ(progress.BytesTotal, progress.BytesTransferred); |
766 | 764 |
767 response_ = base::FilePath(local_name); | 765 response_ = base::FilePath(local_name); |
768 | 766 |
769 return S_OK; | 767 return S_OK; |
770 } | 768 } |
771 | 769 |
772 } // namespace component_updater | 770 } // namespace component_updater |
OLD | NEW |