Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/safe_browsing/srt_fetcher_win.h" | 5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 | 112 |
| 113 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; | 113 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; |
| 114 const char kFoundUwsReadErrorMetricName[] = | 114 const char kFoundUwsReadErrorMetricName[] = |
| 115 "SoftwareReporter.FoundUwSReadError"; | 115 "SoftwareReporter.FoundUwSReadError"; |
| 116 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; | 116 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; |
| 117 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; | 117 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; |
| 118 | 118 |
| 119 // Reports metrics about the software reporter via UMA (and sometimes Rappor). | 119 // Reports metrics about the software reporter via UMA (and sometimes Rappor). |
| 120 class UMAHistogramReporter { | 120 class UMAHistogramReporter { |
| 121 public: | 121 public: |
| 122 explicit UMAHistogramReporter(const std::string& suffix = std::string()) | 122 UMAHistogramReporter() : UMAHistogramReporter(std::string()) {} |
| 123 | |
| 124 explicit UMAHistogramReporter(const std::string& suffix) | |
| 123 : suffix_(suffix), | 125 : suffix_(suffix), |
| 124 registry_key_(suffix.empty() ? kSoftwareRemovalToolRegistryKey | 126 registry_key_(suffix.empty() ? kSoftwareRemovalToolRegistryKey |
| 125 : base::StringPrintf( | 127 : base::StringPrintf( |
| 126 L"%ls\\%ls", | 128 L"%ls\\%ls", |
| 127 kSoftwareRemovalToolRegistryKey, | 129 kSoftwareRemovalToolRegistryKey, |
| 128 base::UTF8ToUTF16(suffix).c_str())) { | 130 base::UTF8ToUTF16(suffix).c_str())) { |
| 129 } | 131 } |
| 130 | 132 |
| 131 // Reports the software reporter tool's version via UMA. | 133 // Reports the software reporter tool's version via UMA. |
| 132 void ReportVersion(const base::Version& version) const { | 134 void ReportVersion(const base::Version& version) const { |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 581 // All the work happens in the self-deleting class below. | 583 // All the work happens in the self-deleting class below. |
| 582 new SRTFetcher(profile); | 584 new SRTFetcher(profile); |
| 583 } | 585 } |
| 584 | 586 |
| 585 // This class tries to run the reporter and reacts to its exit code. It | 587 // This class tries to run the reporter and reacts to its exit code. It |
| 586 // schedules subsequent runs as needed, or retries as soon as a browser is | 588 // schedules subsequent runs as needed, or retries as soon as a browser is |
| 587 // available when none is on first try. | 589 // available when none is on first try. |
| 588 class ReporterRunner : public chrome::BrowserListObserver { | 590 class ReporterRunner : public chrome::BrowserListObserver { |
| 589 public: | 591 public: |
| 590 // Starts the sequence of attempts to run the reporter. | 592 // Starts the sequence of attempts to run the reporter. |
| 591 static void Run(const SwReporterInvocation& invocation, | 593 static void Run(const SwReporterQueue& invocations, |
|
grt (UTC plus 2)
2016/09/01 21:08:55
take as value rather than constref?
Joe Mason
2016/09/02 02:24:30
Done.
| |
| 592 const base::Version& version, | 594 const base::Version& version, |
| 593 scoped_refptr<base::TaskRunner> main_thread_task_runner, | 595 scoped_refptr<base::TaskRunner> main_thread_task_runner, |
| 594 scoped_refptr<base::TaskRunner> blocking_task_runner) { | 596 scoped_refptr<base::TaskRunner> blocking_task_runner) { |
| 595 if (!instance_) | 597 if (!instance_) |
| 596 instance_ = new ReporterRunner; | 598 instance_ = new ReporterRunner; |
| 597 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 599 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 598 // There's nothing to do if the path and version of the reporter has not | 600 // There's nothing to do if the path and version of the reporter has not |
| 599 // changed, we just keep running the tasks that are running now. | 601 // changed, we just keep running the tasks that are running now. |
| 600 if (instance_->invocation_ == invocation && instance_->version_.IsValid() && | 602 if (instance_->invocations_ == invocations && |
| 601 instance_->version_ == version) | 603 instance_->version_.IsValid() && instance_->version_ == version) |
| 602 return; | 604 return; |
| 603 | 605 |
| 604 instance_->invocation_ = invocation; | 606 instance_->invocations_ = invocations; |
|
grt (UTC plus 2)
2016/09/01 21:08:55
std::move here?
Joe Mason
2016/09/02 02:24:30
Done.
| |
| 605 instance_->version_ = version; | 607 instance_->version_ = version; |
| 606 instance_->main_thread_task_runner_ = std::move(main_thread_task_runner); | 608 instance_->main_thread_task_runner_ = std::move(main_thread_task_runner); |
| 607 instance_->blocking_task_runner_ = std::move(blocking_task_runner); | 609 instance_->blocking_task_runner_ = std::move(blocking_task_runner); |
| 608 | 610 |
| 609 if (instance_->first_run_) { | 611 if (instance_->first_run_) { |
| 610 instance_->first_run_ = false; | 612 instance_->first_run_ = false; |
| 611 instance_->TryToRun(); | 613 instance_->TryToRun(); |
| 612 } | 614 } |
| 613 } | 615 } |
| 614 | 616 |
| 615 private: | 617 private: |
| 616 ReporterRunner() {} | 618 ReporterRunner() {} |
| 617 ~ReporterRunner() override {} | 619 ~ReporterRunner() override {} |
| 618 | 620 |
| 619 // BrowserListObserver. | 621 // BrowserListObserver. |
| 620 void OnBrowserSetLastActive(Browser* browser) override {} | 622 void OnBrowserSetLastActive(Browser* browser) override {} |
| 621 void OnBrowserRemoved(Browser* browser) override {} | 623 void OnBrowserRemoved(Browser* browser) override {} |
| 622 void OnBrowserAdded(Browser* browser) override { | 624 void OnBrowserAdded(Browser* browser) override { |
| 623 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 625 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 624 DCHECK(browser); | 626 DCHECK(browser); |
| 625 MaybeFetchSRT(browser, version_); | 627 MaybeFetchSRT(browser, version_); |
| 626 BrowserList::RemoveObserver(this); | 628 BrowserList::RemoveObserver(this); |
| 627 } | 629 } |
| 628 | 630 |
| 631 // Launches the command line at the head of the queue. | |
| 632 void LaunchNextInvocation(std::unique_ptr<SwReporterQueue> invocations) { | |
| 633 DCHECK(invocations); | |
| 634 DCHECK(!invocations->empty()); | |
| 635 auto next_invocation = invocations->front(); | |
| 636 invocations->pop(); | |
| 637 | |
| 638 if (g_testing_delegate_) | |
| 639 g_testing_delegate_->NotifyLaunchReady(); | |
| 640 | |
| 641 // It's OK to simply |PostTaskAndReplyWithResult| so that | |
| 642 // |LaunchAndWaitForExit| doesn't need to access |main_thread_task_runner_| | |
| 643 // since the callback is not delayed and the test task runner won't need to | |
| 644 // force it. | |
| 645 base::PostTaskAndReplyWithResult( | |
| 646 blocking_task_runner_.get(), FROM_HERE, | |
| 647 | |
| 648 // Send the head of the queue to the launch callback. | |
| 649 base::Bind(&LaunchAndWaitForExit, next_invocation), | |
| 650 | |
| 651 // Send the tail of the queue to the next callback, which will handle | |
| 652 // the results of the first launch and then recursively launch | |
| 653 // everything in the tail. | |
| 654 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), | |
| 655 base::Time::Now(), version_, next_invocation, | |
| 656 base::Passed(std::move(invocations)))); | |
| 657 } | |
| 658 | |
| 629 // This method is called on the UI thread when the reporter run has completed. | 659 // This method is called on the UI thread when the reporter run has completed. |
| 630 // This is run as a task posted from an interruptible worker thread so should | 660 // This is run as a task posted from an interruptible worker thread so should |
| 631 // be resilient to unexpected shutdown. | 661 // be resilient to unexpected shutdown. |
| 632 void ReporterDone(const base::Time& reporter_start_time, | 662 void ReporterDone(const base::Time& reporter_start_time, |
| 633 const base::Version& version, | 663 const base::Version& version, |
| 634 const SwReporterInvocation& finished_invocation, | 664 const SwReporterInvocation& finished_invocation, |
| 665 std::unique_ptr<SwReporterQueue> remaining_invocations, | |
| 635 int exit_code) { | 666 int exit_code) { |
| 636 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 667 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 637 | 668 |
| 638 if (g_testing_delegate_) | 669 if (g_testing_delegate_) |
| 639 g_testing_delegate_->NotifyReporterDone(); | 670 g_testing_delegate_->NotifyReporterDone(); |
| 640 | 671 |
| 641 base::TimeDelta reporter_running_time = | 672 base::TimeDelta reporter_running_time = |
| 642 base::Time::Now() - reporter_start_time; | 673 base::Time::Now() - reporter_start_time; |
| 643 // Don't continue when the reporter process failed to launch, but still try | 674 |
| 644 // again after the regular delay. It's not worth retrying earlier, risking | 675 // Don't continue the current queue of reporters if one failed to launch. |
| 645 // running too often if it always fails, since not many users fail here. | 676 // As soon as we're not running this queue, schedule the next overall queue |
| 646 main_thread_task_runner_->PostDelayedTask( | 677 // run after the regular delay. (If there was a failure it's not worth |
| 647 FROM_HERE, | 678 // retrying earlier, risking running too often if it always fails, since |
| 648 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 679 // not many users fail here.) |
| 649 base::TimeDelta::FromDays(days_between_reporter_runs_)); | 680 if (!remaining_invocations->empty() && |
| 681 exit_code != kReporterFailureExitCode) { | |
| 682 LaunchNextInvocation(std::move(remaining_invocations)); | |
| 683 } else { | |
| 684 main_thread_task_runner_->PostDelayedTask( | |
| 685 FROM_HERE, | |
| 686 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | |
| 687 base::TimeDelta::FromDays(days_between_reporter_runs_)); | |
| 688 } | |
| 689 | |
| 690 // If the reporter failed to launch, do not process the results. (The exit | |
| 691 // code itself doesn't need to be logged in this case because | |
| 692 // SW_REPORTER_FAILED_TO_START is logged in |LaunchAndWaitForExit|.) | |
| 650 if (exit_code == kReporterFailureExitCode) | 693 if (exit_code == kReporterFailureExitCode) |
| 651 return; | 694 return; |
| 652 | 695 |
| 653 UMAHistogramReporter uma(finished_invocation.suffix); | 696 UMAHistogramReporter uma(finished_invocation.suffix); |
| 654 uma.ReportVersion(version); | 697 uma.ReportVersion(version); |
| 655 uma.ReportExitCode(exit_code); | 698 uma.ReportExitCode(exit_code); |
| 656 uma.ReportFoundUwS(!finished_invocation.is_experimental /*use_rappor*/); | 699 uma.ReportFoundUwS(finished_invocation.flags & |
| 700 SwReporterInvocation::FLAG_LOG_TO_RAPPOR); | |
| 657 | 701 |
| 658 // Only save results from the canonical version of the software. | 702 // Only save results from the canonical version of the software. |
| 659 PrefService* local_state = g_browser_process->local_state(); | 703 PrefService* local_state = g_browser_process->local_state(); |
| 660 if (local_state && !finished_invocation.is_experimental) { | 704 if (local_state && |
| 705 (finished_invocation.flags & SwReporterInvocation::FLAG_LOG_TO_PREFS)) { | |
| 661 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); | 706 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); |
| 662 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, | 707 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, |
| 663 base::Time::Now().ToInternalValue()); | 708 base::Time::Now().ToInternalValue()); |
| 664 } | 709 } |
| 665 uma.ReportRuntime(reporter_running_time); | 710 uma.ReportRuntime(reporter_running_time); |
| 666 uma.ReportScanTimes(); | 711 uma.ReportScanTimes(); |
| 667 uma.ReportMemoryUsage(); | 712 uma.ReportMemoryUsage(); |
| 668 | 713 |
| 669 // Only continue to launch the prompt for the canonical version. | 714 if (!(finished_invocation.flags & |
| 670 if (finished_invocation.is_experimental) | 715 SwReporterInvocation::FLAG_TRIGGER_PROMPT)) |
| 671 return; | 716 return; |
| 672 | 717 |
| 673 if (!IsInSRTPromptFieldTrialGroups()) { | 718 if (!IsInSRTPromptFieldTrialGroups()) { |
| 674 // Knowing about disabled field trial is more important than reporter not | 719 // Knowing about disabled field trial is more important than reporter not |
| 675 // finding anything to remove, so check this case first. | 720 // finding anything to remove, so check this case first. |
| 676 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); | 721 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); |
| 677 return; | 722 return; |
| 678 } | 723 } |
| 679 | 724 |
| 680 if (exit_code != kSwReporterPostRebootCleanupNeeded && | 725 if (exit_code != kSwReporterPostRebootCleanupNeeded && |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 714 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); | 759 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); |
| 715 } else { | 760 } else { |
| 716 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 761 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
| 717 } | 762 } |
| 718 const base::Time last_time_triggered = base::Time::FromInternalValue( | 763 const base::Time last_time_triggered = base::Time::FromInternalValue( |
| 719 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); | 764 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); |
| 720 base::TimeDelta next_trigger_delay( | 765 base::TimeDelta next_trigger_delay( |
| 721 last_time_triggered + | 766 last_time_triggered + |
| 722 base::TimeDelta::FromDays(days_between_reporter_runs_) - | 767 base::TimeDelta::FromDays(days_between_reporter_runs_) - |
| 723 base::Time::Now()); | 768 base::Time::Now()); |
| 724 if (next_trigger_delay.ToInternalValue() <= 0 || | 769 if (!invocations_.empty() && |
| 725 // Also make sure the kSwReporterLastTimeTriggered value is not set in | 770 (next_trigger_delay.ToInternalValue() <= 0 || |
| 726 // the future. | 771 // Also make sure the kSwReporterLastTimeTriggered value is not set in |
| 727 last_time_triggered > base::Time::Now()) { | 772 // the future. |
| 728 if (g_testing_delegate_) | 773 last_time_triggered > base::Time::Now())) { |
| 729 g_testing_delegate_->NotifyLaunchReady(); | 774 // Make a copy of the queue, since LaunchNextInvocation will pop items |
| 730 | 775 // from it. We need to save the full original for the comparison in |
| 731 // It's OK to simply |PostTaskAndReplyWithResult| so that | 776 // Run. |
| 732 // |LaunchAndWaitForExit| doesn't need to access | 777 auto invocations = std::make_unique<SwReporterQueue>(invocations_); |
| 733 // |main_thread_task_runner_| since the callback is not delayed and the | 778 LaunchNextInvocation(std::move(invocations)); |
| 734 // test task runner won't need to force it. | |
| 735 base::PostTaskAndReplyWithResult( | |
| 736 blocking_task_runner_.get(), FROM_HERE, | |
| 737 base::Bind(&LaunchAndWaitForExit, invocation_), | |
| 738 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), | |
| 739 base::Time::Now(), version_, invocation_)); | |
| 740 } else { | 779 } else { |
| 741 main_thread_task_runner_->PostDelayedTask( | 780 main_thread_task_runner_->PostDelayedTask( |
| 742 FROM_HERE, | 781 FROM_HERE, |
| 743 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 782 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
| 744 next_trigger_delay); | 783 next_trigger_delay); |
| 745 } | 784 } |
| 746 } | 785 } |
| 747 | 786 |
| 748 bool first_run_ = true; | 787 bool first_run_ = true; |
| 749 SwReporterInvocation invocation_; | 788 SwReporterQueue invocations_; |
| 750 base::Version version_; | 789 base::Version version_; |
| 751 scoped_refptr<base::TaskRunner> main_thread_task_runner_; | 790 scoped_refptr<base::TaskRunner> main_thread_task_runner_; |
| 752 scoped_refptr<base::TaskRunner> blocking_task_runner_; | 791 scoped_refptr<base::TaskRunner> blocking_task_runner_; |
| 753 | 792 |
| 754 // This value is used to identify how long to wait before starting a new run | 793 // This value is used to identify how long to wait before starting a new run |
| 755 // of the reporter. It's initialized with the default value and may be changed | 794 // of the reporter. It's initialized with the default value and may be changed |
| 756 // to a different value when a prompt is pending and the reporter should be | 795 // to a different value when a prompt is pending and the reporter should be |
| 757 // run before adding the global error to the Chrome menu. | 796 // run before adding the global error to the Chrome menu. |
| 758 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 797 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
| 759 | 798 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 779 | 818 |
| 780 SwReporterInvocation SwReporterInvocation::FromCommandLine( | 819 SwReporterInvocation SwReporterInvocation::FromCommandLine( |
| 781 const base::CommandLine& command_line) { | 820 const base::CommandLine& command_line) { |
| 782 SwReporterInvocation invocation; | 821 SwReporterInvocation invocation; |
| 783 invocation.command_line = command_line; | 822 invocation.command_line = command_line; |
| 784 return invocation; | 823 return invocation; |
| 785 } | 824 } |
| 786 | 825 |
| 787 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { | 826 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { |
| 788 return command_line.argv() == other.command_line.argv() && | 827 return command_line.argv() == other.command_line.argv() && |
| 789 suffix == other.suffix && is_experimental == other.is_experimental; | 828 suffix == other.suffix && flags == other.flags; |
| 790 } | 829 } |
| 791 | 830 |
| 792 void RunSwReporter(const SwReporterInvocation& invocation, | 831 void RunSwReporters(const SwReporterQueue& invocations, |
| 793 const base::Version& version, | 832 const base::Version& version, |
| 794 scoped_refptr<base::TaskRunner> main_thread_task_runner, | 833 scoped_refptr<base::TaskRunner> main_thread_task_runner, |
| 795 scoped_refptr<base::TaskRunner> blocking_task_runner) { | 834 scoped_refptr<base::TaskRunner> blocking_task_runner) { |
| 796 ReporterRunner::Run(invocation, version, std::move(main_thread_task_runner), | 835 ReporterRunner::Run(invocations, version, std::move(main_thread_task_runner), |
| 797 std::move(blocking_task_runner)); | 836 std::move(blocking_task_runner)); |
| 798 } | 837 } |
| 799 | 838 |
| 800 bool ReporterFoundUws() { | 839 bool ReporterFoundUws() { |
| 801 PrefService* local_state = g_browser_process->local_state(); | 840 PrefService* local_state = g_browser_process->local_state(); |
| 802 if (!local_state) | 841 if (!local_state) |
| 803 return false; | 842 return false; |
| 804 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); | 843 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); |
| 805 return exit_code == kSwReporterCleanupNeeded; | 844 return exit_code == kSwReporterCleanupNeeded; |
| 806 } | 845 } |
| 807 | 846 |
| 808 bool UserHasRunCleaner() { | 847 bool UserHasRunCleaner() { |
| 809 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); | 848 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); |
| 810 cleaner_key_path.append(L"\\").append(kCleanerSubKey); | 849 cleaner_key_path.append(L"\\").append(kCleanerSubKey); |
| 811 | 850 |
| 812 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), | 851 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), |
| 813 KEY_QUERY_VALUE); | 852 KEY_QUERY_VALUE); |
| 814 | 853 |
| 815 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; | 854 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; |
| 816 } | 855 } |
| 817 | 856 |
| 818 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { | 857 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { |
| 819 g_testing_delegate_ = delegate; | 858 g_testing_delegate_ = delegate; |
| 820 } | 859 } |
| 821 | 860 |
| 822 } // namespace safe_browsing | 861 } // namespace safe_browsing |
| OLD | NEW |