| 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 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 prefs->SetString(prefs::kSwReporterPromptVersion, | 577 prefs->SetString(prefs::kSwReporterPromptVersion, |
| 576 reporter_version.GetString()); | 578 reporter_version.GetString()); |
| 577 | 579 |
| 578 // Download the SRT. | 580 // Download the SRT. |
| 579 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); | 581 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); |
| 580 | 582 |
| 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 a queue of reporters and react to their exit codes. |
| 586 // schedules subsequent runs as needed, or retries as soon as a browser is | 588 // It schedules subsequent runs of the queue as needed, or retries as soon as a |
| 587 // available when none is on first try. | 589 // browser is 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 // Registers |invocations| to run next time |TryToRun| is scheduled. (And if |
| 591 static void Run(const SwReporterInvocation& invocation, | 593 // it's not already scheduled, call it now.) |
| 592 const base::Version& version, | 594 static void ScheduleInvocations( |
| 593 scoped_refptr<base::TaskRunner> main_thread_task_runner, | 595 const SwReporterQueue& invocations, |
| 594 scoped_refptr<base::TaskRunner> blocking_task_runner) { | 596 const base::Version& version, |
| 597 scoped_refptr<base::TaskRunner> main_thread_task_runner, |
| 598 scoped_refptr<base::TaskRunner> blocking_task_runner) { |
| 595 if (!instance_) | 599 if (!instance_) |
| 596 instance_ = new ReporterRunner; | 600 instance_ = new ReporterRunner; |
| 597 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 601 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 598 // There's nothing to do if the path and version of the reporter has not | 602 |
| 599 // changed, we just keep running the tasks that are running now. | 603 // There's nothing to do if the invocation parameters and version of the |
| 600 if (instance_->invocation_ == invocation && instance_->version_.IsValid() && | 604 // reporter have not changed, we just keep running the tasks that are |
| 601 instance_->version_ == version) | 605 // running now. |
| 606 if (instance_->pending_invocations_ == invocations && |
| 607 instance_->version_.IsValid() && instance_->version_ == version) |
| 602 return; | 608 return; |
| 603 | 609 |
| 604 instance_->invocation_ = invocation; | 610 instance_->pending_invocations_ = invocations; |
| 605 instance_->version_ = version; | 611 instance_->version_ = version; |
| 606 instance_->main_thread_task_runner_ = std::move(main_thread_task_runner); | 612 instance_->main_thread_task_runner_ = std::move(main_thread_task_runner); |
| 607 instance_->blocking_task_runner_ = std::move(blocking_task_runner); | 613 instance_->blocking_task_runner_ = std::move(blocking_task_runner); |
| 608 | 614 |
| 609 if (instance_->first_run_) { | 615 if (instance_->first_run_) { |
| 610 instance_->first_run_ = false; | 616 instance_->first_run_ = false; |
| 611 instance_->TryToRun(); | 617 instance_->TryToRun(); |
| 612 } | 618 } |
| 613 } | 619 } |
| 614 | 620 |
| 615 private: | 621 private: |
| 616 ReporterRunner() {} | 622 ReporterRunner() {} |
| 617 ~ReporterRunner() override {} | 623 ~ReporterRunner() override {} |
| 618 | 624 |
| 619 // BrowserListObserver. | 625 // BrowserListObserver. |
| 620 void OnBrowserSetLastActive(Browser* browser) override {} | 626 void OnBrowserSetLastActive(Browser* browser) override {} |
| 621 void OnBrowserRemoved(Browser* browser) override {} | 627 void OnBrowserRemoved(Browser* browser) override {} |
| 622 void OnBrowserAdded(Browser* browser) override { | 628 void OnBrowserAdded(Browser* browser) override { |
| 623 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 629 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 624 DCHECK(browser); | 630 DCHECK(browser); |
| 625 MaybeFetchSRT(browser, version_); | 631 MaybeFetchSRT(browser, version_); |
| 626 BrowserList::RemoveObserver(this); | 632 BrowserList::RemoveObserver(this); |
| 627 } | 633 } |
| 628 | 634 |
| 629 // This method is called on the UI thread when the reporter run has completed. | 635 // Launches the command line at the head of the queue. |
| 630 // This is run as a task posted from an interruptible worker thread so should | 636 void ScheduleNextInvocation() { |
| 631 // be resilient to unexpected shutdown. | 637 DCHECK(!current_invocations_.empty()); |
| 638 auto next_invocation = current_invocations_.front(); |
| 639 current_invocations_.pop(); |
| 640 |
| 641 if (g_testing_delegate_) |
| 642 g_testing_delegate_->NotifyLaunchReady(); |
| 643 |
| 644 // It's OK to simply |PostTaskAndReplyWithResult| so that |
| 645 // |LaunchAndWaitForExit| doesn't need to access |main_thread_task_runner_| |
| 646 // since the callback is not delayed and the test task runner won't need to |
| 647 // force it. |
| 648 base::PostTaskAndReplyWithResult( |
| 649 blocking_task_runner_.get(), FROM_HERE, |
| 650 base::Bind(&LaunchAndWaitForExit, next_invocation), |
| 651 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), |
| 652 base::Time::Now(), version_, next_invocation)); |
| 653 } |
| 654 |
| 655 // This method is called on the UI thread when an invocation of the reporter |
| 656 // has completed. This is run as a task posted from an interruptible worker |
| 657 // thread so should be resilient to unexpected shutdown. |
| 632 void ReporterDone(const base::Time& reporter_start_time, | 658 void ReporterDone(const base::Time& reporter_start_time, |
| 633 const base::Version& version, | 659 const base::Version& version, |
| 634 const SwReporterInvocation& finished_invocation, | 660 const SwReporterInvocation& finished_invocation, |
| 635 int exit_code) { | 661 int exit_code) { |
| 636 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 662 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 637 | 663 |
| 638 if (g_testing_delegate_) | 664 if (g_testing_delegate_) |
| 639 g_testing_delegate_->NotifyReporterDone(); | 665 g_testing_delegate_->NotifyReporterDone(); |
| 640 | 666 |
| 641 base::TimeDelta reporter_running_time = | 667 base::TimeDelta reporter_running_time = |
| 642 base::Time::Now() - reporter_start_time; | 668 base::Time::Now() - reporter_start_time; |
| 643 // Don't continue when the reporter process failed to launch, but still try | 669 |
| 644 // again after the regular delay. It's not worth retrying earlier, risking | 670 // 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. | 671 if (exit_code == kReporterFailureExitCode) |
| 646 main_thread_task_runner_->PostDelayedTask( | 672 current_invocations_ = SwReporterQueue(); |
| 647 FROM_HERE, | 673 |
| 648 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 674 // As soon as we're not running this queue, schedule the next overall queue |
| 649 base::TimeDelta::FromDays(days_between_reporter_runs_)); | 675 // run after the regular delay. (If there was a failure it's not worth |
| 676 // retrying earlier, risking running too often if it always fails, since |
| 677 // not many users fail here.) |
| 678 if (current_invocations_.empty()) { |
| 679 main_thread_task_runner_->PostDelayedTask( |
| 680 FROM_HERE, |
| 681 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
| 682 base::TimeDelta::FromDays(days_between_reporter_runs_)); |
| 683 } else { |
| 684 ScheduleNextInvocation(); |
| 685 } |
| 686 |
| 687 // If the reporter failed to launch, do not process the results. (The exit |
| 688 // code itself doesn't need to be logged in this case because |
| 689 // SW_REPORTER_FAILED_TO_START is logged in |LaunchAndWaitForExit|.) |
| 650 if (exit_code == kReporterFailureExitCode) | 690 if (exit_code == kReporterFailureExitCode) |
| 651 return; | 691 return; |
| 652 | 692 |
| 653 UMAHistogramReporter uma(finished_invocation.suffix); | 693 UMAHistogramReporter uma(finished_invocation.suffix); |
| 654 uma.ReportVersion(version); | 694 uma.ReportVersion(version); |
| 655 uma.ReportExitCode(exit_code); | 695 uma.ReportExitCode(exit_code); |
| 656 uma.ReportFoundUwS(!finished_invocation.is_experimental /*use_rappor*/); | 696 uma.ReportFoundUwS(finished_invocation.flags & |
| 697 SwReporterInvocation::FLAG_LOG_TO_RAPPOR); |
| 657 | 698 |
| 658 // Only save results from the canonical version of the software. | |
| 659 PrefService* local_state = g_browser_process->local_state(); | 699 PrefService* local_state = g_browser_process->local_state(); |
| 660 if (local_state && !finished_invocation.is_experimental) { | 700 if (local_state && |
| 701 (finished_invocation.flags & SwReporterInvocation::FLAG_LOG_TO_PREFS)) { |
| 661 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); | 702 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); |
| 662 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, | 703 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, |
| 663 base::Time::Now().ToInternalValue()); | 704 base::Time::Now().ToInternalValue()); |
| 664 } | 705 } |
| 665 uma.ReportRuntime(reporter_running_time); | 706 uma.ReportRuntime(reporter_running_time); |
| 666 uma.ReportScanTimes(); | 707 uma.ReportScanTimes(); |
| 667 uma.ReportMemoryUsage(); | 708 uma.ReportMemoryUsage(); |
| 668 | 709 |
| 669 // Only continue to launch the prompt for the canonical version. | 710 if (!(finished_invocation.flags & |
| 670 if (finished_invocation.is_experimental) | 711 SwReporterInvocation::FLAG_TRIGGER_PROMPT)) |
| 671 return; | 712 return; |
| 672 | 713 |
| 673 if (!IsInSRTPromptFieldTrialGroups()) { | 714 if (!IsInSRTPromptFieldTrialGroups()) { |
| 674 // Knowing about disabled field trial is more important than reporter not | 715 // Knowing about disabled field trial is more important than reporter not |
| 675 // finding anything to remove, so check this case first. | 716 // finding anything to remove, so check this case first. |
| 676 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); | 717 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); |
| 677 return; | 718 return; |
| 678 } | 719 } |
| 679 | 720 |
| 680 if (exit_code != kSwReporterPostRebootCleanupNeeded && | 721 if (exit_code != kSwReporterPostRebootCleanupNeeded && |
| (...skipping 18 matching lines...) Expand all Loading... |
| 699 } | 740 } |
| 700 | 741 |
| 701 void TryToRun() { | 742 void TryToRun() { |
| 702 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 743 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 703 PrefService* local_state = g_browser_process->local_state(); | 744 PrefService* local_state = g_browser_process->local_state(); |
| 704 if (!version_.IsValid() || !local_state) { | 745 if (!version_.IsValid() || !local_state) { |
| 705 DCHECK(first_run_); | 746 DCHECK(first_run_); |
| 706 return; | 747 return; |
| 707 } | 748 } |
| 708 | 749 |
| 709 // Run the reporter if it hasn't been triggered in the last | 750 // Run a queue of reporters if none have been triggered in the last |
| 710 // |days_between_reporter_runs_| days, which depends if there is a pending | 751 // |days_between_reporter_runs_| days, which depends if there is a pending |
| 711 // prompt to be added to Chrome's menu. | 752 // prompt to be added to Chrome's menu. |
| 712 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { | 753 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { |
| 713 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; | 754 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; |
| 714 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); | 755 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); |
| 715 } else { | 756 } else { |
| 716 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 757 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
| 717 } | 758 } |
| 759 const base::Time now = base::Time::Now(); |
| 718 const base::Time last_time_triggered = base::Time::FromInternalValue( | 760 const base::Time last_time_triggered = base::Time::FromInternalValue( |
| 719 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); | 761 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); |
| 720 base::TimeDelta next_trigger_delay( | 762 const base::Time next_trigger( |
| 721 last_time_triggered + | 763 last_time_triggered + |
| 722 base::TimeDelta::FromDays(days_between_reporter_runs_) - | 764 base::TimeDelta::FromDays(days_between_reporter_runs_)); |
| 723 base::Time::Now()); | 765 if (!pending_invocations_.empty() && |
| 724 if (next_trigger_delay.ToInternalValue() <= 0 || | 766 (next_trigger <= now || |
| 725 // Also make sure the kSwReporterLastTimeTriggered value is not set in | 767 // Also make sure the kSwReporterLastTimeTriggered value is not set in |
| 726 // the future. | 768 // the future. |
| 727 last_time_triggered > base::Time::Now()) { | 769 last_time_triggered > now)) { |
| 728 if (g_testing_delegate_) | 770 DCHECK(current_invocations_.empty()); |
| 729 g_testing_delegate_->NotifyLaunchReady(); | 771 current_invocations_ = pending_invocations_; |
| 730 | 772 ScheduleNextInvocation(); |
| 731 // It's OK to simply |PostTaskAndReplyWithResult| so that | |
| 732 // |LaunchAndWaitForExit| doesn't need to access | |
| 733 // |main_thread_task_runner_| since the callback is not delayed and the | |
| 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 { | 773 } else { |
| 741 main_thread_task_runner_->PostDelayedTask( | 774 main_thread_task_runner_->PostDelayedTask( |
| 742 FROM_HERE, | 775 FROM_HERE, |
| 743 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 776 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
| 744 next_trigger_delay); | 777 next_trigger - now); |
| 745 } | 778 } |
| 746 } | 779 } |
| 747 | 780 |
| 748 bool first_run_ = true; | 781 bool first_run_ = true; |
| 749 SwReporterInvocation invocation_; | 782 |
| 783 // The queue of invocations that are currently running. |
| 784 SwReporterQueue current_invocations_; |
| 785 |
| 786 // The invocations to run next time the SwReporter is run. |
| 787 SwReporterQueue pending_invocations_; |
| 788 |
| 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 queue. It's initialized with the default value and may be |
| 756 // to a different value when a prompt is pending and the reporter should be | 795 // changed to a different value when a prompt is pending and the reporter |
| 757 // run before adding the global error to the Chrome menu. | 796 // should be 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 |
| 760 // A single leaky instance. | 799 // A single leaky instance. |
| 761 static ReporterRunner* instance_; | 800 static ReporterRunner* instance_; |
| 762 | 801 |
| 763 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); | 802 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); |
| 764 }; | 803 }; |
| 765 | 804 |
| 766 ReporterRunner* ReporterRunner::instance_ = nullptr; | 805 ReporterRunner* ReporterRunner::instance_ = nullptr; |
| 767 | 806 |
| (...skipping 11 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 DCHECK(!invocations.empty()); |
| 797 std::move(blocking_task_runner)); | 836 ReporterRunner::ScheduleInvocations(invocations, version, |
| 837 std::move(main_thread_task_runner), |
| 838 std::move(blocking_task_runner)); |
| 798 } | 839 } |
| 799 | 840 |
| 800 bool ReporterFoundUws() { | 841 bool ReporterFoundUws() { |
| 801 PrefService* local_state = g_browser_process->local_state(); | 842 PrefService* local_state = g_browser_process->local_state(); |
| 802 if (!local_state) | 843 if (!local_state) |
| 803 return false; | 844 return false; |
| 804 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); | 845 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); |
| 805 return exit_code == kSwReporterCleanupNeeded; | 846 return exit_code == kSwReporterCleanupNeeded; |
| 806 } | 847 } |
| 807 | 848 |
| 808 bool UserHasRunCleaner() { | 849 bool UserHasRunCleaner() { |
| 809 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); | 850 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); |
| 810 cleaner_key_path.append(L"\\").append(kCleanerSubKey); | 851 cleaner_key_path.append(L"\\").append(kCleanerSubKey); |
| 811 | 852 |
| 812 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), | 853 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), |
| 813 KEY_QUERY_VALUE); | 854 KEY_QUERY_VALUE); |
| 814 | 855 |
| 815 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; | 856 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; |
| 816 } | 857 } |
| 817 | 858 |
| 818 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { | 859 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { |
| 819 g_testing_delegate_ = delegate; | 860 g_testing_delegate_ = delegate; |
| 820 } | 861 } |
| 821 | 862 |
| 822 } // namespace safe_browsing | 863 } // namespace safe_browsing |
| OLD | NEW |