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 <algorithm> | 9 #include <algorithm> |
10 #include <memory> | 10 #include <memory> |
11 #include <utility> | 11 #include <utility> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/bind.h" | 14 #include "base/bind.h" |
15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
16 #include "base/callback_helpers.h" | 16 #include "base/callback_helpers.h" |
17 #include "base/command_line.h" | 17 #include "base/command_line.h" |
| 18 #include "base/debug/leak_annotations.h" |
18 #include "base/files/file_path.h" | 19 #include "base/files/file_path.h" |
19 #include "base/macros.h" | 20 #include "base/macros.h" |
20 #include "base/metrics/field_trial.h" | 21 #include "base/metrics/field_trial.h" |
21 #include "base/metrics/histogram_macros.h" | 22 #include "base/metrics/histogram_macros.h" |
22 #include "base/metrics/sparse_histogram.h" | 23 #include "base/metrics/sparse_histogram.h" |
23 #include "base/process/launch.h" | 24 #include "base/process/launch.h" |
24 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
25 #include "base/strings/stringprintf.h" | 26 #include "base/strings/stringprintf.h" |
26 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
27 #include "base/task_runner_util.h" | 28 #include "base/task_runner_util.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 | 123 |
123 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; | 124 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; |
124 const char kFoundUwsReadErrorMetricName[] = | 125 const char kFoundUwsReadErrorMetricName[] = |
125 "SoftwareReporter.FoundUwSReadError"; | 126 "SoftwareReporter.FoundUwSReadError"; |
126 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; | 127 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; |
127 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; | 128 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; |
128 | 129 |
129 // Reports metrics about the software reporter via UMA (and sometimes Rappor). | 130 // Reports metrics about the software reporter via UMA (and sometimes Rappor). |
130 class UMAHistogramReporter { | 131 class UMAHistogramReporter { |
131 public: | 132 public: |
132 explicit UMAHistogramReporter(const std::string& suffix = std::string()) | 133 UMAHistogramReporter() : UMAHistogramReporter(std::string()) {} |
| 134 |
| 135 explicit UMAHistogramReporter(const std::string& suffix) |
133 : suffix_(suffix), | 136 : suffix_(suffix), |
134 registry_key_(suffix.empty() ? kSoftwareRemovalToolRegistryKey | 137 registry_key_(suffix.empty() ? kSoftwareRemovalToolRegistryKey |
135 : base::StringPrintf( | 138 : base::StringPrintf( |
136 L"%ls\\%ls", | 139 L"%ls\\%ls", |
137 kSoftwareRemovalToolRegistryKey, | 140 kSoftwareRemovalToolRegistryKey, |
138 base::UTF8ToUTF16(suffix).c_str())) { | 141 base::UTF8ToUTF16(suffix).c_str())) { |
139 } | 142 } |
140 | 143 |
141 // Reports the software reporter tool's version via UMA. | 144 // Reports the software reporter tool's version via UMA. |
142 void ReportVersion(const base::Version& version) const { | 145 void ReportVersion(const base::Version& version) const { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 reporter_key.DeleteValue(kMemoryUsedValueName); | 221 reporter_key.DeleteValue(kMemoryUsedValueName); |
219 } | 222 } |
220 } | 223 } |
221 | 224 |
222 // Reports the SwReporter run time with UMA both as reported by the tool via | 225 // Reports the SwReporter run time with UMA both as reported by the tool via |
223 // the registry and as measured by |ReporterRunner|. | 226 // the registry and as measured by |ReporterRunner|. |
224 void ReportRuntime(const base::TimeDelta& reporter_running_time) const { | 227 void ReportRuntime(const base::TimeDelta& reporter_running_time) const { |
225 RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome", | 228 RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome", |
226 reporter_running_time); | 229 reporter_running_time); |
227 | 230 |
| 231 // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE, |
| 232 // and use Open to avoid creating the key if it doesn't already exist. |
228 base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(), | 233 base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(), |
229 KEY_ALL_ACCESS); | 234 KEY_ALL_ACCESS); |
230 if (!reporter_key.Valid()) { | 235 if (!reporter_key.Valid()) { |
231 RecordEnumerationHistogram( | 236 RecordEnumerationHistogram( |
232 kRunningTimeErrorMetricName, | 237 kRunningTimeErrorMetricName, |
233 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID, | 238 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID, |
234 REPORTER_RUNNING_TIME_ERROR_MAX); | 239 REPORTER_RUNNING_TIME_ERROR_MAX); |
235 return; | 240 return; |
236 } | 241 } |
237 | 242 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 RecordEnumerationHistogram(kRunningTimeErrorMetricName, | 280 RecordEnumerationHistogram(kRunningTimeErrorMetricName, |
276 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME, | 281 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME, |
277 REPORTER_RUNNING_TIME_ERROR_MAX); | 282 REPORTER_RUNNING_TIME_ERROR_MAX); |
278 } | 283 } |
279 } | 284 } |
280 | 285 |
281 // Reports the UwS scan times of the software reporter tool via UMA. | 286 // Reports the UwS scan times of the software reporter tool via UMA. |
282 void ReportScanTimes() const { | 287 void ReportScanTimes() const { |
283 base::string16 scan_times_key_path = base::StringPrintf( | 288 base::string16 scan_times_key_path = base::StringPrintf( |
284 L"%ls\\%ls", registry_key_.c_str(), kScanTimesSubKey); | 289 L"%ls\\%ls", registry_key_.c_str(), kScanTimesSubKey); |
| 290 // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE, |
| 291 // and use Open to avoid creating the key if it doesn't already exist. |
285 base::win::RegKey scan_times_key( | 292 base::win::RegKey scan_times_key( |
286 HKEY_CURRENT_USER, scan_times_key_path.c_str(), KEY_ALL_ACCESS); | 293 HKEY_CURRENT_USER, scan_times_key_path.c_str(), KEY_ALL_ACCESS); |
287 if (!scan_times_key.Valid()) | 294 if (!scan_times_key.Valid()) |
288 return; | 295 return; |
289 | 296 |
290 base::string16 value_name; | 297 base::string16 value_name; |
291 int uws_id = 0; | 298 int uws_id = 0; |
292 int64_t raw_scan_time = 0; | 299 int64_t raw_scan_time = 0; |
293 int num_scan_times = scan_times_key.GetValueCount(); | 300 int num_scan_times = scan_times_key.GetValueCount(); |
294 for (int i = 0; i < num_scan_times; ++i) { | 301 for (int i = 0; i < num_scan_times; ++i) { |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 prefs->SetString(prefs::kSwReporterPromptVersion, | 608 prefs->SetString(prefs::kSwReporterPromptVersion, |
602 reporter_version.GetString()); | 609 reporter_version.GetString()); |
603 | 610 |
604 // Download the SRT. | 611 // Download the SRT. |
605 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); | 612 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); |
606 | 613 |
607 // All the work happens in the self-deleting class below. | 614 // All the work happens in the self-deleting class below. |
608 new SRTFetcher(profile); | 615 new SRTFetcher(profile); |
609 } | 616 } |
610 | 617 |
611 // This class tries to run the reporter and reacts to its exit code. It | 618 // This class tries to run a queue of reporters and react to their exit codes. |
612 // schedules subsequent runs as needed, or retries as soon as a browser is | 619 // It schedules subsequent runs of the queue as needed, or retries as soon as a |
613 // available when none is on first try. | 620 // browser is available when none is on first try. |
614 class ReporterRunner : public chrome::BrowserListObserver { | 621 class ReporterRunner : public chrome::BrowserListObserver { |
615 public: | 622 public: |
616 // Starts the sequence of attempts to run the reporter. | 623 // Registers |invocations| to run next time |TryToRun| is scheduled. (And if |
617 static void Run(const SwReporterInvocation& invocation, | 624 // it's not already scheduled, call it now.) |
618 const base::Version& version, | 625 static void ScheduleInvocations( |
619 scoped_refptr<base::TaskRunner> main_thread_task_runner, | 626 const SwReporterQueue& invocations, |
620 scoped_refptr<base::TaskRunner> blocking_task_runner) { | 627 const base::Version& version, |
621 if (!instance_) | 628 scoped_refptr<base::TaskRunner> main_thread_task_runner, |
| 629 scoped_refptr<base::TaskRunner> blocking_task_runner) { |
| 630 if (!instance_) { |
622 instance_ = new ReporterRunner; | 631 instance_ = new ReporterRunner; |
| 632 ANNOTATE_LEAKING_OBJECT_PTR(instance_); |
| 633 } |
623 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 634 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
624 // There's nothing to do if the path and version of the reporter has not | 635 |
625 // changed, we just keep running the tasks that are running now. | 636 // There's nothing to do if the invocation parameters and version of the |
626 if (instance_->invocation_ == invocation && instance_->version_.IsValid() && | 637 // reporter have not changed, we just keep running the tasks that are |
627 instance_->version_ == version) | 638 // running now. |
| 639 if (instance_->pending_invocations_ == invocations && |
| 640 instance_->version_.IsValid() && instance_->version_ == version) |
628 return; | 641 return; |
629 | 642 |
630 instance_->invocation_ = invocation; | 643 instance_->pending_invocations_ = invocations; |
631 instance_->version_ = version; | 644 instance_->version_ = version; |
632 instance_->main_thread_task_runner_ = std::move(main_thread_task_runner); | 645 instance_->main_thread_task_runner_ = std::move(main_thread_task_runner); |
633 instance_->blocking_task_runner_ = std::move(blocking_task_runner); | 646 instance_->blocking_task_runner_ = std::move(blocking_task_runner); |
634 | 647 |
635 if (instance_->first_run_) { | 648 if (instance_->first_run_) { |
636 instance_->first_run_ = false; | 649 instance_->first_run_ = false; |
637 instance_->TryToRun(); | 650 instance_->TryToRun(); |
638 } | 651 } |
639 } | 652 } |
640 | 653 |
641 private: | 654 private: |
642 ReporterRunner() {} | 655 ReporterRunner() {} |
643 ~ReporterRunner() override {} | 656 ~ReporterRunner() override {} |
644 | 657 |
645 // BrowserListObserver. | 658 // BrowserListObserver. |
646 void OnBrowserSetLastActive(Browser* browser) override {} | 659 void OnBrowserSetLastActive(Browser* browser) override {} |
647 void OnBrowserRemoved(Browser* browser) override {} | 660 void OnBrowserRemoved(Browser* browser) override {} |
648 void OnBrowserAdded(Browser* browser) override { | 661 void OnBrowserAdded(Browser* browser) override { |
649 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 662 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
650 DCHECK(browser); | 663 DCHECK(browser); |
651 MaybeFetchSRT(browser, version_); | 664 MaybeFetchSRT(browser, version_); |
652 BrowserList::RemoveObserver(this); | 665 BrowserList::RemoveObserver(this); |
653 } | 666 } |
654 | 667 |
655 // This method is called on the UI thread when the reporter run has completed. | 668 // Launches the command line at the head of the queue. |
656 // This is run as a task posted from an interruptible worker thread so should | 669 void ScheduleNextInvocation() { |
657 // be resilient to unexpected shutdown. | 670 DCHECK(!current_invocations_.empty()); |
| 671 auto next_invocation = current_invocations_.front(); |
| 672 current_invocations_.pop(); |
| 673 |
| 674 if (g_testing_delegate_) |
| 675 g_testing_delegate_->NotifyLaunchReady(); |
| 676 |
| 677 // Add switches for users who opted into extended Safe Browsing reporting. |
| 678 // The invocation object is changed locally right before the actual process |
| 679 // is launched because user status can change between this and the next run |
| 680 // for this ReporterRunner object. For example, the ReporterDone() callback |
| 681 // schedules the next run for a few days later, and the user might have |
| 682 // changed settings in the meantime. |
| 683 PrefService* local_state = g_browser_process->local_state(); |
| 684 if (next_invocation.flags & SwReporterInvocation::FLAG_SEND_REPORTER_LOGS && |
| 685 local_state && ShouldSendReporterLogs(*local_state)) { |
| 686 AddSwitchesForExtendedReporterUser(&next_invocation); |
| 687 // Set the local state value before the first attempt to run the |
| 688 // reporter, because we only want to upload logs once in the window |
| 689 // defined by |kDaysBetweenReporterLogsSent|. If we set with other local |
| 690 // state values after the reporter runs, we could send logs again too |
| 691 // quickly (for example, if Chrome stops before the reporter finishes). |
| 692 local_state->SetInt64(prefs::kSwReporterLastTimeSentReport, |
| 693 base::Time::Now().ToInternalValue()); |
| 694 } |
| 695 |
| 696 // It's OK to simply |PostTaskAndReplyWithResult| so that |
| 697 // |LaunchAndWaitForExit| doesn't need to access |main_thread_task_runner_| |
| 698 // since the callback is not delayed and the test task runner won't need to |
| 699 // force it. |
| 700 base::PostTaskAndReplyWithResult( |
| 701 blocking_task_runner_.get(), FROM_HERE, |
| 702 base::Bind(&LaunchAndWaitForExit, next_invocation), |
| 703 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), |
| 704 base::Time::Now(), version_, next_invocation)); |
| 705 } |
| 706 |
| 707 // This method is called on the UI thread when an invocation of the reporter |
| 708 // has completed. This is run as a task posted from an interruptible worker |
| 709 // thread so should be resilient to unexpected shutdown. |
658 void ReporterDone(const base::Time& reporter_start_time, | 710 void ReporterDone(const base::Time& reporter_start_time, |
659 const base::Version& version, | 711 const base::Version& version, |
660 const SwReporterInvocation& finished_invocation, | 712 const SwReporterInvocation& finished_invocation, |
661 int exit_code) { | 713 int exit_code) { |
662 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 714 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
663 | 715 |
664 if (g_testing_delegate_) | 716 if (g_testing_delegate_) |
665 g_testing_delegate_->NotifyReporterDone(); | 717 g_testing_delegate_->NotifyReporterDone(); |
666 | 718 |
667 base::TimeDelta reporter_running_time = | 719 base::TimeDelta reporter_running_time = |
668 base::Time::Now() - reporter_start_time; | 720 base::Time::Now() - reporter_start_time; |
669 // Don't continue when the reporter process failed to launch, but still try | 721 |
670 // again after the regular delay. It's not worth retrying earlier, risking | 722 // Don't continue the current queue of reporters if one failed to launch. |
671 // running too often if it always fails, since not many users fail here. | 723 if (exit_code == kReporterFailureExitCode) |
672 main_thread_task_runner_->PostDelayedTask( | 724 current_invocations_ = SwReporterQueue(); |
673 FROM_HERE, | 725 |
674 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 726 // As soon as we're not running this queue, schedule the next overall queue |
675 base::TimeDelta::FromDays(days_between_reporter_runs_)); | 727 // run after the regular delay. (If there was a failure it's not worth |
| 728 // retrying earlier, risking running too often if it always fails, since |
| 729 // not many users fail here.) |
| 730 if (current_invocations_.empty()) { |
| 731 main_thread_task_runner_->PostDelayedTask( |
| 732 FROM_HERE, |
| 733 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
| 734 base::TimeDelta::FromDays(days_between_reporter_runs_)); |
| 735 } else { |
| 736 ScheduleNextInvocation(); |
| 737 } |
| 738 |
| 739 // If the reporter failed to launch, do not process the results. (The exit |
| 740 // code itself doesn't need to be logged in this case because |
| 741 // SW_REPORTER_FAILED_TO_START is logged in |LaunchAndWaitForExit|.) |
676 if (exit_code == kReporterFailureExitCode) | 742 if (exit_code == kReporterFailureExitCode) |
677 return; | 743 return; |
678 | 744 |
679 UMAHistogramReporter uma(finished_invocation.suffix); | 745 UMAHistogramReporter uma(finished_invocation.suffix); |
680 uma.ReportVersion(version); | 746 uma.ReportVersion(version); |
681 uma.ReportExitCode(exit_code); | 747 uma.ReportExitCode(exit_code); |
682 uma.ReportFoundUwS(!finished_invocation.is_experimental /*use_rappor*/); | 748 uma.ReportFoundUwS(finished_invocation.flags & |
| 749 SwReporterInvocation::FLAG_LOG_TO_RAPPOR); |
683 | 750 |
684 // Only save results from the canonical version of the software. | |
685 PrefService* local_state = g_browser_process->local_state(); | 751 PrefService* local_state = g_browser_process->local_state(); |
686 if (local_state && !finished_invocation.is_experimental) { | 752 if (local_state) { |
687 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); | 753 if (finished_invocation.flags & |
| 754 SwReporterInvocation::FLAG_LOG_EXIT_CODE_TO_PREFS) |
| 755 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); |
688 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, | 756 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, |
689 base::Time::Now().ToInternalValue()); | 757 base::Time::Now().ToInternalValue()); |
690 } | 758 } |
691 uma.ReportRuntime(reporter_running_time); | 759 uma.ReportRuntime(reporter_running_time); |
692 uma.ReportScanTimes(); | 760 uma.ReportScanTimes(); |
693 uma.ReportMemoryUsage(); | 761 uma.ReportMemoryUsage(); |
694 | 762 |
695 // Only continue to launch the prompt for the canonical version. | 763 if (!(finished_invocation.flags & |
696 if (finished_invocation.is_experimental) | 764 SwReporterInvocation::FLAG_TRIGGER_PROMPT)) |
697 return; | 765 return; |
698 | 766 |
699 if (!IsInSRTPromptFieldTrialGroups()) { | 767 if (!IsInSRTPromptFieldTrialGroups()) { |
700 // Knowing about disabled field trial is more important than reporter not | 768 // Knowing about disabled field trial is more important than reporter not |
701 // finding anything to remove, so check this case first. | 769 // finding anything to remove, so check this case first. |
702 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); | 770 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); |
703 return; | 771 return; |
704 } | 772 } |
705 | 773 |
706 if (exit_code != kSwReporterPostRebootCleanupNeeded && | 774 if (exit_code != kSwReporterPostRebootCleanupNeeded && |
(...skipping 13 matching lines...) Expand all Loading... |
720 RecordReporterStepHistogram(SW_REPORTER_NO_BROWSER); | 788 RecordReporterStepHistogram(SW_REPORTER_NO_BROWSER); |
721 BrowserList::AddObserver(this); | 789 BrowserList::AddObserver(this); |
722 } else { | 790 } else { |
723 MaybeFetchSRT(browser, version_); | 791 MaybeFetchSRT(browser, version_); |
724 } | 792 } |
725 } | 793 } |
726 | 794 |
727 void TryToRun() { | 795 void TryToRun() { |
728 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 796 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
729 PrefService* local_state = g_browser_process->local_state(); | 797 PrefService* local_state = g_browser_process->local_state(); |
| 798 |
730 if (!version_.IsValid() || !local_state) { | 799 if (!version_.IsValid() || !local_state) { |
| 800 // TODO(b/641081): This doesn't look right. Even on first run, |version_| |
| 801 // should be valid (and this is already checked in RunSwReporters). We |
| 802 // should abort if local_state is missing, but this has nothing to do |
| 803 // with |first_run_|. |
731 DCHECK(first_run_); | 804 DCHECK(first_run_); |
732 return; | 805 return; |
733 } | 806 } |
734 | 807 |
735 // Run the reporter if it hasn't been triggered in the last | 808 // Run a queue of reporters if none have been triggered in the last |
736 // |days_between_reporter_runs_| days, which depends if there is a pending | 809 // |days_between_reporter_runs_| days, which depends if there is a pending |
737 // prompt to be added to Chrome's menu. | 810 // prompt to be added to Chrome's menu. |
738 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { | 811 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { |
739 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; | 812 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; |
740 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); | 813 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); |
741 } else { | 814 } else { |
742 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 815 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
743 } | 816 } |
| 817 const base::Time now = base::Time::Now(); |
744 const base::Time last_time_triggered = base::Time::FromInternalValue( | 818 const base::Time last_time_triggered = base::Time::FromInternalValue( |
745 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); | 819 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); |
746 base::TimeDelta next_trigger_delay( | 820 const base::Time next_trigger( |
747 last_time_triggered + | 821 last_time_triggered + |
748 base::TimeDelta::FromDays(days_between_reporter_runs_) - | 822 base::TimeDelta::FromDays(days_between_reporter_runs_)); |
749 base::Time::Now()); | 823 if (!pending_invocations_.empty() && |
750 if (next_trigger_delay.ToInternalValue() <= 0 || | 824 (next_trigger <= now || |
751 // Also make sure the kSwReporterLastTimeTriggered value is not set in | 825 // Also make sure the kSwReporterLastTimeTriggered value is not set in |
752 // the future. | 826 // the future. |
753 last_time_triggered > base::Time::Now()) { | 827 last_time_triggered > now)) { |
754 if (g_testing_delegate_) | 828 DCHECK(current_invocations_.empty()); |
755 g_testing_delegate_->NotifyLaunchReady(); | 829 current_invocations_ = pending_invocations_; |
756 | 830 ScheduleNextInvocation(); |
757 // Creating a new invocation to add switches for users who opted into | |
758 // extended Safe Browsing reporting. The invocation object is changed | |
759 // locally right before the actual process is launched because user status | |
760 // can change between this and the next run for this ReporterRunner | |
761 // object. For example, the ReporterDone() callback schedules the next run | |
762 // for a few days later, and the user might have changed settings in the | |
763 // meantime. | |
764 SwReporterInvocation actual_invocation(invocation_); | |
765 if (ShouldSendReporterLogs(*local_state)) { | |
766 AddSwitchesForExtendedReporterUser(&actual_invocation); | |
767 // Set the local state value before the first attempt to run the | |
768 // reporter, because we only want to upload logs once in the window | |
769 // defined by |kDaysBetweenReporterLogsSent|. If we set with other local | |
770 // state values after the reporter runs, we could send logs again too | |
771 // quickly (for example, if Chrome stops before the reporter finishes). | |
772 local_state->SetInt64(prefs::kSwReporterLastTimeSentReport, | |
773 base::Time::Now().ToInternalValue()); | |
774 } | |
775 // It's OK to simply |PostTaskAndReplyWithResult| so that | |
776 // |LaunchAndWaitForExit| doesn't need to access | |
777 // |main_thread_task_runner_| since the callback is not delayed and the | |
778 // test task runner won't need to force it. | |
779 base::PostTaskAndReplyWithResult( | |
780 blocking_task_runner_.get(), FROM_HERE, | |
781 base::Bind(&LaunchAndWaitForExit, actual_invocation), | |
782 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), | |
783 base::Time::Now(), version_, invocation_)); | |
784 } else { | 831 } else { |
785 main_thread_task_runner_->PostDelayedTask( | 832 main_thread_task_runner_->PostDelayedTask( |
786 FROM_HERE, | 833 FROM_HERE, |
787 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 834 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
788 next_trigger_delay); | 835 next_trigger - now); |
789 } | 836 } |
790 } | 837 } |
791 | 838 |
792 // Returns true if the experiment to send reporter logs is enabled, the user | 839 // Returns true if the experiment to send reporter logs is enabled, the user |
793 // opted into Safe Browsing extended reporting, and logs have been sent at | 840 // opted into Safe Browsing extended reporting, and logs have been sent at |
794 // least |kSwReporterLastTimeSentReport| days ago. | 841 // least |kSwReporterLastTimeSentReport| days ago. |
795 bool ShouldSendReporterLogs(const PrefService& local_state) { | 842 bool ShouldSendReporterLogs(const PrefService& local_state) { |
796 if (!base::FeatureList::IsEnabled(kSwReporterExtendedSafeBrowsingFeature) || | 843 if (!base::FeatureList::IsEnabled(kSwReporterExtendedSafeBrowsingFeature) || |
797 !SafeBrowsingExtendedReportingEnabled()) { | 844 !SafeBrowsingExtendedReportingEnabled()) { |
798 return false; | 845 return false; |
(...skipping 15 matching lines...) Expand all Loading... |
814 | 861 |
815 void AddSwitchesForExtendedReporterUser(SwReporterInvocation* invocation) { | 862 void AddSwitchesForExtendedReporterUser(SwReporterInvocation* invocation) { |
816 invocation->command_line.AppendSwitch(kExtendedSafeBrowsingEnabledSwitch); | 863 invocation->command_line.AppendSwitch(kExtendedSafeBrowsingEnabledSwitch); |
817 invocation->command_line.AppendSwitchASCII( | 864 invocation->command_line.AppendSwitchASCII( |
818 kChromeVersionSwitch, version_info::GetVersionNumber()); | 865 kChromeVersionSwitch, version_info::GetVersionNumber()); |
819 invocation->command_line.AppendSwitchNative( | 866 invocation->command_line.AppendSwitchNative( |
820 kChromeChannelSwitch, base::IntToString16(ChannelAsInt())); | 867 kChromeChannelSwitch, base::IntToString16(ChannelAsInt())); |
821 } | 868 } |
822 | 869 |
823 bool first_run_ = true; | 870 bool first_run_ = true; |
824 SwReporterInvocation invocation_; | 871 |
| 872 // The queue of invocations that are currently running. |
| 873 SwReporterQueue current_invocations_; |
| 874 |
| 875 // The invocations to run next time the SwReporter is run. |
| 876 SwReporterQueue pending_invocations_; |
| 877 |
825 base::Version version_; | 878 base::Version version_; |
826 scoped_refptr<base::TaskRunner> main_thread_task_runner_; | 879 scoped_refptr<base::TaskRunner> main_thread_task_runner_; |
827 scoped_refptr<base::TaskRunner> blocking_task_runner_; | 880 scoped_refptr<base::TaskRunner> blocking_task_runner_; |
828 | 881 |
829 // This value is used to identify how long to wait before starting a new run | 882 // This value is used to identify how long to wait before starting a new run |
830 // of the reporter. It's initialized with the default value and may be changed | 883 // of the reporter queue. It's initialized with the default value and may be |
831 // to a different value when a prompt is pending and the reporter should be | 884 // changed to a different value when a prompt is pending and the reporter |
832 // run before adding the global error to the Chrome menu. | 885 // should be run before adding the global error to the Chrome menu. |
833 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 886 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
834 | 887 |
835 // A single leaky instance. | 888 // A single leaky instance. |
836 static ReporterRunner* instance_; | 889 static ReporterRunner* instance_; |
837 | 890 |
838 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); | 891 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); |
839 }; | 892 }; |
840 | 893 |
841 ReporterRunner* ReporterRunner::instance_ = nullptr; | 894 ReporterRunner* ReporterRunner::instance_ = nullptr; |
842 | 895 |
843 } // namespace | 896 } // namespace |
844 | 897 |
845 SwReporterInvocation::SwReporterInvocation() | 898 SwReporterInvocation::SwReporterInvocation() |
846 : command_line(base::CommandLine::NO_PROGRAM) {} | 899 : command_line(base::CommandLine::NO_PROGRAM) {} |
847 | 900 |
848 SwReporterInvocation::SwReporterInvocation(const SwReporterInvocation& other) | |
849 : command_line(other.command_line), | |
850 suffix(other.suffix), | |
851 is_experimental(other.is_experimental) {} | |
852 | |
853 SwReporterInvocation SwReporterInvocation::FromFilePath( | 901 SwReporterInvocation SwReporterInvocation::FromFilePath( |
854 const base::FilePath& exe_path) { | 902 const base::FilePath& exe_path) { |
855 SwReporterInvocation invocation; | 903 SwReporterInvocation invocation; |
856 invocation.command_line = base::CommandLine(exe_path); | 904 invocation.command_line = base::CommandLine(exe_path); |
857 return invocation; | 905 return invocation; |
858 } | 906 } |
859 | 907 |
860 SwReporterInvocation SwReporterInvocation::FromCommandLine( | 908 SwReporterInvocation SwReporterInvocation::FromCommandLine( |
861 const base::CommandLine& command_line) { | 909 const base::CommandLine& command_line) { |
862 SwReporterInvocation invocation; | 910 SwReporterInvocation invocation; |
863 invocation.command_line = command_line; | 911 invocation.command_line = command_line; |
864 return invocation; | 912 return invocation; |
865 } | 913 } |
866 | 914 |
867 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { | 915 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { |
868 return command_line.argv() == other.command_line.argv() && | 916 return command_line.argv() == other.command_line.argv() && |
869 suffix == other.suffix && is_experimental == other.is_experimental; | 917 suffix == other.suffix && flags == other.flags; |
870 } | 918 } |
871 | 919 |
872 void RunSwReporter(const SwReporterInvocation& invocation, | 920 void RunSwReporters(const SwReporterQueue& invocations, |
873 const base::Version& version, | 921 const base::Version& version, |
874 scoped_refptr<base::TaskRunner> main_thread_task_runner, | 922 scoped_refptr<base::TaskRunner> main_thread_task_runner, |
875 scoped_refptr<base::TaskRunner> blocking_task_runner) { | 923 scoped_refptr<base::TaskRunner> blocking_task_runner) { |
876 ReporterRunner::Run(invocation, version, std::move(main_thread_task_runner), | 924 DCHECK(!invocations.empty()); |
877 std::move(blocking_task_runner)); | 925 DCHECK(version.IsValid()); |
| 926 ReporterRunner::ScheduleInvocations(invocations, version, |
| 927 std::move(main_thread_task_runner), |
| 928 std::move(blocking_task_runner)); |
878 } | 929 } |
879 | 930 |
880 bool ReporterFoundUws() { | 931 bool ReporterFoundUws() { |
881 PrefService* local_state = g_browser_process->local_state(); | 932 PrefService* local_state = g_browser_process->local_state(); |
882 if (!local_state) | 933 if (!local_state) |
883 return false; | 934 return false; |
884 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); | 935 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); |
885 return exit_code == kSwReporterCleanupNeeded; | 936 return exit_code == kSwReporterCleanupNeeded; |
886 } | 937 } |
887 | 938 |
888 bool UserHasRunCleaner() { | 939 bool UserHasRunCleaner() { |
889 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); | 940 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); |
890 cleaner_key_path.append(L"\\").append(kCleanerSubKey); | 941 cleaner_key_path.append(L"\\").append(kCleanerSubKey); |
891 | 942 |
892 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), | 943 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), |
893 KEY_QUERY_VALUE); | 944 KEY_QUERY_VALUE); |
894 | 945 |
895 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; | 946 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; |
896 } | 947 } |
897 | 948 |
898 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { | 949 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { |
899 g_testing_delegate_ = delegate; | 950 g_testing_delegate_ = delegate; |
900 } | 951 } |
901 | 952 |
902 } // namespace safe_browsing | 953 } // namespace safe_browsing |
OLD | NEW |