Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(193)

Side by Side Diff: chrome/browser/safe_browsing/srt_fetcher_win.cc

Issue 2846333003: Chrome cleaner: move Chrome Cleaner files to their own directory (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "base/bind.h"
15 #include "base/bind_helpers.h"
16 #include "base/callback_helpers.h"
17 #include "base/command_line.h"
18 #include "base/debug/leak_annotations.h"
19 #include "base/files/file_path.h"
20 #include "base/macros.h"
21 #include "base/memory/ptr_util.h"
22 #include "base/metrics/field_trial.h"
23 #include "base/metrics/histogram_macros.h"
24 #include "base/metrics/sparse_histogram.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/task_runner_util.h"
29 #include "base/task_scheduler/post_task.h"
30 #include "base/task_scheduler/task_traits.h"
31 #include "base/time/time.h"
32 #include "base/version.h"
33 #include "base/win/registry.h"
34 #include "chrome/browser/browser_process.h"
35 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/profiles/profile_io_data.h"
38 #include "chrome/browser/safe_browsing/srt_chrome_prompt_impl.h"
39 #include "chrome/browser/safe_browsing/srt_client_info_win.h"
40 #include "chrome/browser/safe_browsing/srt_global_error_win.h"
41 #include "chrome/browser/ui/browser_finder.h"
42 #include "chrome/browser/ui/browser_list.h"
43 #include "chrome/browser/ui/browser_list_observer.h"
44 #include "chrome/browser/ui/global_error/global_error_service.h"
45 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
46 #include "chrome/common/pref_names.h"
47 #include "components/chrome_cleaner/public/constants/constants.h"
48 #include "components/component_updater/pref_names.h"
49 #include "components/data_use_measurement/core/data_use_user_data.h"
50 #include "components/prefs/pref_service.h"
51 #include "components/variations/net/variations_http_headers.h"
52 #include "components/version_info/version_info.h"
53 #include "content/public/browser/browser_thread.h"
54 #include "mojo/edk/embedder/connection_params.h"
55 #include "mojo/edk/embedder/pending_process_connection.h"
56 #include "mojo/edk/embedder/platform_channel_pair.h"
57 #include "mojo/public/cpp/system/message_pipe.h"
58 #include "net/base/load_flags.h"
59 #include "net/http/http_status_code.h"
60 #include "net/url_request/url_fetcher.h"
61 #include "net/url_request/url_fetcher_delegate.h"
62 #include "net/url_request/url_request_context_getter.h"
63
64 using content::BrowserThread;
65
66 namespace safe_browsing {
67
68 const base::Feature kInBrowserCleanerUIFeature{
69 "InBrowserCleanerUI", base::FEATURE_DISABLED_BY_DEFAULT};
70
71 namespace {
72
73 // Used to send UMA information about missing start and end time registry
74 // values for the reporter. Replicated in the histograms.xml file, so the order
75 // MUST NOT CHANGE.
76 enum SwReporterRunningTimeRegistryError {
77 REPORTER_RUNNING_TIME_ERROR_NO_ERROR = 0,
78 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID = 1,
79 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME = 2,
80 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME = 3,
81 REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES = 4,
82 REPORTER_RUNNING_TIME_ERROR_MAX,
83 };
84
85 // Used to send UMA information about the progress of the SwReporter launch and
86 // prompt sequence. Replicated in the histograms.xml file, so the order MUST
87 // NOT CHANGE.
88 enum SwReporterUmaValue {
89 // Deprecated.
90 SW_REPORTER_EXPLICIT_REQUEST = 0,
91 // Deprecated.
92 SW_REPORTER_STARTUP_RETRY = 1,
93 // Deprecated.
94 SW_REPORTER_RETRIED_TOO_MANY_TIMES = 2,
95 SW_REPORTER_START_EXECUTION = 3,
96 SW_REPORTER_FAILED_TO_START = 4,
97 // Deprecated.
98 SW_REPORTER_REGISTRY_EXIT_CODE = 5,
99 // Deprecated.
100 SW_REPORTER_RESET_RETRIES = 6,
101 SW_REPORTER_DOWNLOAD_START = 7,
102 SW_REPORTER_NO_BROWSER = 8,
103 SW_REPORTER_NO_LOCAL_STATE = 9,
104 SW_REPORTER_NO_PROMPT_NEEDED = 10,
105 SW_REPORTER_NO_PROMPT_FIELD_TRIAL = 11,
106 SW_REPORTER_ALREADY_PROMPTED = 12,
107 SW_REPORTER_RAN_DAILY = 13,
108 SW_REPORTER_ADDED_TO_MENU = 14,
109
110 SW_REPORTER_MAX,
111 };
112
113 // Used to send UMA information showing whether uploading of Software Reporter
114 // logs is enabled, or the reason why not.
115 // Replicated in the histograms.xml file, so the order MUST NOT CHANGE.
116 enum SwReporterLogsUploadsEnabled {
117 REPORTER_LOGS_UPLOADS_ENABLED = 0,
118 REPORTER_LOGS_UPLOADS_SBER_DISABLED = 1,
119 REPORTER_LOGS_UPLOADS_RECENTLY_SENT_LOGS = 2,
120 REPORTER_LOGS_UPLOADS_MAX,
121 };
122
123 // Used to send UMA information about missing logs upload result in the registry
124 // for the reporter. Replicated in the histograms.xml file, so the order
125 // MUST NOT CHANGE.
126 enum SwReporterLogsUploadResultRegistryError {
127 REPORTER_LOGS_UPLOAD_RESULT_ERROR_NO_ERROR = 0,
128 REPORTER_LOGS_UPLOAD_RESULT_ERROR_REGISTRY_KEY_INVALID = 1,
129 REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_NOT_FOUND = 2,
130 REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_OUT_OF_BOUNDS = 3,
131 REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX,
132 };
133
134 const char kRunningTimeErrorMetricName[] =
135 "SoftwareReporter.RunningTimeRegistryError";
136
137 SwReporterTestingDelegate* g_testing_delegate_ = nullptr;
138
139 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS";
140 const char kFoundUwsReadErrorMetricName[] =
141 "SoftwareReporter.FoundUwSReadError";
142 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes";
143 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed";
144 const char kStepMetricName[] = "SoftwareReporter.Step";
145 const char kLogsUploadEnabledMetricName[] =
146 "SoftwareReporter.LogsUploadEnabled";
147 const char kLogsUploadResultMetricName[] = "SoftwareReporter.LogsUploadResult";
148 const char kLogsUploadResultRegistryErrorMetricName[] =
149 "SoftwareReporter.LogsUploadResultRegistryError";
150 const char kExitCodeMetricName[] = "SoftwareReporter.ExitCodeFromRegistry";
151 const char kEngineErrorCodeMetricName[] = "SoftwareReporter.EngineErrorCode";
152
153 // The max value for histogram SoftwareReporter.LogsUploadResult, which is used
154 // to send UMA information about the result of Software Reporter's attempt to
155 // upload logs, when logs are enabled. This value must be consistent with the
156 // SoftwareReporterLogsUploadResult enum defined in the histograms.xml file.
157 const int kSwReporterLogsUploadResultMax = 30;
158
159 // Reports metrics about the software reporter via UMA (and sometimes Rappor).
160 class UMAHistogramReporter {
161 public:
162 UMAHistogramReporter() : UMAHistogramReporter(std::string()) {}
163
164 explicit UMAHistogramReporter(const std::string& suffix)
165 : suffix_(suffix),
166 registry_key_(suffix.empty()
167 ? chrome_cleaner::kSoftwareRemovalToolRegistryKey
168 : base::StringPrintf(
169 L"%ls\\%ls",
170 chrome_cleaner::kSoftwareRemovalToolRegistryKey,
171 base::UTF8ToUTF16(suffix).c_str())) {}
172
173 // Reports the software reporter tool's version via UMA.
174 void ReportVersion(const base::Version& version) const {
175 DCHECK(!version.components().empty());
176 // The minor version is the 2nd last component of the version,
177 // or just the first component if there is only 1.
178 uint32_t minor_version = 0;
179 if (version.components().size() > 1)
180 minor_version = version.components()[version.components().size() - 2];
181 else
182 minor_version = version.components()[0];
183 RecordSparseHistogram("SoftwareReporter.MinorVersion", minor_version);
184
185 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional
186 // components, only the first three count, and if there are less than 3, the
187 // missing values are just replaced by zero. So 1 is equivalent 1.0.0.
188 DCHECK_LT(version.components()[0], 0x100U);
189 uint32_t major_version = 0x1000000 * version.components()[0];
190 if (version.components().size() >= 2) {
191 DCHECK_LT(version.components()[1], 0x10000U);
192 major_version += 0x100 * version.components()[1];
193 }
194 if (version.components().size() >= 3) {
195 DCHECK_LT(version.components()[2], 0x100U);
196 major_version += version.components()[2];
197 }
198 RecordSparseHistogram("SoftwareReporter.MajorVersion", major_version);
199 }
200
201 void ReportExitCode(int exit_code) const {
202 RecordSparseHistogram("SoftwareReporter.ExitCode", exit_code);
203
204 // Also report the exit code that the reporter writes to the registry.
205 base::win::RegKey reporter_key;
206 DWORD exit_code_in_registry;
207 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
208 KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS ||
209 reporter_key.ReadValueDW(chrome_cleaner::kExitCodeValueName,
210 &exit_code_in_registry) != ERROR_SUCCESS) {
211 return;
212 }
213
214 RecordSparseHistogram(kExitCodeMetricName, exit_code_in_registry);
215 reporter_key.DeleteValue(chrome_cleaner::kExitCodeValueName);
216 }
217
218 void ReportEngineErrorCode() const {
219 base::win::RegKey reporter_key;
220 DWORD engine_error_code;
221 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
222 KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS ||
223 reporter_key.ReadValueDW(chrome_cleaner::kEngineErrorCodeValueName,
224 &engine_error_code) != ERROR_SUCCESS) {
225 return;
226 }
227
228 RecordSparseHistogram(kEngineErrorCodeMetricName, engine_error_code);
229 reporter_key.DeleteValue(chrome_cleaner::kEngineErrorCodeValueName);
230 }
231
232 // Reports UwS found by the software reporter tool via UMA and RAPPOR.
233 void ReportFoundUwS() const {
234 base::win::RegKey reporter_key;
235 std::vector<base::string16> found_uws_strings;
236 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
237 KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS ||
238 reporter_key.ReadValues(chrome_cleaner::kFoundUwsValueName,
239 &found_uws_strings) != ERROR_SUCCESS) {
240 return;
241 }
242
243 bool parse_error = false;
244 for (const base::string16& uws_string : found_uws_strings) {
245 // All UwS ids are expected to be integers.
246 uint32_t uws_id = 0;
247 if (base::StringToUint(uws_string, &uws_id)) {
248 RecordSparseHistogram(kFoundUwsMetricName, uws_id);
249 } else {
250 parse_error = true;
251 }
252 }
253
254 // Clean up the old value.
255 reporter_key.DeleteValue(chrome_cleaner::kFoundUwsValueName);
256 RecordBooleanHistogram(kFoundUwsReadErrorMetricName, parse_error);
257 }
258
259 // Reports to UMA the memory usage of the software reporter tool as reported
260 // by the tool itself in the Windows registry.
261 void ReportMemoryUsage() const {
262 base::win::RegKey reporter_key;
263 DWORD memory_used = 0;
264 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
265 KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS ||
266 reporter_key.ReadValueDW(chrome_cleaner::kMemoryUsedValueName,
267 &memory_used) != ERROR_SUCCESS) {
268 return;
269 }
270 RecordMemoryKBHistogram(kMemoryUsedMetricName, memory_used);
271 reporter_key.DeleteValue(chrome_cleaner::kMemoryUsedValueName);
272 }
273
274 // Reports the SwReporter run time with UMA both as reported by the tool via
275 // the registry and as measured by |ReporterRunner|.
276 void ReportRuntime(const base::TimeDelta& reporter_running_time) const {
277 RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome",
278 reporter_running_time);
279
280 // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE.
281 base::win::RegKey reporter_key;
282 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
283 KEY_ALL_ACCESS) != ERROR_SUCCESS) {
284 RecordEnumerationHistogram(
285 kRunningTimeErrorMetricName,
286 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID,
287 REPORTER_RUNNING_TIME_ERROR_MAX);
288 return;
289 }
290
291 bool has_start_time = false;
292 int64_t start_time_value = 0;
293 if (reporter_key.HasValue(chrome_cleaner::kStartTimeValueName) &&
294 reporter_key.ReadInt64(chrome_cleaner::kStartTimeValueName,
295 &start_time_value) == ERROR_SUCCESS) {
296 has_start_time = true;
297 reporter_key.DeleteValue(chrome_cleaner::kStartTimeValueName);
298 }
299
300 bool has_end_time = false;
301 int64_t end_time_value = 0;
302 if (reporter_key.HasValue(chrome_cleaner::kEndTimeValueName) &&
303 reporter_key.ReadInt64(chrome_cleaner::kEndTimeValueName,
304 &end_time_value) == ERROR_SUCCESS) {
305 has_end_time = true;
306 reporter_key.DeleteValue(chrome_cleaner::kEndTimeValueName);
307 }
308
309 if (has_start_time && has_end_time) {
310 base::TimeDelta registry_run_time =
311 base::Time::FromInternalValue(end_time_value) -
312 base::Time::FromInternalValue(start_time_value);
313 RecordLongTimesHistogram("SoftwareReporter.RunningTime",
314 registry_run_time);
315 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
316 REPORTER_RUNNING_TIME_ERROR_NO_ERROR,
317 REPORTER_RUNNING_TIME_ERROR_MAX);
318 } else if (!has_start_time && !has_end_time) {
319 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
320 REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES,
321 REPORTER_RUNNING_TIME_ERROR_MAX);
322 } else if (!has_start_time) {
323 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
324 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME,
325 REPORTER_RUNNING_TIME_ERROR_MAX);
326 } else {
327 DCHECK(!has_end_time);
328 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
329 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME,
330 REPORTER_RUNNING_TIME_ERROR_MAX);
331 }
332 }
333
334 // Reports the UwS scan times of the software reporter tool via UMA.
335 void ReportScanTimes() const {
336 base::string16 scan_times_key_path = base::StringPrintf(
337 L"%ls\\%ls", registry_key_.c_str(), chrome_cleaner::kScanTimesSubKey);
338 // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE.
339 base::win::RegKey scan_times_key;
340 if (scan_times_key.Open(HKEY_CURRENT_USER, scan_times_key_path.c_str(),
341 KEY_ALL_ACCESS) != ERROR_SUCCESS) {
342 return;
343 }
344
345 base::string16 value_name;
346 int uws_id = 0;
347 int64_t raw_scan_time = 0;
348 int num_scan_times = scan_times_key.GetValueCount();
349 for (int i = 0; i < num_scan_times; ++i) {
350 if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS &&
351 base::StringToInt(value_name, &uws_id) &&
352 scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) ==
353 ERROR_SUCCESS) {
354 base::TimeDelta scan_time =
355 base::TimeDelta::FromInternalValue(raw_scan_time);
356 // We report the number of seconds plus one because it can take less
357 // than one second to scan some UwS and the count passed to |AddCount|
358 // must be at least one.
359 RecordSparseHistogramCount(kScanTimesMetricName, uws_id,
360 scan_time.InSeconds() + 1);
361 }
362 }
363 // Clean up by deleting the scan times key, which is a subkey of the main
364 // reporter key.
365 scan_times_key.Close();
366 base::win::RegKey reporter_key;
367 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
368 KEY_ENUMERATE_SUB_KEYS) == ERROR_SUCCESS) {
369 reporter_key.DeleteKey(chrome_cleaner::kScanTimesSubKey);
370 }
371 }
372
373 void RecordReporterStep(SwReporterUmaValue value) {
374 RecordEnumerationHistogram(kStepMetricName, value, SW_REPORTER_MAX);
375 }
376
377 void RecordLogsUploadEnabled(SwReporterLogsUploadsEnabled value) {
378 RecordEnumerationHistogram(kLogsUploadEnabledMetricName, value,
379 REPORTER_LOGS_UPLOADS_MAX);
380 }
381
382 void RecordLogsUploadResult() {
383 base::win::RegKey reporter_key;
384 DWORD logs_upload_result = 0;
385 if (reporter_key.Open(HKEY_CURRENT_USER, registry_key_.c_str(),
386 KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS) {
387 RecordEnumerationHistogram(
388 kLogsUploadResultRegistryErrorMetricName,
389 REPORTER_LOGS_UPLOAD_RESULT_ERROR_REGISTRY_KEY_INVALID,
390 REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX);
391 return;
392 }
393
394 if (reporter_key.ReadValueDW(chrome_cleaner::kLogsUploadResultValueName,
395 &logs_upload_result) != ERROR_SUCCESS) {
396 RecordEnumerationHistogram(
397 kLogsUploadResultRegistryErrorMetricName,
398 REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_NOT_FOUND,
399 REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX);
400 return;
401 }
402
403 if (logs_upload_result >= kSwReporterLogsUploadResultMax) {
404 RecordEnumerationHistogram(
405 kLogsUploadResultRegistryErrorMetricName,
406 REPORTER_LOGS_UPLOAD_RESULT_ERROR_VALUE_OUT_OF_BOUNDS,
407 REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX);
408 return;
409 }
410
411 RecordEnumerationHistogram(kLogsUploadResultMetricName,
412 static_cast<Sample>(logs_upload_result),
413 kSwReporterLogsUploadResultMax);
414 reporter_key.DeleteValue(chrome_cleaner::kLogsUploadResultValueName);
415 RecordEnumerationHistogram(kLogsUploadResultRegistryErrorMetricName,
416 REPORTER_LOGS_UPLOAD_RESULT_ERROR_NO_ERROR,
417 REPORTER_LOGS_UPLOAD_RESULT_ERROR_MAX);
418 }
419
420 private:
421 using Sample = base::HistogramBase::Sample;
422
423 static constexpr base::HistogramBase::Flags kUmaHistogramFlag =
424 base::HistogramBase::kUmaTargetedHistogramFlag;
425
426 // Helper functions to record histograms with an optional suffix added to the
427 // histogram name. The UMA_HISTOGRAM macros can't be used because they
428 // require a constant string.
429
430 std::string FullName(const std::string& name) const {
431 if (suffix_.empty())
432 return name;
433 return base::StringPrintf("%s_%s", name.c_str(), suffix_.c_str());
434 }
435
436 void RecordBooleanHistogram(const std::string& name, bool sample) const {
437 auto* histogram =
438 base::BooleanHistogram::FactoryGet(FullName(name), kUmaHistogramFlag);
439 if (histogram)
440 histogram->AddBoolean(sample);
441 }
442
443 void RecordEnumerationHistogram(const std::string& name,
444 Sample sample,
445 Sample boundary) const {
446 // See HISTOGRAM_ENUMERATION_WITH_FLAG for the parameters to |FactoryGet|.
447 auto* histogram = base::LinearHistogram::FactoryGet(
448 FullName(name), 1, boundary, boundary + 1, kUmaHistogramFlag);
449 if (histogram)
450 histogram->Add(sample);
451 }
452
453 void RecordLongTimesHistogram(const std::string& name,
454 const base::TimeDelta& sample) const {
455 // See UMA_HISTOGRAM_LONG_TIMES for the parameters to |FactoryTimeGet|.
456 auto* histogram = base::Histogram::FactoryTimeGet(
457 FullName(name), base::TimeDelta::FromMilliseconds(1),
458 base::TimeDelta::FromHours(1), 100, kUmaHistogramFlag);
459 if (histogram)
460 histogram->AddTime(sample);
461 }
462
463 void RecordMemoryKBHistogram(const std::string& name, Sample sample) const {
464 // See UMA_HISTOGRAM_MEMORY_KB for the parameters to |FactoryGet|.
465 auto* histogram = base::Histogram::FactoryGet(FullName(name), 1000, 500000,
466 50, kUmaHistogramFlag);
467 if (histogram)
468 histogram->Add(sample);
469 }
470
471 void RecordSparseHistogram(const std::string& name, Sample sample) const {
472 auto* histogram =
473 base::SparseHistogram::FactoryGet(FullName(name), kUmaHistogramFlag);
474 if (histogram)
475 histogram->Add(sample);
476 }
477
478 void RecordSparseHistogramCount(const std::string& name,
479 Sample sample,
480 int count) const {
481 auto* histogram =
482 base::SparseHistogram::FactoryGet(FullName(name), kUmaHistogramFlag);
483 if (histogram)
484 histogram->AddCount(sample, count);
485 }
486
487 const std::string suffix_;
488 const std::wstring registry_key_;
489 };
490
491 // Records the reporter step without a suffix. (For steps that are never run by
492 // the experimental reporter.)
493 void RecordReporterStepHistogram(SwReporterUmaValue value) {
494 UMAHistogramReporter uma;
495 uma.RecordReporterStep(value);
496 }
497
498 void DisplaySRTPrompt(const base::FilePath& download_path) {
499 // Find the last active browser, which may be NULL, in which case we won't
500 // show the prompt this time and will wait until the next run of the
501 // reporter. We can't use other ways of finding a browser because we don't
502 // have a profile.
503 Browser* browser = chrome::FindLastActive();
504 if (!browser)
505 return;
506
507 Profile* profile = browser->profile();
508 DCHECK(profile);
509
510 // Make sure we have a tabbed browser since we need to anchor the bubble to
511 // the toolbar's wrench menu. Create one if none exist already.
512 if (browser->type() != Browser::TYPE_TABBED) {
513 browser = chrome::FindTabbedBrowser(profile, false);
514 if (!browser)
515 browser = new Browser(Browser::CreateParams(profile, false));
516 }
517 GlobalErrorService* global_error_service =
518 GlobalErrorServiceFactory::GetForProfile(profile);
519 SRTGlobalError* global_error =
520 new SRTGlobalError(global_error_service, download_path);
521
522 // Ownership of |global_error| is passed to the service. The error removes
523 // itself from the service and self-destructs when done.
524 global_error_service->AddGlobalError(base::WrapUnique(global_error));
525
526 bool show_bubble = true;
527 PrefService* local_state = g_browser_process->local_state();
528 if (local_state && local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) {
529 // Don't show the bubble if there's already a pending prompt to only be
530 // sown in the Chrome menu.
531 RecordReporterStepHistogram(SW_REPORTER_ADDED_TO_MENU);
532 show_bubble = false;
533 } else {
534 // Do not try to show bubble if another GlobalError is already showing
535 // one. The bubble will be shown once the others have been dismissed.
536 for (GlobalError* error : global_error_service->errors()) {
537 if (error->GetBubbleView()) {
538 show_bubble = false;
539 break;
540 }
541 }
542 }
543 if (show_bubble)
544 global_error->ShowBubbleView(browser);
545 }
546
547 // Handles the case when the remote end has been closed, by performing the
548 // necessary cleanups if the prompt dialog is being shown to the user.
549 void OnConnectionClosed() {
550 // Placeholder. This should handle cases when the reporter process is
551 // disconnected (e.g. due to a crash) and the prompt dialog is being shown
552 // to the user.
553 }
554
555 // Handles the case when a mojo::ReportBadMessage has been explicitly reported.
556 void OnConnectionError(const std::string& message) {
557 // Placeholder. This should handle cases when the reporter process sends
558 // a bad message and the prompt dialog is being shown to the user.
559 }
560
561 // Class responsible for launching the reporter process and waiting for its
562 // completion. If feature InBrowserCleanerUI is enabled, this object will also
563 // be responsible for starting the ChromePromptImpl object on the IO thread and
564 // controlling its lifetime.
565 //
566 // Expected lifecycle of a SwReporterProcess:
567 // - created on the UI thread before the reporter process launch is posted
568 // (method ScheduleNextInvocation);
569 // - deleted on the UI thread once ReporterDone() finishes (the method is
570 // called after the reporter process exits).
571 //
572 // If feature InBrowserCleanerUI feature is enabled, the following tasks will
573 // be posted in sequence to the IO Thread and will retain the SwReporterProcess
574 // object:
575 // - creation of a ChromePromptImpl object right after the reporter process is
576 // launched (that object will be responsible for handling IPC requests from
577 // the reporter process);
578 // - deletion of the ChromePromptImpl object on ReporterDone().
579 // As a consequence, the SwReporterProcess object can outlive ReporterDone()
580 // and will only be deleted after the ChromePromptImpl object is released on
581 // the IO thread.
582 class SwReporterProcess : public base::RefCountedThreadSafe<SwReporterProcess> {
583 public:
584 explicit SwReporterProcess(const SwReporterInvocation& invocation)
585 : invocation_(invocation) {}
586
587 // This function is called from a worker thread to launch the SwReporter and
588 // wait for termination to collect its exit code. This task could be
589 // interrupted by a shutdown at any time, so it shouldn't depend on anything
590 // external that could be shut down beforehand.
591 int LaunchAndWaitForExitOnBackgroundThread();
592
593 // Schedules to release the instance of ChromePromptImpl on the IO thread.
594 void OnReporterDone();
595
596 const SwReporterInvocation& invocation() const { return invocation_; }
597
598 private:
599 friend class base::RefCountedThreadSafe<SwReporterProcess>;
600 ~SwReporterProcess() = default;
601
602 // Starts a new IPC service implementing the ChromePrompt interface and
603 // launches a new reporter process that can connect to the IPC.
604 base::Process LaunchConnectedReporterProcess();
605
606 // Starts a new instance of ChromePromptImpl to receive requests from the
607 // reporter and establishes the mojo connection to it.
608 // Must be run on the IO thread.
609 void CreateChromePromptImpl(
610 chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request);
611
612 // Releases the instance of ChromePromptImpl. Must be run on the IO thread.
613 void ReleaseChromePromptImpl();
614
615 // Launches a new process with the command line in the invocation and
616 // provided launch options. Uses g_testing_delegate_ if not null.
617 base::Process LaunchReporterProcess(
618 const SwReporterInvocation& invocation,
619 const base::LaunchOptions& launch_options);
620
621 // The invocation for the current reporter process.
622 SwReporterInvocation invocation_;
623
624 // Implementation of the ChromePrompt service to be used by the current
625 // reporter process. Can only be accessed on the IO thread.
626 std::unique_ptr<ChromePromptImpl> chrome_prompt_impl_;
627 };
628
629 int SwReporterProcess::LaunchAndWaitForExitOnBackgroundThread() {
630 base::Process reporter_process =
631 base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)
632 ? LaunchConnectedReporterProcess()
633 : LaunchReporterProcess(invocation_, base::LaunchOptions());
634
635 // This exit code is used to identify that a reporter run didn't happen, so
636 // the result should be ignored and a rerun scheduled for the usual delay.
637 int exit_code = kReporterNotLaunchedExitCode;
638 UMAHistogramReporter uma(invocation_.suffix);
639 if (reporter_process.IsValid()) {
640 uma.RecordReporterStep(SW_REPORTER_START_EXECUTION);
641 bool success = reporter_process.WaitForExit(&exit_code);
642 DCHECK(success);
643 } else {
644 uma.RecordReporterStep(SW_REPORTER_FAILED_TO_START);
645 }
646 return exit_code;
647 }
648
649 void SwReporterProcess::OnReporterDone() {
650 if (base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature)) {
651 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)
652 ->PostTask(FROM_HERE,
653 base::Bind(&SwReporterProcess::ReleaseChromePromptImpl,
654 base::RetainedRef(this)));
655 }
656 }
657
658 base::Process SwReporterProcess::LaunchConnectedReporterProcess() {
659 DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature));
660
661 mojo::edk::PendingProcessConnection pending_process_connection;
662 std::string mojo_pipe_token;
663 mojo::ScopedMessagePipeHandle mojo_pipe =
664 pending_process_connection.CreateMessagePipe(&mojo_pipe_token);
665 invocation_.command_line.AppendSwitchASCII(
666 chrome_cleaner::kChromeMojoPipeTokenSwitch, mojo_pipe_token);
667 invocation_.command_line.AppendSwitchASCII(
668 chrome_cleaner::kExecutionModeSwitch,
669 base::IntToString(
670 static_cast<int>(chrome_cleaner::ExecutionMode::kScanning)));
671
672 mojo::edk::PlatformChannelPair channel;
673 base::HandlesToInheritVector handles_to_inherit;
674 channel.PrepareToPassClientHandleToChildProcess(&invocation_.command_line,
675 &handles_to_inherit);
676
677 base::LaunchOptions launch_options;
678 launch_options.handles_to_inherit = &handles_to_inherit;
679 base::Process reporter_process =
680 LaunchReporterProcess(invocation_, launch_options);
681
682 if (!reporter_process.IsValid())
683 return reporter_process;
684
685 chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request;
686 chrome_prompt_request.Bind(std::move(mojo_pipe));
687
688 // ChromePromptImpl tasks will need to run on the IO thread. There is no
689 // need to synchronize its creation, since the client end will wait for this
690 // initialization to be done before sending requests.
691 BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)
692 ->PostTask(FROM_HERE,
693 base::BindOnce(&SwReporterProcess::CreateChromePromptImpl,
694 base::RetainedRef(this),
695 std::move(chrome_prompt_request)));
696
697 mojo::edk::ProcessErrorCallback on_connection_error =
698 g_testing_delegate_
699 ? base::Bind(&SwReporterTestingDelegate::OnConnectionError,
700 base::Unretained(g_testing_delegate_))
701 : base::Bind(&OnConnectionError);
702 pending_process_connection.Connect(
703 reporter_process.Handle(),
704 mojo::edk::ConnectionParams(channel.PassServerHandle()),
705 on_connection_error);
706
707 return reporter_process;
708 }
709
710 base::Process SwReporterProcess::LaunchReporterProcess(
711 const SwReporterInvocation& invocation,
712 const base::LaunchOptions& launch_options) {
713 return g_testing_delegate_
714 ? g_testing_delegate_->LaunchReporter(invocation, launch_options)
715 : base::LaunchProcess(invocation.command_line, launch_options);
716 }
717
718 void SwReporterProcess::CreateChromePromptImpl(
719 chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request) {
720 DCHECK_CURRENTLY_ON(BrowserThread::IO);
721 DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature));
722
723 chrome_prompt_impl_ =
724 g_testing_delegate_
725 ? g_testing_delegate_->CreateChromePromptImpl(
726 std::move(chrome_prompt_request))
727 : base::MakeUnique<ChromePromptImpl>(std::move(chrome_prompt_request),
728 base::Bind(&OnConnectionClosed));
729 }
730
731 void SwReporterProcess::ReleaseChromePromptImpl() {
732 DCHECK_CURRENTLY_ON(BrowserThread::IO);
733 DCHECK(base::FeatureList::IsEnabled(kInBrowserCleanerUIFeature));
734
735 chrome_prompt_impl_.release();
736 }
737
738 } // namespace
739
740 void DisplaySRTPromptForTesting(const base::FilePath& download_path) {
741 DisplaySRTPrompt(download_path);
742 }
743
744 // Class that will attempt to download the SRT, showing the SRT notification
745 // bubble when the download operation is complete. Instances of SRTFetcher own
746 // themselves, they will self-delete on completion of the network request when
747 // OnURLFetchComplete is called.
748 class SRTFetcher : public net::URLFetcherDelegate {
749 public:
750 explicit SRTFetcher(Profile* profile)
751 : profile_(profile),
752 url_fetcher_(net::URLFetcher::Create(0,
753 GURL(GetSRTDownloadURL()),
754 net::URLFetcher::GET,
755 this)) {
756 data_use_measurement::DataUseUserData::AttachToFetcher(
757 url_fetcher_.get(),
758 data_use_measurement::DataUseUserData::SAFE_BROWSING);
759 url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
760 url_fetcher_->SetMaxRetriesOn5xx(3);
761 url_fetcher_->SaveResponseToTemporaryFile(
762 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE));
763 url_fetcher_->SetRequestContext(
764 g_browser_process->system_request_context());
765 // Adds the UMA bit to the download request if the user is enrolled in UMA.
766 ProfileIOData* io_data = ProfileIOData::FromResourceContext(
767 profile_->GetResourceContext());
768 net::HttpRequestHeaders headers;
769 // Note: It's OK to pass |is_signed_in| false if it's unknown, as it does
770 // not affect transmission of experiments coming from the variations server.
771 bool is_signed_in = false;
772 variations::AppendVariationHeaders(
773 url_fetcher_->GetOriginalURL(), io_data->IsOffTheRecord(),
774 ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(),
775 is_signed_in, &headers);
776 url_fetcher_->SetExtraRequestHeaders(headers.ToString());
777 url_fetcher_->Start();
778 }
779
780 // net::URLFetcherDelegate:
781 void OnURLFetchComplete(const net::URLFetcher* source) override {
782 // Take ownership of the fetcher in this scope (source == url_fetcher_).
783 DCHECK_EQ(url_fetcher_.get(), source);
784
785 base::FilePath download_path;
786 if (source->GetStatus().is_success() &&
787 source->GetResponseCode() == net::HTTP_OK) {
788 if (source->GetResponseAsFilePath(true, &download_path)) {
789 DCHECK(!download_path.empty());
790 }
791 }
792
793 // As long as the fetch didn't fail due to HTTP_NOT_FOUND, show a prompt
794 // (either offering the tool directly or pointing to the download page).
795 // If the fetch failed to find the file, don't prompt the user since the
796 // tool is not currently available.
797 // TODO(mad): Consider implementing another layer of retries / alternate
798 // fetching mechanisms. http://crbug.com/460293
799 // TODO(mad): In the event the browser is closed before the prompt displays,
800 // we will wait until the next scanner run to re-display it.
801 // Improve this. http://crbug.com/460295
802 if (source->GetResponseCode() != net::HTTP_NOT_FOUND)
803 DisplaySRTPrompt(download_path);
804 else
805 RecordSRTPromptHistogram(SRT_PROMPT_DOWNLOAD_UNAVAILABLE);
806
807 // Explicitly destroy the url_fetcher_ to avoid destruction races.
808 url_fetcher_.reset();
809
810 // At this point, the url_fetcher_ is gone and this SRTFetcher instance is
811 // no longer needed.
812 delete this;
813 }
814
815 private:
816 ~SRTFetcher() override {}
817
818 // The user profile.
819 Profile* profile_;
820
821 // The underlying URL fetcher. The instance is alive from construction through
822 // OnURLFetchComplete.
823 std::unique_ptr<net::URLFetcher> url_fetcher_;
824
825 DISALLOW_COPY_AND_ASSIGN(SRTFetcher);
826 };
827
828 namespace {
829
830 // Try to fetch the SRT, and on success, show the prompt to run it.
831 void MaybeFetchSRT(Browser* browser, const base::Version& reporter_version) {
832 DCHECK_CURRENTLY_ON(BrowserThread::UI);
833
834 if (g_testing_delegate_) {
835 g_testing_delegate_->TriggerPrompt(browser, reporter_version.GetString());
836 return;
837 }
838 Profile* profile = browser->profile();
839 DCHECK(profile);
840 PrefService* prefs = profile->GetPrefs();
841 DCHECK(prefs);
842
843 // Don't show the prompt again if it's been shown before for this profile
844 // and for the current variations seed, unless there's a pending prompt to
845 // show in the Chrome menu.
846 std::string incoming_seed = GetIncomingSRTSeed();
847 std::string old_seed = prefs->GetString(prefs::kSwReporterPromptSeed);
848 PrefService* local_state = g_browser_process->local_state();
849 bool pending_prompt =
850 local_state && local_state->GetBoolean(prefs::kSwReporterPendingPrompt);
851 if (!incoming_seed.empty() && incoming_seed == old_seed && !pending_prompt) {
852 RecordReporterStepHistogram(SW_REPORTER_ALREADY_PROMPTED);
853 return;
854 }
855
856 if (!incoming_seed.empty() && incoming_seed != old_seed) {
857 prefs->SetString(prefs::kSwReporterPromptSeed, incoming_seed);
858 // Forget about pending prompts if prompt seed has changed.
859 if (local_state)
860 local_state->SetBoolean(prefs::kSwReporterPendingPrompt, false);
861 }
862 prefs->SetString(prefs::kSwReporterPromptVersion,
863 reporter_version.GetString());
864
865 // Download the SRT.
866 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START);
867
868 // All the work happens in the self-deleting class below.
869 new SRTFetcher(profile);
870 }
871
872 base::Time Now() {
873 return g_testing_delegate_ ? g_testing_delegate_->Now() : base::Time::Now();
874 }
875
876 } // namespace
877
878 // This class tries to run a queue of reporters and react to their exit codes.
879 // It schedules subsequent runs of the queue as needed, or retries as soon as a
880 // browser is available when none is on first try.
881 class ReporterRunner : public chrome::BrowserListObserver {
882 public:
883 // Registers |invocations| to run next time |TryToRun| is scheduled. (And if
884 // it's not already scheduled, call it now.)
885 static void ScheduleInvocations(const SwReporterQueue& invocations,
886 const base::Version& version) {
887 if (!instance_) {
888 instance_ = new ReporterRunner;
889 ANNOTATE_LEAKING_OBJECT_PTR(instance_);
890 }
891 DCHECK_CURRENTLY_ON(BrowserThread::UI);
892
893 // There's nothing to do if the invocation parameters and version of the
894 // reporter have not changed, we just keep running the tasks that are
895 // running now.
896 if (instance_->pending_invocations_ == invocations &&
897 instance_->version_.IsValid() && instance_->version_ == version)
898 return;
899
900 instance_->pending_invocations_ = invocations;
901 instance_->version_ = version;
902 if (instance_->first_run_) {
903 instance_->first_run_ = false;
904 instance_->TryToRun();
905 }
906 }
907
908 private:
909 ReporterRunner() {}
910 ~ReporterRunner() override {}
911
912 // BrowserListObserver.
913 void OnBrowserSetLastActive(Browser* browser) override {}
914 void OnBrowserRemoved(Browser* browser) override {}
915 void OnBrowserAdded(Browser* browser) override {
916 DCHECK_CURRENTLY_ON(BrowserThread::UI);
917 DCHECK(browser);
918 MaybeFetchSRT(browser, version_);
919 BrowserList::RemoveObserver(this);
920 }
921
922 // Launches the command line at the head of the queue.
923 void ScheduleNextInvocation() {
924 DCHECK(!current_invocations_.empty());
925 auto next_invocation = current_invocations_.front();
926 current_invocations_.pop();
927
928 AppendInvocationSpecificSwitches(&next_invocation);
929
930 base::TaskRunner* task_runner =
931 g_testing_delegate_ ? g_testing_delegate_->BlockingTaskRunner()
932 : blocking_task_runner_.get();
933 auto sw_reporter_process =
934 make_scoped_refptr(new SwReporterProcess(next_invocation));
935 auto launch_and_wait =
936 base::Bind(&SwReporterProcess::LaunchAndWaitForExitOnBackgroundThread,
937 sw_reporter_process);
938 auto reporter_done =
939 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), Now(),
940 version_, std::move(sw_reporter_process));
941 base::PostTaskAndReplyWithResult(task_runner, FROM_HERE,
942 std::move(launch_and_wait),
943 std::move(reporter_done));
944 }
945
946 // This method is called on the UI thread when an invocation of the reporter
947 // has completed. This is run as a task posted from an interruptible worker
948 // thread so should be resilient to unexpected shutdown.
949 void ReporterDone(const base::Time& reporter_start_time,
950 const base::Version& version,
951 scoped_refptr<SwReporterProcess> sw_reporter_process,
952 int exit_code) {
953 DCHECK_CURRENTLY_ON(BrowserThread::UI);
954
955 sw_reporter_process->OnReporterDone();
956
957 base::Time now = Now();
958 base::TimeDelta reporter_running_time = now - reporter_start_time;
959
960 // Don't continue the current queue of reporters if one failed to launch.
961 if (exit_code == kReporterNotLaunchedExitCode)
962 current_invocations_ = SwReporterQueue();
963
964 // As soon as we're not running this queue, schedule the next overall queue
965 // run after the regular delay. (If there was a failure it's not worth
966 // retrying earlier, risking running too often if it always fails, since
967 // not many users fail here.)
968 if (current_invocations_.empty()) {
969 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
970 FROM_HERE,
971 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
972 base::TimeDelta::FromDays(days_between_reporter_runs_));
973 } else {
974 ScheduleNextInvocation();
975 }
976
977 // If the reporter failed to launch, do not process the results. (The exit
978 // code itself doesn't need to be logged in this case because
979 // SW_REPORTER_FAILED_TO_START is logged in
980 // |LaunchAndWaitForExitOnBackgroundThread|.)
981 if (exit_code == kReporterNotLaunchedExitCode)
982 return;
983
984 const auto& finished_invocation = sw_reporter_process->invocation();
985 UMAHistogramReporter uma(finished_invocation.suffix);
986 uma.ReportVersion(version);
987 uma.ReportExitCode(exit_code);
988 uma.ReportEngineErrorCode();
989 uma.ReportFoundUwS();
990
991 PrefService* local_state = g_browser_process->local_state();
992 if (local_state) {
993 if (finished_invocation.BehaviourIsSupported(
994 SwReporterInvocation::BEHAVIOUR_LOG_EXIT_CODE_TO_PREFS)) {
995 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code);
996 }
997 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered,
998 now.ToInternalValue());
999 }
1000 uma.ReportRuntime(reporter_running_time);
1001 uma.ReportScanTimes();
1002 uma.ReportMemoryUsage();
1003 if (finished_invocation.logs_upload_enabled)
1004 uma.RecordLogsUploadResult();
1005
1006 if (!finished_invocation.BehaviourIsSupported(
1007 SwReporterInvocation::BEHAVIOUR_TRIGGER_PROMPT)) {
1008 return;
1009 }
1010
1011 if (!IsInSRTPromptFieldTrialGroups()) {
1012 // Knowing about disabled field trial is more important than reporter not
1013 // finding anything to remove, so check this case first.
1014 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL);
1015 return;
1016 }
1017
1018 if (exit_code != chrome_cleaner::kSwReporterPostRebootCleanupNeeded &&
1019 exit_code != chrome_cleaner::kSwReporterCleanupNeeded) {
1020 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_NEEDED);
1021 return;
1022 }
1023
1024 // Find the last active browser, which may be NULL, in which case we need
1025 // to wait for one to be available. We can't use other ways of finding a
1026 // browser because we don't have a profile. And we need a browser to get to
1027 // a profile, which we need, to tell whether we should prompt or not.
1028 // TODO(mad): crbug.com/503269, investigate whether we should change how we
1029 // decide when it's time to download the SRT and when to display the prompt.
1030 Browser* browser = chrome::FindLastActive();
1031 if (!browser) {
1032 RecordReporterStepHistogram(SW_REPORTER_NO_BROWSER);
1033 BrowserList::AddObserver(this);
1034 } else {
1035 MaybeFetchSRT(browser, version_);
1036 }
1037 }
1038
1039 void TryToRun() {
1040 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1041 PrefService* local_state = g_browser_process->local_state();
1042
1043 if (!version_.IsValid() || !local_state) {
1044 // TODO(b/641081): This doesn't look right. Even on first run, |version_|
1045 // should be valid (and this is already checked in RunSwReporters). We
1046 // should abort if local_state is missing, but this has nothing to do
1047 // with |first_run_|.
1048 DCHECK(first_run_);
1049 return;
1050 }
1051
1052 // Run a queue of reporters if none have been triggered in the last
1053 // |days_between_reporter_runs_| days, which depends if there is a pending
1054 // prompt to be added to Chrome's menu.
1055 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) {
1056 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt;
1057 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY);
1058 } else {
1059 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns;
1060 }
1061 const base::Time now = Now();
1062 const base::Time last_time_triggered = base::Time::FromInternalValue(
1063 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered));
1064 const base::Time next_trigger(
1065 last_time_triggered +
1066 base::TimeDelta::FromDays(days_between_reporter_runs_));
1067 if (!pending_invocations_.empty() &&
1068 (next_trigger <= now ||
1069 // Also make sure the kSwReporterLastTimeTriggered value is not set in
1070 // the future.
1071 last_time_triggered > now)) {
1072 const base::Time last_time_sent_logs = base::Time::FromInternalValue(
1073 local_state->GetInt64(prefs::kSwReporterLastTimeSentReport));
1074 const base::Time next_time_send_logs =
1075 last_time_sent_logs +
1076 base::TimeDelta::FromDays(kDaysBetweenReporterLogsSent);
1077 // Send the logs for this whole queue of invocations if the last send is
1078 // in the future or if logs have been sent at least
1079 // |kSwReporterLastTimeSentReport| days ago. The former is intended as a
1080 // measure for failure recovery, in case the time in local state is
1081 // incorrectly set to the future.
1082 in_logs_upload_period_ =
1083 last_time_sent_logs > now || next_time_send_logs <= now;
1084
1085 DCHECK(current_invocations_.empty());
1086 current_invocations_ = pending_invocations_;
1087 ScheduleNextInvocation();
1088 } else {
1089 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1090 FROM_HERE,
1091 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
1092 next_trigger - now);
1093 }
1094 }
1095
1096 // Returns true if the experiment to send reporter logs is enabled, the user
1097 // opted into Safe Browsing extended reporting, and this queue of invocations
1098 // started during the logs upload interval.
1099 bool ShouldSendReporterLogs(const std::string& suffix,
1100 const PrefService& local_state) {
1101 UMAHistogramReporter uma(suffix);
1102 if (!SafeBrowsingExtendedReportingEnabled()) {
1103 uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_SBER_DISABLED);
1104 return false;
1105 }
1106 if (!in_logs_upload_period_) {
1107 uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_RECENTLY_SENT_LOGS);
1108 return false;
1109 }
1110 uma.RecordLogsUploadEnabled(REPORTER_LOGS_UPLOADS_ENABLED);
1111 return true;
1112 }
1113
1114 // Appends switches to the next invocation that depend on the user current
1115 // state with respect to opting into extended Safe Browsing reporting and
1116 // metrics and crash reporting. The invocation object is changed locally right
1117 // before the actual process is launched because user status can change
1118 // between this and the next run for this ReporterRunner object. For example,
1119 // the ReporterDone() callback schedules the next run for a few days later,
1120 // and the user might have changed settings in the meantime.
1121 void AppendInvocationSpecificSwitches(SwReporterInvocation* next_invocation) {
1122 // Add switches for users who opted into extended Safe Browsing reporting.
1123 PrefService* local_state = g_browser_process->local_state();
1124 if (next_invocation->BehaviourIsSupported(
1125 SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS) &&
1126 local_state &&
1127 ShouldSendReporterLogs(next_invocation->suffix, *local_state)) {
1128 next_invocation->logs_upload_enabled = true;
1129 AddSwitchesForExtendedReportingUser(next_invocation);
1130 // Set the local state value before the first attempt to run the
1131 // reporter, because we only want to upload logs once in the window
1132 // defined by |kDaysBetweenReporterLogsSent|. If we set with other local
1133 // state values after the reporter runs, we could send logs again too
1134 // quickly (for example, if Chrome stops before the reporter finishes).
1135 local_state->SetInt64(prefs::kSwReporterLastTimeSentReport,
1136 Now().ToInternalValue());
1137 }
1138
1139 if (ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled())
1140 next_invocation->command_line.AppendSwitch(
1141 chrome_cleaner::kEnableCrashReportingSwitch);
1142 }
1143
1144 // Adds switches to be sent to the Software Reporter when the user opted into
1145 // extended Safe Browsing reporting and is not incognito.
1146 void AddSwitchesForExtendedReportingUser(SwReporterInvocation* invocation) {
1147 invocation->command_line.AppendSwitch(
1148 chrome_cleaner::kExtendedSafeBrowsingEnabledSwitch);
1149 invocation->command_line.AppendSwitchASCII(
1150 chrome_cleaner::kChromeVersionSwitch, version_info::GetVersionNumber());
1151 invocation->command_line.AppendSwitchNative(
1152 chrome_cleaner::kChromeChannelSwitch,
1153 base::IntToString16(ChannelAsInt()));
1154 }
1155
1156 bool first_run_ = true;
1157
1158 // The queue of invocations that are currently running.
1159 SwReporterQueue current_invocations_;
1160
1161 // The invocations to run next time the SwReporter is run.
1162 SwReporterQueue pending_invocations_;
1163
1164 base::Version version_;
1165
1166 scoped_refptr<base::TaskRunner> blocking_task_runner_ =
1167 base::CreateTaskRunnerWithTraits(
1168 // LaunchAndWaitForExitOnBackgroundThread() creates (MayBlock()) and
1169 // joins (WithBaseSyncPrimitives()) a process.
1170 base::TaskTraits()
1171 .WithShutdownBehavior(
1172 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)
1173 .WithPriority(base::TaskPriority::BACKGROUND)
1174 .MayBlock()
1175 .WithBaseSyncPrimitives());
1176
1177 // This value is used to identify how long to wait before starting a new run
1178 // of the reporter queue. It's initialized with the default value and may be
1179 // changed to a different value when a prompt is pending and the reporter
1180 // should be run before adding the global error to the Chrome menu.
1181 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns;
1182
1183 // This will be true if the current queue of invocations started at a time
1184 // when logs should be uploaded.
1185 bool in_logs_upload_period_ = false;
1186
1187 // A single leaky instance.
1188 static ReporterRunner* instance_;
1189
1190 DISALLOW_COPY_AND_ASSIGN(ReporterRunner);
1191 };
1192
1193 ReporterRunner* ReporterRunner::instance_ = nullptr;
1194
1195 SwReporterInvocation::SwReporterInvocation()
1196 : command_line(base::CommandLine::NO_PROGRAM) {}
1197
1198 SwReporterInvocation SwReporterInvocation::FromFilePath(
1199 const base::FilePath& exe_path) {
1200 SwReporterInvocation invocation;
1201 invocation.command_line = base::CommandLine(exe_path);
1202 return invocation;
1203 }
1204
1205 SwReporterInvocation SwReporterInvocation::FromCommandLine(
1206 const base::CommandLine& command_line) {
1207 SwReporterInvocation invocation;
1208 invocation.command_line = command_line;
1209 return invocation;
1210 }
1211
1212 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const {
1213 return command_line.argv() == other.command_line.argv() &&
1214 suffix == other.suffix &&
1215 supported_behaviours == other.supported_behaviours &&
1216 logs_upload_enabled == other.logs_upload_enabled;
1217 }
1218
1219 bool SwReporterInvocation::BehaviourIsSupported(
1220 SwReporterInvocation::Behaviours intended_behaviour) const {
1221 return (supported_behaviours & intended_behaviour) != 0;
1222 }
1223
1224 void RunSwReporters(const SwReporterQueue& invocations,
1225 const base::Version& version) {
1226 DCHECK(!invocations.empty());
1227 DCHECK(version.IsValid());
1228 ReporterRunner::ScheduleInvocations(invocations, version);
1229 }
1230
1231 bool ReporterFoundUws() {
1232 PrefService* local_state = g_browser_process->local_state();
1233 if (!local_state)
1234 return false;
1235 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode);
1236 return exit_code == chrome_cleaner::kSwReporterCleanupNeeded;
1237 }
1238
1239 bool UserHasRunCleaner() {
1240 base::string16 cleaner_key_path(
1241 chrome_cleaner::kSoftwareRemovalToolRegistryKey);
1242 cleaner_key_path.append(L"\\").append(chrome_cleaner::kCleanerSubKey);
1243
1244 base::win::RegKey srt_cleaner_key;
1245 return srt_cleaner_key.Open(HKEY_CURRENT_USER, cleaner_key_path.c_str(),
1246 KEY_QUERY_VALUE) == ERROR_SUCCESS &&
1247 srt_cleaner_key.GetValueCount() > 0;
1248 }
1249
1250 void SetSwReporterTestingDelegate(SwReporterTestingDelegate* delegate) {
1251 g_testing_delegate_ = delegate;
1252 }
1253
1254 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « chrome/browser/safe_browsing/srt_fetcher_win.h ('k') | chrome/browser/safe_browsing/srt_field_trial_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698