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 <memory> | 10 #include <memory> |
10 #include <vector> | 11 #include <vector> |
11 | 12 |
12 #include "base/bind.h" | 13 #include "base/bind.h" |
13 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
14 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
15 #include "base/command_line.h" | 16 #include "base/command_line.h" |
17 #include "base/feature_list.h" | |
16 #include "base/files/file_path.h" | 18 #include "base/files/file_path.h" |
17 #include "base/macros.h" | 19 #include "base/macros.h" |
18 #include "base/metrics/field_trial.h" | 20 #include "base/metrics/field_trial.h" |
19 #include "base/metrics/histogram_macros.h" | 21 #include "base/metrics/histogram_macros.h" |
20 #include "base/metrics/sparse_histogram.h" | 22 #include "base/metrics/sparse_histogram.h" |
21 #include "base/process/launch.h" | 23 #include "base/process/launch.h" |
22 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" |
23 #include "base/strings/stringprintf.h" | 25 #include "base/strings/stringprintf.h" |
24 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" |
25 #include "base/task_runner_util.h" | 27 #include "base/task_runner_util.h" |
26 #include "base/time/time.h" | 28 #include "base/time/time.h" |
27 #include "base/win/registry.h" | 29 #include "base/win/registry.h" |
28 #include "chrome/browser/browser_process.h" | 30 #include "chrome/browser/browser_process.h" |
29 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" | 31 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" |
30 #include "chrome/browser/profiles/profile.h" | 32 #include "chrome/browser/profiles/profile.h" |
31 #include "chrome/browser/profiles/profile_io_data.h" | 33 #include "chrome/browser/profiles/profile_io_data.h" |
34 #include "chrome/browser/safe_browsing/srt_client_info_win.h" | |
32 #include "chrome/browser/safe_browsing/srt_global_error_win.h" | 35 #include "chrome/browser/safe_browsing/srt_global_error_win.h" |
33 #include "chrome/browser/ui/browser_finder.h" | 36 #include "chrome/browser/ui/browser_finder.h" |
34 #include "chrome/browser/ui/browser_list.h" | 37 #include "chrome/browser/ui/browser_list.h" |
35 #include "chrome/browser/ui/browser_list_observer.h" | 38 #include "chrome/browser/ui/browser_list_observer.h" |
36 #include "chrome/browser/ui/global_error/global_error_service.h" | 39 #include "chrome/browser/ui/global_error/global_error_service.h" |
37 #include "chrome/browser/ui/global_error/global_error_service_factory.h" | 40 #include "chrome/browser/ui/global_error/global_error_service_factory.h" |
41 #include "chrome/common/pref_names.h" | |
38 #include "components/component_updater/pref_names.h" | 42 #include "components/component_updater/pref_names.h" |
39 #include "components/prefs/pref_service.h" | 43 #include "components/prefs/pref_service.h" |
40 #include "components/rappor/rappor_service.h" | 44 #include "components/rappor/rappor_service.h" |
41 #include "components/variations/net/variations_http_headers.h" | 45 #include "components/variations/net/variations_http_headers.h" |
46 #include "components/version_info/version_info.h" | |
42 #include "content/public/browser/browser_thread.h" | 47 #include "content/public/browser/browser_thread.h" |
43 #include "net/base/load_flags.h" | 48 #include "net/base/load_flags.h" |
44 #include "net/http/http_status_code.h" | 49 #include "net/http/http_status_code.h" |
45 #include "net/url_request/url_fetcher.h" | 50 #include "net/url_request/url_fetcher.h" |
46 #include "net/url_request/url_fetcher_delegate.h" | 51 #include "net/url_request/url_fetcher_delegate.h" |
47 #include "net/url_request/url_request_context_getter.h" | 52 #include "net/url_request/url_request_context_getter.h" |
48 | 53 |
49 using content::BrowserThread; | 54 using content::BrowserThread; |
50 | 55 |
51 namespace safe_browsing { | 56 namespace safe_browsing { |
52 | 57 |
53 const wchar_t kSoftwareRemovalToolRegistryKey[] = | 58 const wchar_t kSoftwareRemovalToolRegistryKey[] = |
54 L"Software\\Google\\Software Removal Tool"; | 59 L"Software\\Google\\Software Removal Tool"; |
55 | 60 |
56 const wchar_t kCleanerSubKey[] = L"Cleaner"; | 61 const wchar_t kCleanerSubKey[] = L"Cleaner"; |
57 | 62 |
58 const wchar_t kEndTimeValueName[] = L"EndTime"; | 63 const wchar_t kEndTimeValueName[] = L"EndTime"; |
59 const wchar_t kStartTimeValueName[] = L"StartTime"; | 64 const wchar_t kStartTimeValueName[] = L"StartTime"; |
60 | 65 |
66 const char kExtendedSafeBrowsingEnabledSwitch[] = | |
67 "extended-safebrowsing-enabled"; | |
68 | |
61 namespace { | 69 namespace { |
62 | 70 |
63 // Used to send UMA information about missing start and end time registry | 71 // Used to send UMA information about missing start and end time registry |
64 // values for the reporter. Replicated in the histograms.xml file, so the order | 72 // values for the reporter. Replicated in the histograms.xml file, so the order |
65 // MUST NOT CHANGE. | 73 // MUST NOT CHANGE. |
66 enum SwReporterRunningTimeRegistryError { | 74 enum SwReporterRunningTimeRegistryError { |
67 REPORTER_RUNNING_TIME_ERROR_NO_ERROR = 0, | 75 REPORTER_RUNNING_TIME_ERROR_NO_ERROR = 0, |
68 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID = 1, | 76 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID = 1, |
69 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME = 2, | 77 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME = 2, |
70 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME = 3, | 78 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME = 3, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 const wchar_t kScanTimesSubKey[] = L"ScanTimes"; | 116 const wchar_t kScanTimesSubKey[] = L"ScanTimes"; |
109 const wchar_t kFoundUwsValueName[] = L"FoundUws"; | 117 const wchar_t kFoundUwsValueName[] = L"FoundUws"; |
110 const wchar_t kMemoryUsedValueName[] = L"MemoryUsed"; | 118 const wchar_t kMemoryUsedValueName[] = L"MemoryUsed"; |
111 | 119 |
112 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; | 120 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; |
113 const char kFoundUwsReadErrorMetricName[] = | 121 const char kFoundUwsReadErrorMetricName[] = |
114 "SoftwareReporter.FoundUwSReadError"; | 122 "SoftwareReporter.FoundUwSReadError"; |
115 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; | 123 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; |
116 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; | 124 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; |
117 | 125 |
126 const base::Feature kSwReporterExtendedSafeBrowsingFeature{ | |
127 "SwReporterExtendedSafeBrowsingFeature", base::FEATURE_DISABLED_BY_DEFAULT}; | |
128 | |
118 // Reports metrics about the software reporter via UMA (and sometimes Rappor). | 129 // Reports metrics about the software reporter via UMA (and sometimes Rappor). |
119 class UMAHistogramReporter { | 130 class UMAHistogramReporter { |
120 public: | 131 public: |
121 // Reports the software reporter tool's version via UMA. | 132 // Reports the software reporter tool's version via UMA. |
122 void ReportVersion(const base::Version& version) const { | 133 void ReportVersion(const base::Version& version) const { |
123 DCHECK(!version.components().empty()); | 134 DCHECK(!version.components().empty()); |
124 // The minor version is the 2nd last component of the version, | 135 // The minor version is the 2nd last component of the version, |
125 // or just the first component if there is only 1. | 136 // or just the first component if there is only 1. |
126 uint32_t minor_version = 0; | 137 uint32_t minor_version = 0; |
127 if (version.components().size() > 1) | 138 if (version.components().size() > 1) |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 if (error->GetBubbleView()) { | 358 if (error->GetBubbleView()) { |
348 show_bubble = false; | 359 show_bubble = false; |
349 break; | 360 break; |
350 } | 361 } |
351 } | 362 } |
352 } | 363 } |
353 if (show_bubble) | 364 if (show_bubble) |
354 global_error->ShowBubbleView(browser); | 365 global_error->ShowBubbleView(browser); |
355 } | 366 } |
356 | 367 |
368 // Returns true if there is a profile that is not in incognito mode and the user | |
369 // has opted into Safe Browsing extended reporting. | |
370 bool SafeBrowsingExtendedReportingEnabled() { | |
371 BrowserList* browser_list = BrowserList::GetInstance(); | |
372 return std::any_of(browser_list->begin_last_active(), | |
373 browser_list->end_last_active(), | |
374 [](const Browser* browser) { | |
375 const Profile* profile = browser->profile(); | |
csharp
2016/08/30 13:39:08
What about converting this lambda to a helper func
ftirelo
2016/08/30 21:21:48
Done.
| |
376 return profile && !profile->IsOffTheRecord() && | |
377 profile->GetPrefs()->GetBoolean( | |
378 prefs::kSafeBrowsingExtendedReportingEnabled); | |
379 }); | |
380 } | |
381 | |
357 // This function is called from a worker thread to launch the SwReporter and | 382 // This function is called from a worker thread to launch the SwReporter and |
358 // wait for termination to collect its exit code. This task could be | 383 // wait for termination to collect its exit code. This task could be |
359 // interrupted by a shutdown at any time, so it shouldn't depend on anything | 384 // interrupted by a shutdown at any time, so it shouldn't depend on anything |
360 // external that could be shut down beforehand. | 385 // external that could be shut down beforehand. |
361 int LaunchAndWaitForExit(const SwReporterInvocation& invocation) { | 386 int LaunchAndWaitForExit(const SwReporterInvocation& invocation) { |
362 if (g_testing_delegate_) | 387 if (g_testing_delegate_) |
363 return g_testing_delegate_->LaunchReporter(invocation); | 388 return g_testing_delegate_->LaunchReporter(invocation); |
364 base::Process reporter_process = | 389 base::Process reporter_process = |
365 base::LaunchProcess(invocation.command_line, base::LaunchOptions()); | 390 base::LaunchProcess(invocation.command_line, base::LaunchOptions()); |
366 // This exit code is used to identify that a reporter run didn't happen, so | 391 // This exit code is used to identify that a reporter run didn't happen, so |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
542 DCHECK(browser); | 567 DCHECK(browser); |
543 MaybeFetchSRT(browser, version_); | 568 MaybeFetchSRT(browser, version_); |
544 BrowserList::RemoveObserver(this); | 569 BrowserList::RemoveObserver(this); |
545 } | 570 } |
546 | 571 |
547 // This method is called on the UI thread when the reporter run has completed. | 572 // This method is called on the UI thread when the reporter run has completed. |
548 // This is run as a task posted from an interruptible worker thread so should | 573 // This is run as a task posted from an interruptible worker thread so should |
549 // be resilient to unexpected shutdown. | 574 // be resilient to unexpected shutdown. |
550 void ReporterDone(const base::Time& reporter_start_time, | 575 void ReporterDone(const base::Time& reporter_start_time, |
551 const base::Version& version, | 576 const base::Version& version, |
577 bool logging_enabled, | |
552 int exit_code) { | 578 int exit_code) { |
553 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 579 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
554 | 580 |
555 if (g_testing_delegate_) | 581 if (g_testing_delegate_) |
556 g_testing_delegate_->NotifyReporterDone(); | 582 g_testing_delegate_->NotifyReporterDone(); |
557 | 583 |
558 base::TimeDelta reporter_running_time = | 584 base::TimeDelta reporter_running_time = |
559 base::Time::Now() - reporter_start_time; | 585 base::Time::Now() - reporter_start_time; |
560 // Don't continue when the reporter process failed to launch, but still try | 586 // Don't continue when the reporter process failed to launch, but still try |
561 // again after the regular delay. It's not worth retrying earlier, risking | 587 // again after the regular delay. It's not worth retrying earlier, risking |
562 // running too often if it always fails, since not many users fail here. | 588 // running too often if it always fails, since not many users fail here. |
563 main_thread_task_runner_->PostDelayedTask( | 589 main_thread_task_runner_->PostDelayedTask( |
564 FROM_HERE, | 590 FROM_HERE, |
565 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 591 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
566 base::TimeDelta::FromDays(days_between_reporter_runs_)); | 592 base::TimeDelta::FromDays(days_between_reporter_runs_)); |
567 if (exit_code == kReporterFailureExitCode) | 593 if (exit_code == kReporterFailureExitCode) |
568 return; | 594 return; |
569 | 595 |
570 UMAHistogramReporter uma; | 596 UMAHistogramReporter uma; |
571 uma.ReportVersion(version); | 597 uma.ReportVersion(version); |
572 uma.ReportExitCode(exit_code); | 598 uma.ReportExitCode(exit_code); |
573 uma.ReportFoundUwS(); | 599 uma.ReportFoundUwS(); |
574 PrefService* local_state = g_browser_process->local_state(); | 600 PrefService* local_state = g_browser_process->local_state(); |
575 if (local_state) { | 601 if (local_state) { |
576 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); | 602 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); |
577 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, | 603 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, |
578 base::Time::Now().ToInternalValue()); | 604 base::Time::Now().ToInternalValue()); |
605 if (logging_enabled) { | |
606 local_state->SetInt64(prefs::kSwReporterLastTimeSentReport, | |
csharp
2016/08/30 13:39:08
I wonder if this should be set right before the re
ftirelo
2016/08/30 21:21:49
Done.
| |
607 base::Time::Now().ToInternalValue()); | |
608 } | |
579 } | 609 } |
580 uma.ReportRuntime(reporter_running_time); | 610 uma.ReportRuntime(reporter_running_time); |
581 uma.ReportScanTimes(); | 611 uma.ReportScanTimes(); |
582 uma.ReportMemoryUsage(); | 612 uma.ReportMemoryUsage(); |
583 | 613 |
584 if (!IsInSRTPromptFieldTrialGroups()) { | 614 if (!IsInSRTPromptFieldTrialGroups()) { |
585 // Knowing about disabled field trial is more important than reporter not | 615 // Knowing about disabled field trial is more important than reporter not |
586 // finding anything to remove, so check this case first. | 616 // finding anything to remove, so check this case first. |
587 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); | 617 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); |
588 return; | 618 return; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
632 last_time_triggered + | 662 last_time_triggered + |
633 base::TimeDelta::FromDays(days_between_reporter_runs_) - | 663 base::TimeDelta::FromDays(days_between_reporter_runs_) - |
634 base::Time::Now()); | 664 base::Time::Now()); |
635 if (next_trigger_delay.ToInternalValue() <= 0 || | 665 if (next_trigger_delay.ToInternalValue() <= 0 || |
636 // Also make sure the kSwReporterLastTimeTriggered value is not set in | 666 // Also make sure the kSwReporterLastTimeTriggered value is not set in |
637 // the future. | 667 // the future. |
638 last_time_triggered > base::Time::Now()) { | 668 last_time_triggered > base::Time::Now()) { |
639 if (g_testing_delegate_) | 669 if (g_testing_delegate_) |
640 g_testing_delegate_->NotifyLaunchReady(); | 670 g_testing_delegate_->NotifyLaunchReady(); |
641 | 671 |
672 // Creating a new invocation to add switches for users who opted into | |
csharp
2016/08/30 13:39:08
Could you add some tests for this?
ftirelo
2016/08/30 21:21:49
Done.
| |
673 // extended Safe Browsing reporting. The invocation object is changed | |
674 // locally right before the actual process is launched because user status | |
675 // can between this and the next run for this ReporterRunner object. For | |
676 // example, the ReporterDone() callback schedules the next run for a few | |
677 // days later, and the user might have changed settings in the meantime. | |
678 SwReporterInvocation actual_invocation = | |
csharp
2016/08/30 13:39:08
I think you want to create a copy constructor and
ftirelo
2016/08/30 21:21:49
Done.
| |
679 SwReporterInvocation::FromCommandLine(invocation_.command_line); | |
680 bool logging_enabled = ShouldSendReporterLogs(*local_state); | |
681 if (logging_enabled) | |
682 AddSwitchesForExtendedReporterUser(&actual_invocation); | |
683 | |
642 // It's OK to simply |PostTaskAndReplyWithResult| so that | 684 // It's OK to simply |PostTaskAndReplyWithResult| so that |
643 // |LaunchAndWaitForExit| doesn't need to access | 685 // |LaunchAndWaitForExit| doesn't need to access |
644 // |main_thread_task_runner_| since the callback is not delayed and the | 686 // |main_thread_task_runner_| since the callback is not delayed and the |
645 // test task runner won't need to force it. | 687 // test task runner won't need to force it. |
646 base::PostTaskAndReplyWithResult( | 688 base::PostTaskAndReplyWithResult( |
647 blocking_task_runner_.get(), FROM_HERE, | 689 blocking_task_runner_.get(), FROM_HERE, |
648 base::Bind(&LaunchAndWaitForExit, invocation_), | 690 base::Bind(&LaunchAndWaitForExit, actual_invocation), |
649 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), | 691 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), |
650 base::Time::Now(), version_)); | 692 base::Time::Now(), version_, logging_enabled)); |
651 } else { | 693 } else { |
652 main_thread_task_runner_->PostDelayedTask( | 694 main_thread_task_runner_->PostDelayedTask( |
653 FROM_HERE, | 695 FROM_HERE, |
654 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 696 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
655 next_trigger_delay); | 697 next_trigger_delay); |
656 } | 698 } |
657 } | 699 } |
658 | 700 |
701 // Returns true if the experiment to send reporter logs is enabled, the user | |
702 // opted into Safe Browsing extended reporting, and logs have been sent at | |
703 // least |kSwReporterLastTimeSentReport| days ago. | |
704 bool ShouldSendReporterLogs(const PrefService& local_state) { | |
705 if (!base::FeatureList::IsEnabled(kSwReporterExtendedSafeBrowsingFeature) || | |
706 !SafeBrowsingExtendedReportingEnabled()) { | |
707 return false; | |
708 } | |
709 | |
710 const base::Time now = base::Time::Now(); | |
711 const base::Time last_time_sent_logs = base::Time::FromInternalValue( | |
712 local_state.GetInt64(prefs::kSwReporterLastTimeSentReport)); | |
713 // Send the logs if the last send was in the future. | |
csharp
2016/08/30 13:39:08
nit: Could you explain why we care about this a bi
ftirelo
2016/08/30 21:21:49
Done.
| |
714 if (last_time_sent_logs > now) | |
715 return true; | |
716 // Otherwise, send them if the interval has passed. | |
717 return last_time_sent_logs + | |
718 base::TimeDelta::FromDays(kDaysBetweenReporterLogsSent) <= | |
719 now; | |
720 } | |
721 | |
722 void AddSwitchesForExtendedReporterUser(SwReporterInvocation* invocation) { | |
723 invocation->command_line.AppendSwitch(kExtendedSafeBrowsingEnabledSwitch); | |
724 invocation->command_line.AppendSwitchASCII( | |
725 kChromeVersionSwitch, version_info::GetVersionNumber()); | |
726 invocation->command_line.AppendSwitchNative( | |
727 kChromeChannelSwitch, base::IntToString16(ChannelAsInt())); | |
728 } | |
729 | |
659 bool first_run_ = true; | 730 bool first_run_ = true; |
660 SwReporterInvocation invocation_; | 731 SwReporterInvocation invocation_; |
661 base::Version version_; | 732 base::Version version_; |
662 scoped_refptr<base::TaskRunner> main_thread_task_runner_; | 733 scoped_refptr<base::TaskRunner> main_thread_task_runner_; |
663 scoped_refptr<base::TaskRunner> blocking_task_runner_; | 734 scoped_refptr<base::TaskRunner> blocking_task_runner_; |
664 | 735 |
665 // This value is used to identify how long to wait before starting a new run | 736 // This value is used to identify how long to wait before starting a new run |
666 // of the reporter. It's initialized with the default value and may be changed | 737 // of the reporter. It's initialized with the default value and may be changed |
667 // to a different value when a prompt is pending and the reporter should be | 738 // to a different value when a prompt is pending and the reporter should be |
668 // run before adding the global error to the Chrome menu. | 739 // run before adding the global error to the Chrome menu. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
723 KEY_QUERY_VALUE); | 794 KEY_QUERY_VALUE); |
724 | 795 |
725 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; | 796 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; |
726 } | 797 } |
727 | 798 |
728 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { | 799 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { |
729 g_testing_delegate_ = delegate; | 800 g_testing_delegate_ = delegate; |
730 } | 801 } |
731 | 802 |
732 } // namespace safe_browsing | 803 } // namespace safe_browsing |
OLD | NEW |