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 |