Index: chrome/browser/safe_browsing/srt_fetcher_win.cc |
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc |
deleted file mode 100644 |
index b786599300c8642bfc8635e6b39879dec106da6f..0000000000000000000000000000000000000000 |
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc |
+++ /dev/null |
@@ -1,1254 +0,0 @@ |
-// Copyright 2015 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/safe_browsing/srt_fetcher_win.h" |
- |
-#include <stdint.h> |
- |
-#include <algorithm> |
-#include <memory> |
-#include <utility> |
-#include <vector> |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/callback_helpers.h" |
-#include "base/command_line.h" |
-#include "base/debug/leak_annotations.h" |
-#include "base/files/file_path.h" |
-#include "base/macros.h" |
-#include "base/memory/ptr_util.h" |
-#include "base/metrics/field_trial.h" |
-#include "base/metrics/histogram_macros.h" |
-#include "base/metrics/sparse_histogram.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/task_runner_util.h" |
-#include "base/task_scheduler/post_task.h" |
-#include "base/task_scheduler/task_traits.h" |
-#include "base/time/time.h" |
-#include "base/version.h" |
-#include "base/win/registry.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/metrics/chrome_metrics_service_accessor.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/profiles/profile_io_data.h" |
-#include "chrome/browser/safe_browsing/srt_chrome_prompt_impl.h" |
-#include "chrome/browser/safe_browsing/srt_client_info_win.h" |
-#include "chrome/browser/safe_browsing/srt_global_error_win.h" |
-#include "chrome/browser/ui/browser_finder.h" |
-#include "chrome/browser/ui/browser_list.h" |
-#include "chrome/browser/ui/browser_list_observer.h" |
-#include "chrome/browser/ui/global_error/global_error_service.h" |
-#include "chrome/browser/ui/global_error/global_error_service_factory.h" |
-#include "chrome/common/pref_names.h" |
-#include "components/chrome_cleaner/public/constants/constants.h" |
-#include "components/component_updater/pref_names.h" |
-#include "components/data_use_measurement/core/data_use_user_data.h" |
-#include "components/prefs/pref_service.h" |
-#include "components/variations/net/variations_http_headers.h" |
-#include "components/version_info/version_info.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "mojo/edk/embedder/connection_params.h" |
-#include "mojo/edk/embedder/pending_process_connection.h" |
-#include "mojo/edk/embedder/platform_channel_pair.h" |
-#include "mojo/public/cpp/system/message_pipe.h" |
-#include "net/base/load_flags.h" |
-#include "net/http/http_status_code.h" |
-#include "net/url_request/url_fetcher.h" |
-#include "net/url_request/url_fetcher_delegate.h" |
-#include "net/url_request/url_request_context_getter.h" |
- |
-using content::BrowserThread; |
- |
-namespace safe_browsing { |
- |
-const base::Feature kInBrowserCleanerUIFeature{ |
- "InBrowserCleanerUI", base::FEATURE_DISABLED_BY_DEFAULT}; |
- |
-namespace { |
- |
-// Used to send UMA information about missing start and end time registry |
-// values for the reporter. Replicated in the histograms.xml file, so the order |
-// MUST NOT CHANGE. |
-enum SwReporterRunningTimeRegistryError { |
- REPORTER_RUNNING_TIME_ERROR_NO_ERROR = 0, |
- REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID = 1, |
- REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME = 2, |
- REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME = 3, |
- REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES = 4, |
- REPORTER_RUNNING_TIME_ERROR_MAX, |
-}; |
- |
-// Used to send UMA information about the progress of the SwReporter launch and |
-// prompt sequence. Replicated in the histograms.xml file, so the order MUST |
-// NOT CHANGE. |
-enum SwReporterUmaValue { |
- // Deprecated. |
- SW_REPORTER_EXPLICIT_REQUEST = 0, |
- // Deprecated. |
- SW_REPORTER_STARTUP_RETRY = 1, |
- // Deprecated. |
- SW_REPORTER_RETRIED_TOO_MANY_TIMES = 2, |
- SW_REPORTER_START_EXECUTION = 3, |
- SW_REPORTER_FAILED_TO_START = 4, |
- // Deprecated. |
- SW_REPORTER_REGISTRY_EXIT_CODE = 5, |
- // Deprecated. |
- SW_REPORTER_RESET_RETRIES = 6, |
- SW_REPORTER_DOWNLOAD_START = 7, |
- SW_REPORTER_NO_BROWSER = 8, |
- SW_REPORTER_NO_LOCAL_STATE = 9, |
- SW_REPORTER_NO_PROMPT_NEEDED = 10, |
- SW_REPORTER_NO_PROMPT_FIELD_TRIAL = 11, |
- SW_REPORTER_ALREADY_PROMPTED = 12, |
- SW_REPORTER_RAN_DAILY = 13, |
- SW_REPORTER_ADDED_TO_MENU = 14, |
- |
- SW_REPORTER_MAX, |
-}; |
- |
-// Used to send UMA information showing whether uploading of Software Reporter |
-// logs is enabled, or the reason why not. |
-// Replicated in the histograms.xml file, so the order MUST NOT CHANGE. |
-enum SwReporterLogsUploadsEnabled { |
- REPORTER_LOGS_UPLOADS_ENABLED = 0, |
- REPORTER_LOGS_UPLOADS_SBER_DISABLED = 1, |
- REPORTER_LOGS_UPLOADS_RECENTLY_SENT_LOGS = 2, |
- REPORTER_LOGS_UPLOADS_MAX, |
-}; |
- |
-// Used to send UMA information about missing logs upload result in the registry |
-// for the reporter. Replicated in the histograms.xml file, so the order |
-// MUST NOT CHANGE. |
-enum SwReporterLogsUploadResultRegistryError { |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_NO_ERROR = 0, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_REGISTRY_KEY_INVALID = 1, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_NOT_FOUND = 2, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_OUT_OF_BOUNDS = 3, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX, |
-}; |
- |
-const char kRunningTimeErrorMetricName[] = |
- "SoftwareReporter.RunningTimeRegistryError"; |
- |
-SwReporterTestingDelegate* g_testing_delegate_ = nullptr; |
- |
-const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; |
-const char kFoundUwsReadErrorMetricName[] = |
- "SoftwareReporter.FoundUwSReadError"; |
-const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; |
-const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; |
-const char kStepMetricName[] = "SoftwareReporter.Step"; |
-const char kLogsUploadEnabledMetricName[] = |
- "SoftwareReporter.LogsUploadEnabled"; |
-const char kLogsUploadResultMetricName[] = "SoftwareReporter.LogsUploadResult"; |
-const char kLogsUploadResultRegistryErrorMetricName[] = |
- "SoftwareReporter.LogsUploadResultRegistryError"; |
-const char kExitCodeMetricName[] = "SoftwareReporter.ExitCodeFromRegistry"; |
-const char kEngineErrorCodeMetricName[] = "SoftwareReporter.EngineErrorCode"; |
- |
-// The max value for histogram SoftwareReporter.LogsUploadResult, which is used |
-// to send UMA information about the result of Software Reporter's attempt to |
-// upload logs, when logs are enabled. This value must be consistent with the |
-// SoftwareReporterLogsUploadResult enum defined in the histograms.xml file. |
-const int kSwReporterLogsUploadResultMax = 30; |
- |
-// Reports metrics about the software reporter via UMA (and sometimes Rappor). |
-class UMAHistogramReporter { |
- public: |
- UMAHistogramReporter() : UMAHistogramReporter(std::string()) {} |
- |
- explicit UMAHistogramReporter(const std::string& suffix) |
- : suffix_(suffix), |
- registry_key_(suffix.empty() |
- ? chrome_cleaner::kSoftwareRemovalToolRegistryKey |
- : base::StringPrintf( |
- L"%ls\\%ls", |
- chrome_cleaner::kSoftwareRemovalToolRegistryKey, |
- base::UTF8ToUTF16(suffix).c_str())) {} |
- |
- // Reports the software reporter tool's version via UMA. |
- void ReportVersion(const base::Version& version) const { |
- DCHECK(!version.components().empty()); |
- // The minor version is the 2nd last component of the version, |
- // or just the first component if there is only 1. |
- uint32_t minor_version = 0; |
- if (version.components().size() > 1) |
- minor_version = version.components()[version.components().size() - 2]; |
- else |
- minor_version = version.components()[0]; |
- RecordSparseHistogram("SoftwareReporter.MinorVersion", minor_version); |
- |
- // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional |
- // components, only the first three count, and if there are less than 3, the |
- // missing values are just replaced by zero. So 1 is equivalent 1.0.0. |
- DCHECK_LT(version.components()[0], 0x100U); |
- uint32_t major_version = 0x1000000 * version.components()[0]; |
- if (version.components().size() >= 2) { |
- DCHECK_LT(version.components()[1], 0x10000U); |
- major_version += 0x100 * version.components()[1]; |
- } |
- if (version.components().size() >= 3) { |
- DCHECK_LT(version.components()[2], 0x100U); |
- major_version += version.components()[2]; |
- } |
- RecordSparseHistogram("SoftwareReporter.MajorVersion", major_version); |
- } |
- |
- void ReportExitCode(int exit_code) const { |
- RecordSparseHistogram("SoftwareReporter.ExitCode", exit_code); |
- |
- // Also report the exit code that the reporter writes to the registry. |
- base::win::RegKey reporter_key; |
- DWORD exit_code_in_registry; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS || |
- reporter_key.ReadValueDW(chrome_cleaner::kExitCodeValueName, |
- &exit_code_in_registry) != ERROR_SUCCESS) { |
- return; |
- } |
- |
- RecordSparseHistogram(kExitCodeMetricName, exit_code_in_registry); |
- reporter_key.DeleteValue(chrome_cleaner::kExitCodeValueName); |
- } |
- |
- void ReportEngineErrorCode() const { |
- base::win::RegKey reporter_key; |
- DWORD engine_error_code; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS || |
- reporter_key.ReadValueDW(chrome_cleaner::kEngineErrorCodeValueName, |
- &engine_error_code) != ERROR_SUCCESS) { |
- return; |
- } |
- |
- RecordSparseHistogram(kEngineErrorCodeMetricName, engine_error_code); |
- reporter_key.DeleteValue(chrome_cleaner::kEngineErrorCodeValueName); |
- } |
- |
- // Reports UwS found by the software reporter tool via UMA and RAPPOR. |
- void ReportFoundUwS() const { |
- base::win::RegKey reporter_key; |
- std::vector<base::string16> found_uws_strings; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS || |
- reporter_key.ReadValues(chrome_cleaner::kFoundUwsValueName, |
- &found_uws_strings) != ERROR_SUCCESS) { |
- return; |
- } |
- |
- bool parse_error = false; |
- for (const base::string16& uws_string : found_uws_strings) { |
- // All UwS ids are expected to be integers. |
- uint32_t uws_id = 0; |
- if (base::StringToUint(uws_string, &uws_id)) { |
- RecordSparseHistogram(kFoundUwsMetricName, uws_id); |
- } else { |
- parse_error = true; |
- } |
- } |
- |
- // Clean up the old value. |
- reporter_key.DeleteValue(chrome_cleaner::kFoundUwsValueName); |
- RecordBooleanHistogram(kFoundUwsReadErrorMetricName, parse_error); |
- } |
- |
- // Reports to UMA the memory usage of the software reporter tool as reported |
- // by the tool itself in the Windows registry. |
- void ReportMemoryUsage() const { |
- base::win::RegKey reporter_key; |
- DWORD memory_used = 0; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS || |
- reporter_key.ReadValueDW(chrome_cleaner::kMemoryUsedValueName, |
- &memory_used) != ERROR_SUCCESS) { |
- return; |
- } |
- RecordMemoryKBHistogram(kMemoryUsedMetricName, memory_used); |
- reporter_key.DeleteValue(chrome_cleaner::kMemoryUsedValueName); |
- } |
- |
- // Reports the SwReporter run time with UMA both as reported by the tool via |
- // the registry and as measured by |ReporterRunner|. |
- void ReportRuntime(const base::TimeDelta& reporter_running_time) const { |
- RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome", |
- reporter_running_time); |
- |
- // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE. |
- base::win::RegKey reporter_key; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_ALL_ACCESS) != ERROR_SUCCESS) { |
- RecordEnumerationHistogram( |
- kRunningTimeErrorMetricName, |
- REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID, |
- REPORTER_RUNNING_TIME_ERROR_MAX); |
- return; |
- } |
- |
- bool has_start_time = false; |
- int64_t start_time_value = 0; |
- if (reporter_key.HasValue(chrome_cleaner::kStartTimeValueName) && |
- reporter_key.ReadInt64(chrome_cleaner::kStartTimeValueName, |
- &start_time_value) == ERROR_SUCCESS) { |
- has_start_time = true; |
- reporter_key.DeleteValue(chrome_cleaner::kStartTimeValueName); |
- } |
- |
- bool has_end_time = false; |
- int64_t end_time_value = 0; |
- if (reporter_key.HasValue(chrome_cleaner::kEndTimeValueName) && |
- reporter_key.ReadInt64(chrome_cleaner::kEndTimeValueName, |
- &end_time_value) == ERROR_SUCCESS) { |
- has_end_time = true; |
- reporter_key.DeleteValue(chrome_cleaner::kEndTimeValueName); |
- } |
- |
- if (has_start_time && has_end_time) { |
- base::TimeDelta registry_run_time = |
- base::Time::FromInternalValue(end_time_value) - |
- base::Time::FromInternalValue(start_time_value); |
- RecordLongTimesHistogram("SoftwareReporter.RunningTime", |
- registry_run_time); |
- RecordEnumerationHistogram(kRunningTimeErrorMetricName, |
- REPORTER_RUNNING_TIME_ERROR_NO_ERROR, |
- REPORTER_RUNNING_TIME_ERROR_MAX); |
- } else if (!has_start_time && !has_end_time) { |
- RecordEnumerationHistogram(kRunningTimeErrorMetricName, |
- REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES, |
- REPORTER_RUNNING_TIME_ERROR_MAX); |
- } else if (!has_start_time) { |
- RecordEnumerationHistogram(kRunningTimeErrorMetricName, |
- REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME, |
- REPORTER_RUNNING_TIME_ERROR_MAX); |
- } else { |
- DCHECK(!has_end_time); |
- RecordEnumerationHistogram(kRunningTimeErrorMetricName, |
- REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME, |
- REPORTER_RUNNING_TIME_ERROR_MAX); |
- } |
- } |
- |
- // Reports the UwS scan times of the software reporter tool via UMA. |
- void ReportScanTimes() const { |
- base::string16 scan_times_key_path = base::StringPrintf( |
- L"%ls\\%ls", registry_key_.c_str(), chrome_cleaner::kScanTimesSubKey); |
- // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE. |
- base::win::RegKey scan_times_key; |
- if (scan_times_key.Open(HKEY_CURRENT_USER, scan_times_key_path.c_str(), |
- KEY_ALL_ACCESS) != ERROR_SUCCESS) { |
- return; |
- } |
- |
- base::string16 value_name; |
- int uws_id = 0; |
- int64_t raw_scan_time = 0; |
- int num_scan_times = scan_times_key.GetValueCount(); |
- for (int i = 0; i < num_scan_times; ++i) { |
- if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS && |
- base::StringToInt(value_name, &uws_id) && |
- scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) == |
- ERROR_SUCCESS) { |
- base::TimeDelta scan_time = |
- base::TimeDelta::FromInternalValue(raw_scan_time); |
- // We report the number of seconds plus one because it can take less |
- // than one second to scan some UwS and the count passed to |AddCount| |
- // must be at least one. |
- RecordSparseHistogramCount(kScanTimesMetricName, uws_id, |
- scan_time.InSeconds() + 1); |
- } |
- } |
- // Clean up by deleting the scan times key, which is a subkey of the main |
- // reporter key. |
- scan_times_key.Close(); |
- base::win::RegKey reporter_key; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_ENUMERATE_SUB_KEYS) == ERROR_SUCCESS) { |
- reporter_key.DeleteKey(chrome_cleaner::kScanTimesSubKey); |
- } |
- } |
- |
- void RecordReporterStep(SwReporterUmaValue value) { |
- RecordEnumerationHistogram(kStepMetricName, value, SW_REPORTER_MAX); |
- } |
- |
- void RecordLogsUploadEnabled(SwReporterLogsUploadsEnabled value) { |
- RecordEnumerationHistogram(kLogsUploadEnabledMetricName, value, |
- REPORTER_LOGS_UPLOADS_MAX); |
- } |
- |
- void RecordLogsUploadResult() { |
- base::win::RegKey reporter_key; |
- DWORD logs_upload_result = 0; |
- if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(), |
- KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS) { |
- RecordEnumerationHistogram( |
- kLogsUploadResultRegistryErrorMetricName, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_REGISTRY_KEY_INVALID, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX); |
- return; |
- } |
- |
- if (reporter_key.ReadValueDW(chrome_cleaner::kLogsUploadResultValueName, |
- &logs_upload_result) != ERROR_SUCCESS) { |
- RecordEnumerationHistogram( |
- kLogsUploadResultRegistryErrorMetricName, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_NOT_FOUND, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX); |
- return; |
- } |
- |
- if (logs_upload_result >= kSwReporterLogsUploadResultMax) { |
- RecordEnumerationHistogram( |
- kLogsUploadResultRegistryErrorMetricName, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_OUT_OF_BOUNDS, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX); |
- return; |
- } |
- |
- RecordEnumerationHistogram(kLogsUploadResultMetricName, |
- static_cast<Sample>(logs_upload_result), |
- kSwReporterLogsUploadResultMax); |
- reporter_key.DeleteValue(chrome_cleaner::kLogsUploadResultValueName); |
- RecordEnumerationHistogram(kLogsUploadResultRegistryErrorMetricName, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_NO_ERROR, |
- REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX); |
- } |
- |
- private: |
- using Sample = base::HistogramBase::Sample; |
- |
- static constexpr base::HistogramBase::Flags kUmaHistogramFlag = |
- base::HistogramBase::kUmaTargetedHistogramFlag; |
- |
- // Helper functions to record histograms with an optional suffix added to the |
- // histogram name. The UMA_HISTOGRAM macros can't be used because they |
- // require a constant string. |
- |
- std::string FullName(const std::string& name) const { |
- if (suffix_.empty()) |
- return name; |
- return base::StringPrintf("%s_%s", name.c_str(), suffix_.c_str()); |
- } |
- |
- void RecordBooleanHistogram(const std::string& name, bool sample) const { |
- auto* histogram = |
- base::BooleanHistogram::FactoryGet(FullName(name), kUmaHistogramFlag); |
- if (histogram) |
- histogram->AddBoolean(sample); |
- } |
- |
- void RecordEnumerationHistogram(const std::string& name, |
- Sample sample, |
- Sample boundary) const { |
- // See HISTOGRAM_ENUMERATION_WITH_FLAG for the parameters to |FactoryGet|. |
- auto* histogram = base::LinearHistogram::FactoryGet( |
- FullName(name), 1, boundary, boundary + 1, kUmaHistogramFlag); |
- if (histogram) |
- histogram->Add(sample); |
- } |
- |
- void RecordLongTimesHistogram(const std::string& name, |
- const base::TimeDelta& sample) const { |
- // See UMA_HISTOGRAM_LONG_TIMES for the parameters to |FactoryTimeGet|. |
- auto* histogram = base::Histogram::FactoryTimeGet( |
- FullName(name), base::TimeDelta::FromMilliseconds(1), |
- base::TimeDelta::FromHours(1), 100, kUmaHistogramFlag); |
- if (histogram) |
- histogram->AddTime(sample); |
- } |
- |
- void RecordMemoryKBHistogram(const std::string& name, Sample sample) const { |
- // See UMA_HISTOGRAM_MEMORY_KB for the parameters to |FactoryGet|. |
- auto* histogram = base::Histogram::FactoryGet(FullName(name), 1000, 500000, |
- 50, kUmaHistogramFlag); |
- if (histogram) |
- histogram->Add(sample); |
- } |
- |
- void RecordSparseHistogram(const std::string& name, Sample sample) const { |
- auto* histogram = |
- base::SparseHistogram::FactoryGet(FullName(name), kUmaHistogramFlag); |
- if (histogram) |
- histogram->Add(sample); |
- } |
- |
- void RecordSparseHistogramCount(const std::string& name, |
- Sample sample, |
- int count) const { |
- auto* histogram = |
- base::SparseHistogram::FactoryGet(FullName(name), kUmaHistogramFlag); |
- if (histogram) |
- histogram->AddCount(sample, count); |
- } |
- |
- const std::string suffix_; |
- const std::wstring registry_key_; |
-}; |
- |
-// Records the reporter step without a suffix. (For steps that are never run by |
-// the experimental reporter.) |
-void RecordReporterStepHistogram(SwReporterUmaValue value) { |
- UMAHistogramReporter uma; |
- uma.RecordReporterStep(value); |
-} |
- |
-void DisplaySRTPrompt(const base::FilePath& download_path) { |
- // Find the last active browser, which may be NULL, in which case we won't |
- // show the prompt this time and will wait until the next run of the |
- // reporter. We can't use other ways of finding a browser because we don't |
- // have a profile. |
- Browser* browser = chrome::FindLastActive(); |
- if (!browser) |
- return; |
- |
- Profile* profile = browser->profile(); |
- DCHECK(profile); |
- |
- // Make sure we have a tabbed browser since we need to anchor the bubble to |
- // the toolbar's wrench menu. Create one if none exist already. |
- if (browser->type() != Browser::TYPE_TABBED) { |
- browser = chrome::FindTabbedBrowser(profile, false); |
- if (!browser) |
- browser = new Browser(Browser::CreateParams(profile, false)); |
- } |
- GlobalErrorService* global_error_service = |
- GlobalErrorServiceFactory::GetForProfile(profile); |
- SRTGlobalError* global_error = |
- new SRTGlobalError(global_error_service, download_path); |
- |
- // Ownership of |global_error| is passed to the service. The error removes |
- // itself from the service and self-destructs when done. |
- global_error_service->AddGlobalError(base::WrapUnique(global_error)); |
- |
- bool show_bubble = true; |
- PrefService* local_state = g_browser_process->local_state(); |
- if (local_state && local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { |
- // Don't show the bubble if there's already a pending prompt to only be |
- // sown in the Chrome menu. |
- RecordReporterStepHistogram(SW_REPORTER_ADDED_TO_MENU); |
- show_bubble = false; |
- } else { |
- // Do not try to show bubble if another GlobalError is already showing |
- // one. The bubble will be shown once the others have been dismissed. |
- for (GlobalError* error : global_error_service->errors()) { |
- if (error->GetBubbleView()) { |
- show_bubble = false; |
- break; |
- } |
- } |
- } |
- if (show_bubble) |
- global_error->ShowBubbleView(browser); |
-} |
- |
-// Handles the case when the remote end has been closed, by performing the |
-// necessary cleanups if the prompt dialog is being shown to the user. |
-void OnConnectionClosed() { |
- // Placeholder. This should handle cases when the reporter process is |
- // disconnected (e.g. due to a crash) and the prompt dialog is being shown |
- // to the user. |
-} |
- |
-// Handles the case when a mojo::ReportBadMessage has been explicitly reported. |
-void OnConnectionError(const std::string& message) { |
- // Placeholder. This should handle cases when the reporter process sends |
- // a bad message and the prompt dialog is being shown to the user. |
-} |
- |
-// Class responsible for launching the reporter process and waiting for its |
-// completion. If feature InBrowserCleanerUI is enabled, this object will also |
-// be responsible for starting the ChromePromptImpl object on the IO thread and |
-// controlling its lifetime. |
-// |
-// Expected lifecycle of a SwReporterProcess: |
-// - created on the UI thread before the reporter process launch is posted |
-// (method ScheduleNextInvocation); |
-// - deleted on the UI thread once ReporterDone() finishes (the method is |
-// called after the reporter process exits). |
-// |
-// If feature InBrowserCleanerUI feature is enabled, the following tasks will |
-// be posted in sequence to the IO Thread and will retain the SwReporterProcess |
-// object: |
-// - creation of a ChromePromptImpl object right after the reporter process is |
-// launched (that object will be responsible for handling IPC requests from |
-// the reporter process); |
-// - deletion of the ChromePromptImpl object on ReporterDone(). |
-// As a consequence, the SwReporterProcess object can outlive ReporterDone() |
-// and will only be deleted after the ChromePromptImpl object is released on |
-// the IO thread. |
-class SwReporterProcess : public base::RefCountedThreadSafe<SwReporterProcess> { |
- public: |
- explicit SwReporterProcess(const SwReporterInvocation& invocation) |
- : invocation_(invocation) {} |
- |
- // This function is called from a worker thread to launch the SwReporter and |
- // wait for termination to collect its exit code. This task could be |
- // interrupted by a shutdown at any time, so it shouldn't depend on anything |
- // external that could be shut down beforehand. |
- int LaunchAndWaitForExitOnBackgroundThread(); |
- |
- // Schedules to release the instance of ChromePromptImpl on the IO thread. |
- void OnReporterDone(); |
- |
- const SwReporterInvocation& invocation() const { return invocation_; } |
- |
- private: |
- friend class base::RefCountedThreadSafe<SwReporterProcess>; |
- ~SwReporterProcess() = default; |
- |
- // Starts a new IPC service implementing the ChromePrompt interface and |
- // launches a new reporter process that can connect to the IPC. |
- base::Process LaunchConnectedReporterProcess(); |
- |
- // Starts a new instance of ChromePromptImpl to receive requests from the |
- // reporter and establishes the mojo connection to it. |
- // Must be run on the IO thread. |
- void CreateChromePromptImpl( |
- chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request); |
- |
- // Releases the instance of ChromePromptImpl. Must be run on the IO thread. |
- void ReleaseChromePromptImpl(); |
- |
- // Launches a new process with the command line in the invocation and |
- // provided launch options. Uses g_testing_delegate_ if not null. |
- base::Process LaunchReporterProcess( |
- const SwReporterInvocation& invocation, |
- const base::LaunchOptions& launch_options); |
- |
- // The invocation for the current reporter process. |
- SwReporterInvocation invocation_; |
- |
- // Implementation of the ChromePrompt service to be used by the current |
- // reporter process. Can only be accessed on the IO thread. |
- std::unique_ptr<ChromePromptImpl> chrome_prompt_impl_; |
-}; |
- |
-int SwReporterProcess::LaunchAndWaitForExitOnBackgroundThread() { |
- base::Process reporter_process = |
- base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature) |
- ? LaunchConnectedReporterProcess() |
- : LaunchReporterProcess(invocation_, base::LaunchOptions()); |
- |
- // This exit code is used to identify that a reporter run didn't happen, so |
- // the result should be ignored and a rerun scheduled for the usual delay. |
- int exit_code = kReporterNotLaunchedExitCode; |
- UMAHistogramReporter uma(invocation_.suffix); |
- if (reporter_process.IsValid()) { |
- uma.RecordReporterStep(SW_REPORTER_START_EXECUTION); |
- bool success = reporter_process.WaitForExit(&exit_code); |
- DCHECK(success); |
- } else { |
- uma.RecordReporterStep(SW_REPORTER_FAILED_TO_START); |
- } |
- return exit_code; |
-} |
- |
-void SwReporterProcess::OnReporterDone() { |
- if (base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)) { |
- BrowserThread::GetTaskRunnerForThread(BrowserThread::IO) |
- ->PostTask(FROM_HERE, |
- base::Bind(&SwReporterProcess::ReleaseChromePromptImpl, |
- base::RetainedRef(this))); |
- } |
-} |
- |
-base::Process SwReporterProcess::LaunchConnectedReporterProcess() { |
- DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)); |
- |
- mojo::edk::PendingProcessConnection pending_process_connection; |
- std::string mojo_pipe_token; |
- mojo::ScopedMessagePipeHandle mojo_pipe = |
- pending_process_connection.CreateMessagePipe(&mojo_pipe_token); |
- invocation_.command_line.AppendSwitchASCII( |
- chrome_cleaner::kChromeMojoPipeTokenSwitch, mojo_pipe_token); |
- invocation_.command_line.AppendSwitchASCII( |
- chrome_cleaner::kExecutionModeSwitch, |
- base::IntToString( |
- static_cast<int>(chrome_cleaner::ExecutionMode::kScanning))); |
- |
- mojo::edk::PlatformChannelPair channel; |
- base::HandlesToInheritVector handles_to_inherit; |
- channel.PrepareToPassClientHandleToChildProcess(&invocation_.command_line, |
- &handles_to_inherit); |
- |
- base::LaunchOptions launch_options; |
- launch_options.handles_to_inherit = &handles_to_inherit; |
- base::Process reporter_process = |
- LaunchReporterProcess(invocation_, launch_options); |
- |
- if (!reporter_process.IsValid()) |
- return reporter_process; |
- |
- chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request; |
- chrome_prompt_request.Bind(std::move(mojo_pipe)); |
- |
- // ChromePromptImpl tasks will need to run on the IO thread. There is no |
- // need to synchronize its creation, since the client end will wait for this |
- // initialization to be done before sending requests. |
- BrowserThread::GetTaskRunnerForThread(BrowserThread::IO) |
- ->PostTask(FROM_HERE, |
- base::BindOnce(&SwReporterProcess::CreateChromePromptImpl, |
- base::RetainedRef(this), |
- std::move(chrome_prompt_request))); |
- |
- mojo::edk::ProcessErrorCallback on_connection_error = |
- g_testing_delegate_ |
- ? base::Bind(&SwReporterTestingDelegate::OnConnectionError, |
- base::Unretained(g_testing_delegate_)) |
- : base::Bind(&OnConnectionError); |
- pending_process_connection.Connect( |
- reporter_process.Handle(), |
- mojo::edk::ConnectionParams(channel.PassServerHandle()), |
- on_connection_error); |
- |
- return reporter_process; |
-} |
- |
-base::Process SwReporterProcess::LaunchReporterProcess( |
- const SwReporterInvocation& invocation, |
- const base::LaunchOptions& launch_options) { |
- return g_testing_delegate_ |
- ? g_testing_delegate_->LaunchReporter(invocation, launch_options) |
- : base::LaunchProcess(invocation.command_line, launch_options); |
-} |
- |
-void SwReporterProcess::CreateChromePromptImpl( |
- chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)); |
- |
- chrome_prompt_impl_ = |
- g_testing_delegate_ |
- ? g_testing_delegate_->CreateChromePromptImpl( |
- std::move(chrome_prompt_request)) |
- : base::MakeUnique<ChromePromptImpl>(std::move(chrome_prompt_request), |
- base::Bind(&OnConnectionClosed)); |
-} |
- |
-void SwReporterProcess::ReleaseChromePromptImpl() { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)); |
- |
- chrome_prompt_impl_.release(); |
-} |
- |
-} // namespace |
- |
-void DisplaySRTPromptForTesting(const base::FilePath& download_path) { |
- DisplaySRTPrompt(download_path); |
-} |
- |
-// Class that will attempt to download the SRT, showing the SRT notification |
-// bubble when the download operation is complete. Instances of SRTFetcher own |
-// themselves, they will self-delete on completion of the network request when |
-// OnURLFetchComplete is called. |
-class SRTFetcher : public net::URLFetcherDelegate { |
- public: |
- explicit SRTFetcher(Profile* profile) |
- : profile_(profile), |
- url_fetcher_(net::URLFetcher::Create(0, |
- GURL(GetSRTDownloadURL()), |
- net::URLFetcher::GET, |
- this)) { |
- data_use_measurement::DataUseUserData::AttachToFetcher( |
- url_fetcher_.get(), |
- data_use_measurement::DataUseUserData::SAFE_BROWSING); |
- url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
- url_fetcher_->SetMaxRetriesOn5xx(3); |
- url_fetcher_->SaveResponseToTemporaryFile( |
- BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE)); |
- url_fetcher_->SetRequestContext( |
- g_browser_process->system_request_context()); |
- // Adds the UMA bit to the download request if the user is enrolled in UMA. |
- ProfileIOData* io_data = ProfileIOData::FromResourceContext( |
- profile_->GetResourceContext()); |
- net::HttpRequestHeaders headers; |
- // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does |
- // not affect transmission of experiments coming from the variations server. |
- bool is_signed_in = false; |
- variations::AppendVariationHeaders( |
- url_fetcher_->GetOriginalURL(), io_data->IsOffTheRecord(), |
- ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(), |
- is_signed_in, &headers); |
- url_fetcher_->SetExtraRequestHeaders(headers.ToString()); |
- url_fetcher_->Start(); |
- } |
- |
- // net::URLFetcherDelegate: |
- void OnURLFetchComplete(const net::URLFetcher* source) override { |
- // Take ownership of the fetcher in this scope (source == url_fetcher_). |
- DCHECK_EQ(url_fetcher_.get(), source); |
- |
- base::FilePath download_path; |
- if (source->GetStatus().is_success() && |
- source->GetResponseCode() == net::HTTP_OK) { |
- if (source->GetResponseAsFilePath(true, &download_path)) { |
- DCHECK(!download_path.empty()); |
- } |
- } |
- |
- // As long as the fetch didn't fail due to HTTP_NOT_FOUND, show a prompt |
- // (either offering the tool directly or pointing to the download page). |
- // If the fetch failed to find the file, don't prompt the user since the |
- // tool is not currently available. |
- // TODO(mad): Consider implementing another layer of retries / alternate |
- // fetching mechanisms. http://crbug.com/460293 |
- // TODO(mad): In the event the browser is closed before the prompt displays, |
- // we will wait until the next scanner run to re-display it. |
- // Improve this. http://crbug.com/460295 |
- if (source->GetResponseCode() != net::HTTP_NOT_FOUND) |
- DisplaySRTPrompt(download_path); |
- else |
- RecordSRTPromptHistogram(SRT_PROMPT_DOWNLOAD_UNAVAILABLE); |
- |
- // Explicitly destroy the url_fetcher_ to avoid destruction races. |
- url_fetcher_.reset(); |
- |
- // At this point, the url_fetcher_ is gone and this SRTFetcher instance is |
- // no longer needed. |
- delete this; |
- } |
- |
- private: |
- ~SRTFetcher() override {} |
- |
- // The user profile. |
- Profile* profile_; |
- |
- // The underlying URL fetcher. The instance is alive from construction through |
- // OnURLFetchComplete. |
- std::unique_ptr<net::URLFetcher> url_fetcher_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SRTFetcher); |
-}; |
- |
-namespace { |
- |
-// Try to fetch the SRT, and on success, show the prompt to run it. |
-void MaybeFetchSRT(Browser* browser, const base::Version& reporter_version) { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- |
- if (g_testing_delegate_) { |
- g_testing_delegate_->TriggerPrompt(browser, reporter_version.GetString()); |
- return; |
- } |
- Profile* profile = browser->profile(); |
- DCHECK(profile); |
- PrefService* prefs = profile->GetPrefs(); |
- DCHECK(prefs); |
- |
- // Don't show the prompt again if it's been shown before for this profile |
- // and for the current variations seed, unless there's a pending prompt to |
- // show in the Chrome menu. |
- std::string incoming_seed = GetIncomingSRTSeed(); |
- std::string old_seed = prefs->GetString(prefs::kSwReporterPromptSeed); |
- PrefService* local_state = g_browser_process->local_state(); |
- bool pending_prompt = |
- local_state && local_state->GetBoolean(prefs::kSwReporterPendingPrompt); |
- if (!incoming_seed.empty() && incoming_seed == old_seed && !pending_prompt) { |
- RecordReporterStepHistogram(SW_REPORTER_ALREADY_PROMPTED); |
- return; |
- } |
- |
- if (!incoming_seed.empty() && incoming_seed != old_seed) { |
- prefs->SetString(prefs::kSwReporterPromptSeed, incoming_seed); |
- // Forget about pending prompts if prompt seed has changed. |
- if (local_state) |
- local_state->SetBoolean(prefs::kSwReporterPendingPrompt, false); |
- } |
- prefs->SetString(prefs::kSwReporterPromptVersion, |
- reporter_version.GetString()); |
- |
- // Download the SRT. |
- RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); |
- |
- // All the work happens in the self-deleting class below. |
- new SRTFetcher(profile); |
-} |
- |
-base::Time Now() { |
- return g_testing_delegate_ ? g_testing_delegate_->Now() : base::Time::Now(); |
-} |
- |
-} // namespace |
- |
-// This class tries to run a queue of reporters and react to their exit codes. |
-// It schedules subsequent runs of the queue as needed, or retries as soon as a |
-// browser is available when none is on first try. |
-class ReporterRunner : public chrome::BrowserListObserver { |
- public: |
- // Registers |invocations| to run next time |TryToRun| is scheduled. (And if |
- // it's not already scheduled, call it now.) |
- static void ScheduleInvocations(const SwReporterQueue& invocations, |
- const base::Version& version) { |
- if (!instance_) { |
- instance_ = new ReporterRunner; |
- ANNOTATE_LEAKING_OBJECT_PTR(instance_); |
- } |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- |
- // There's nothing to do if the invocation parameters and version of the |
- // reporter have not changed, we just keep running the tasks that are |
- // running now. |
- if (instance_->pending_invocations_ == invocations && |
- instance_->version_.IsValid() && instance_->version_ == version) |
- return; |
- |
- instance_->pending_invocations_ = invocations; |
- instance_->version_ = version; |
- if (instance_->first_run_) { |
- instance_->first_run_ = false; |
- instance_->TryToRun(); |
- } |
- } |
- |
- private: |
- ReporterRunner() {} |
- ~ReporterRunner() override {} |
- |
- // BrowserListObserver. |
- void OnBrowserSetLastActive(Browser* browser) override {} |
- void OnBrowserRemoved(Browser* browser) override {} |
- void OnBrowserAdded(Browser* browser) override { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- DCHECK(browser); |
- MaybeFetchSRT(browser, version_); |
- BrowserList::RemoveObserver(this); |
- } |
- |
- // Launches the command line at the head of the queue. |
- void ScheduleNextInvocation() { |
- DCHECK(!current_invocations_.empty()); |
- auto next_invocation = current_invocations_.front(); |
- current_invocations_.pop(); |
- |
- AppendInvocationSpecificSwitches(&next_invocation); |
- |
- base::TaskRunner* task_runner = |
- g_testing_delegate_ ? g_testing_delegate_->BlockingTaskRunner() |
- : blocking_task_runner_.get(); |
- auto sw_reporter_process = |
- make_scoped_refptr(new SwReporterProcess(next_invocation)); |
- auto launch_and_wait = |
- base::Bind(&SwReporterProcess::LaunchAndWaitForExitOnBackgroundThread, |
- sw_reporter_process); |
- auto reporter_done = |
- base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), Now(), |
- version_, std::move(sw_reporter_process)); |
- base::PostTaskAndReplyWithResult(task_runner, FROM_HERE, |
- std::move(launch_and_wait), |
- std::move(reporter_done)); |
- } |
- |
- // This method is called on the UI thread when an invocation of the reporter |
- // has completed. This is run as a task posted from an interruptible worker |
- // thread so should be resilient to unexpected shutdown. |
- void ReporterDone(const base::Time& reporter_start_time, |
- const base::Version& version, |
- scoped_refptr<SwReporterProcess> sw_reporter_process, |
- int exit_code) { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- |
- sw_reporter_process->OnReporterDone(); |
- |
- base::Time now = Now(); |
- base::TimeDelta reporter_running_time = now - reporter_start_time; |
- |
- // Don't continue the current queue of reporters if one failed to launch. |
- if (exit_code == kReporterNotLaunchedExitCode) |
- current_invocations_ = SwReporterQueue(); |
- |
- // As soon as we're not running this queue, schedule the next overall queue |
- // run after the regular delay. (If there was a failure it's not worth |
- // retrying earlier, risking running too often if it always fails, since |
- // not many users fail here.) |
- if (current_invocations_.empty()) { |
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
- base::TimeDelta::FromDays(days_between_reporter_runs_)); |
- } else { |
- ScheduleNextInvocation(); |
- } |
- |
- // If the reporter failed to launch, do not process the results. (The exit |
- // code itself doesn't need to be logged in this case because |
- // SW_REPORTER_FAILED_TO_START is logged in |
- // |LaunchAndWaitForExitOnBackgroundThread|.) |
- if (exit_code == kReporterNotLaunchedExitCode) |
- return; |
- |
- const auto& finished_invocation = sw_reporter_process->invocation(); |
- UMAHistogramReporter uma(finished_invocation.suffix); |
- uma.ReportVersion(version); |
- uma.ReportExitCode(exit_code); |
- uma.ReportEngineErrorCode(); |
- uma.ReportFoundUwS(); |
- |
- PrefService* local_state = g_browser_process->local_state(); |
- if (local_state) { |
- if (finished_invocation.BehaviourIsSupported( |
- SwReporterInvocation::BEHAVIOUR_LOG_EXIT_CODE_TO_PREFS)) { |
- local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); |
- } |
- local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, |
- now.ToInternalValue()); |
- } |
- uma.ReportRuntime(reporter_running_time); |
- uma.ReportScanTimes(); |
- uma.ReportMemoryUsage(); |
- if (finished_invocation.logs_upload_enabled) |
- uma.RecordLogsUploadResult(); |
- |
- if (!finished_invocation.BehaviourIsSupported( |
- SwReporterInvocation::BEHAVIOUR_TRIGGER_PROMPT)) { |
- return; |
- } |
- |
- if (!IsInSRTPromptFieldTrialGroups()) { |
- // Knowing about disabled field trial is more important than reporter not |
- // finding anything to remove, so check this case first. |
- RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); |
- return; |
- } |
- |
- if (exit_code != chrome_cleaner::kSwReporterPostRebootCleanupNeeded && |
- exit_code != chrome_cleaner::kSwReporterCleanupNeeded) { |
- RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_NEEDED); |
- return; |
- } |
- |
- // Find the last active browser, which may be NULL, in which case we need |
- // to wait for one to be available. We can't use other ways of finding a |
- // browser because we don't have a profile. And we need a browser to get to |
- // a profile, which we need, to tell whether we should prompt or not. |
- // TODO(mad): crbug.com/503269, investigate whether we should change how we |
- // decide when it's time to download the SRT and when to display the prompt. |
- Browser* browser = chrome::FindLastActive(); |
- if (!browser) { |
- RecordReporterStepHistogram(SW_REPORTER_NO_BROWSER); |
- BrowserList::AddObserver(this); |
- } else { |
- MaybeFetchSRT(browser, version_); |
- } |
- } |
- |
- void TryToRun() { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- PrefService* local_state = g_browser_process->local_state(); |
- |
- if (!version_.IsValid() || !local_state) { |
- // TODO(b/641081): This doesn't look right. Even on first run, |version_| |
- // should be valid (and this is already checked in RunSwReporters). We |
- // should abort if local_state is missing, but this has nothing to do |
- // with |first_run_|. |
- DCHECK(first_run_); |
- return; |
- } |
- |
- // Run a queue of reporters if none have been triggered in the last |
- // |days_between_reporter_runs_| days, which depends if there is a pending |
- // prompt to be added to Chrome's menu. |
- if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { |
- days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; |
- RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); |
- } else { |
- days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
- } |
- const base::Time now = Now(); |
- const base::Time last_time_triggered = base::Time::FromInternalValue( |
- local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); |
- const base::Time next_trigger( |
- last_time_triggered + |
- base::TimeDelta::FromDays(days_between_reporter_runs_)); |
- if (!pending_invocations_.empty() && |
- (next_trigger <= now || |
- // Also make sure the kSwReporterLastTimeTriggered value is not set in |
- // the future. |
- last_time_triggered > now)) { |
- const base::Time last_time_sent_logs = base::Time::FromInternalValue( |
- local_state->GetInt64(prefs::kSwReporterLastTimeSentReport)); |
- const base::Time next_time_send_logs = |
- last_time_sent_logs + |
- base::TimeDelta::FromDays(kDaysBetweenReporterLogsSent); |
- // Send the logs for this whole queue of invocations if the last send is |
- // in the future or if logs have been sent at least |
- // |kSwReporterLastTimeSentReport| days ago. The former is intended as a |
- // measure for failure recovery, in case the time in local state is |
- // incorrectly set to the future. |
- in_logs_upload_period_ = |
- last_time_sent_logs > now || next_time_send_logs <= now; |
- |
- DCHECK(current_invocations_.empty()); |
- current_invocations_ = pending_invocations_; |
- ScheduleNextInvocation(); |
- } else { |
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
- next_trigger - now); |
- } |
- } |
- |
- // Returns true if the experiment to send reporter logs is enabled, the user |
- // opted into Safe Browsing extended reporting, and this queue of invocations |
- // started during the logs upload interval. |
- bool ShouldSendReporterLogs(const std::string& suffix, |
- const PrefService& local_state) { |
- UMAHistogramReporter uma(suffix); |
- if (!SafeBrowsingExtendedReportingEnabled()) { |
- uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_SBER_DISABLED); |
- return false; |
- } |
- if (!in_logs_upload_period_) { |
- uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_RECENTLY_SENT_LOGS); |
- return false; |
- } |
- uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_ENABLED); |
- return true; |
- } |
- |
- // Appends switches to the next invocation that depend on the user current |
- // state with respect to opting into extended Safe Browsing reporting and |
- // metrics and crash reporting. The invocation object is changed locally right |
- // before the actual process is launched because user status can change |
- // between this and the next run for this ReporterRunner object. For example, |
- // the ReporterDone() callback schedules the next run for a few days later, |
- // and the user might have changed settings in the meantime. |
- void AppendInvocationSpecificSwitches(SwReporterInvocation* next_invocation) { |
- // Add switches for users who opted into extended Safe Browsing reporting. |
- PrefService* local_state = g_browser_process->local_state(); |
- if (next_invocation->BehaviourIsSupported( |
- SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS) && |
- local_state && |
- ShouldSendReporterLogs(next_invocation->suffix, *local_state)) { |
- next_invocation->logs_upload_enabled = true; |
- AddSwitchesForExtendedReportingUser(next_invocation); |
- // Set the local state value before the first attempt to run the |
- // reporter, because we only want to upload logs once in the window |
- // defined by |kDaysBetweenReporterLogsSent|. If we set with other local |
- // state values after the reporter runs, we could send logs again too |
- // quickly (for example, if Chrome stops before the reporter finishes). |
- local_state->SetInt64(prefs::kSwReporterLastTimeSentReport, |
- Now().ToInternalValue()); |
- } |
- |
- if (ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled()) |
- next_invocation->command_line.AppendSwitch( |
- chrome_cleaner::kEnableCrashReportingSwitch); |
- } |
- |
- // Adds switches to be sent to the Software Reporter when the user opted into |
- // extended Safe Browsing reporting and is not incognito. |
- void AddSwitchesForExtendedReportingUser(SwReporterInvocation* invocation) { |
- invocation->command_line.AppendSwitch( |
- chrome_cleaner::kExtendedSafeBrowsingEnabledSwitch); |
- invocation->command_line.AppendSwitchASCII( |
- chrome_cleaner::kChromeVersionSwitch, version_info::GetVersionNumber()); |
- invocation->command_line.AppendSwitchNative( |
- chrome_cleaner::kChromeChannelSwitch, |
- base::IntToString16(ChannelAsInt())); |
- } |
- |
- bool first_run_ = true; |
- |
- // The queue of invocations that are currently running. |
- SwReporterQueue current_invocations_; |
- |
- // The invocations to run next time the SwReporter is run. |
- SwReporterQueue pending_invocations_; |
- |
- base::Version version_; |
- |
- scoped_refptr<base::TaskRunner> blocking_task_runner_ = |
- base::CreateTaskRunnerWithTraits( |
- // LaunchAndWaitForExitOnBackgroundThread() creates (MayBlock()) and |
- // joins (WithBaseSyncPrimitives()) a process. |
- base::TaskTraits() |
- .WithShutdownBehavior( |
- base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) |
- .WithPriority(base::TaskPriority::BACKGROUND) |
- .MayBlock() |
- .WithBaseSyncPrimitives()); |
- |
- // This value is used to identify how long to wait before starting a new run |
- // of the reporter queue. It's initialized with the default value and may be |
- // changed to a different value when a prompt is pending and the reporter |
- // should be run before adding the global error to the Chrome menu. |
- int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
- |
- // This will be true if the current queue of invocations started at a time |
- // when logs should be uploaded. |
- bool in_logs_upload_period_ = false; |
- |
- // A single leaky instance. |
- static ReporterRunner* instance_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ReporterRunner); |
-}; |
- |
-ReporterRunner* ReporterRunner::instance_ = nullptr; |
- |
-SwReporterInvocation::SwReporterInvocation() |
- : command_line(base::CommandLine::NO_PROGRAM) {} |
- |
-SwReporterInvocation SwReporterInvocation::FromFilePath( |
- const base::FilePath& exe_path) { |
- SwReporterInvocation invocation; |
- invocation.command_line = base::CommandLine(exe_path); |
- return invocation; |
-} |
- |
-SwReporterInvocation SwReporterInvocation::FromCommandLine( |
- const base::CommandLine& command_line) { |
- SwReporterInvocation invocation; |
- invocation.command_line = command_line; |
- return invocation; |
-} |
- |
-bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { |
- return command_line.argv() == other.command_line.argv() && |
- suffix == other.suffix && |
- supported_behaviours == other.supported_behaviours && |
- logs_upload_enabled == other.logs_upload_enabled; |
-} |
- |
-bool SwReporterInvocation::BehaviourIsSupported( |
- SwReporterInvocation::Behaviours intended_behaviour) const { |
- return (supported_behaviours & intended_behaviour) != 0; |
-} |
- |
-void RunSwReporters(const SwReporterQueue& invocations, |
- const base::Version& version) { |
- DCHECK(!invocations.empty()); |
- DCHECK(version.IsValid()); |
- ReporterRunner::ScheduleInvocations(invocations, version); |
-} |
- |
-bool ReporterFoundUws() { |
- PrefService* local_state = g_browser_process->local_state(); |
- if (!local_state) |
- return false; |
- int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); |
- return exit_code == chrome_cleaner::kSwReporterCleanupNeeded; |
-} |
- |
-bool UserHasRunCleaner() { |
- base::string16 cleaner_key_path( |
- chrome_cleaner::kSoftwareRemovalToolRegistryKey); |
- cleaner_key_path.append(L"\\").append(chrome_cleaner::kCleanerSubKey); |
- |
- base::win::RegKey srt_cleaner_key; |
- return srt_cleaner_key.Open(HKEY_CURRENT_USER, cleaner_key_path.c_str(), |
- KEY_QUERY_VALUE) == ERROR_SUCCESS && |
- srt_cleaner_key.GetValueCount() > 0; |
-} |
- |
-void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) { |
- g_testing_delegate_ = delegate; |
-} |
- |
-} // namespace safe_browsing |