OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" | 5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | |
9 #include <vector> | 10 #include <vector> |
10 | 11 |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
13 #include "base/callback_helpers.h" | 14 #include "base/callback_helpers.h" |
14 #include "base/command_line.h" | 15 #include "base/command_line.h" |
15 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
16 #include "base/macros.h" | 17 #include "base/macros.h" |
17 #include "base/metrics/field_trial.h" | 18 #include "base/metrics/field_trial.h" |
18 #include "base/metrics/histogram_macros.h" | 19 #include "base/metrics/histogram_macros.h" |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 } | 136 } |
136 } | 137 } |
137 if (show_bubble) | 138 if (show_bubble) |
138 global_error->ShowBubbleView(browser); | 139 global_error->ShowBubbleView(browser); |
139 } | 140 } |
140 | 141 |
141 // This function is called from a worker thread to launch the SwReporter and | 142 // This function is called from a worker thread to launch the SwReporter and |
142 // wait for termination to collect its exit code. This task could be | 143 // wait for termination to collect its exit code. This task could be |
143 // interrupted by a shutdown at any time, so it shouldn't depend on anything | 144 // interrupted by a shutdown at any time, so it shouldn't depend on anything |
144 // external that could be shut down beforehand. | 145 // external that could be shut down beforehand. |
145 int LaunchAndWaitForExit(const base::FilePath& exe_path) { | 146 int LaunchAndWaitForExit(const SwReporterInvocation& invocation) { |
146 if (!g_reporter_launcher_.is_null()) | 147 if (!g_reporter_launcher_.is_null()) |
147 return g_reporter_launcher_.Run(exe_path); | 148 return g_reporter_launcher_.Run(invocation.command_line.GetProgram()); |
148 base::Process reporter_process = | 149 base::Process reporter_process = |
149 base::LaunchProcess(exe_path.value(), base::LaunchOptions()); | 150 base::LaunchProcess(invocation.command_line, base::LaunchOptions()); |
150 // This exit code is used to identify that a reporter run didn't happen, so | 151 // This exit code is used to identify that a reporter run didn't happen, so |
151 // the result should be ignored and a rerun scheduled for the usual delay. | 152 // the result should be ignored and a rerun scheduled for the usual delay. |
152 int exit_code = kReporterFailureExitCode; | 153 int exit_code = kReporterFailureExitCode; |
153 if (reporter_process.IsValid()) { | 154 if (reporter_process.IsValid()) { |
154 RecordReporterStepHistogram(SW_REPORTER_START_EXECUTION); | 155 RecordReporterStepHistogram(SW_REPORTER_START_EXECUTION, |
156 invocation.suffix); | |
155 bool success = reporter_process.WaitForExit(&exit_code); | 157 bool success = reporter_process.WaitForExit(&exit_code); |
156 DCHECK(success); | 158 DCHECK(success); |
157 } else { | 159 } else { |
158 RecordReporterStepHistogram(SW_REPORTER_FAILED_TO_START); | 160 RecordReporterStepHistogram(SW_REPORTER_FAILED_TO_START, |
161 invocation.suffix); | |
159 } | 162 } |
160 return exit_code; | 163 return exit_code; |
161 } | 164 } |
162 | 165 |
166 std::string AddHistogramSuffix(const std::string& histogram, | |
167 const std::string& suffix) { | |
csharp
2016/08/11 18:58:02
Given the number of functions that have been modif
Joe Mason
2016/08/15 17:24:40
Done. Also I moved this refactor to http://crrev.c
| |
168 if (suffix.empty()) | |
169 return histogram; | |
170 return base::StringPrintf("%s_%s", histogram, suffix); | |
171 } | |
172 | |
173 std::wstring RegistryKeyWithSuffix(const std::string& suffix) { | |
174 if (suffix.empty()) | |
175 return kSoftwareRemovalToolRegistryKey; | |
176 return base::StringPrintf(L"%s\\%s", kSoftwareRemovalToolRegistryKey, | |
177 base::UTF8ToUTF16(suffix)); | |
178 } | |
179 | |
163 // Reports the software reporter tool's version via UMA. | 180 // Reports the software reporter tool's version via UMA. |
164 void ReportVersion(const base::Version& version) { | 181 void ReportVersion(const base::Version& version, const std::string& suffix) { |
165 DCHECK(!version.components().empty()); | 182 DCHECK(!version.components().empty()); |
166 // The minor version is the 2nd last component of the version, | 183 // The minor version is the 2nd last component of the version, |
167 // or just the first component if there is only 1. | 184 // or just the first component if there is only 1. |
168 uint32_t minor_version = 0; | 185 uint32_t minor_version = 0; |
169 if (version.components().size() > 1) | 186 if (version.components().size() > 1) |
170 minor_version = version.components()[version.components().size() - 2]; | 187 minor_version = version.components()[version.components().size() - 2]; |
171 else | 188 else |
172 minor_version = version.components()[0]; | 189 minor_version = version.components()[0]; |
173 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MinorVersion", minor_version); | 190 UMA_HISTOGRAM_SPARSE_SLOWLY( |
191 AddHistogramSuffix("SoftwareReporter.MinorVersion", suffix), | |
192 minor_version); | |
174 | 193 |
175 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional | 194 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional |
176 // components, only the first three count, and if there are less than 3, the | 195 // components, only the first three count, and if there are less than 3, the |
177 // missing values are just replaced by zero. So 1 is equivalent 1.0.0. | 196 // missing values are just replaced by zero. So 1 is equivalent 1.0.0. |
178 DCHECK_LT(version.components()[0], 0x100U); | 197 DCHECK_LT(version.components()[0], 0x100U); |
179 uint32_t major_version = 0x1000000 * version.components()[0]; | 198 uint32_t major_version = 0x1000000 * version.components()[0]; |
180 if (version.components().size() >= 2) { | 199 if (version.components().size() >= 2) { |
181 DCHECK_LT(version.components()[1], 0x10000U); | 200 DCHECK_LT(version.components()[1], 0x10000U); |
182 major_version += 0x100 * version.components()[1]; | 201 major_version += 0x100 * version.components()[1]; |
183 } | 202 } |
184 if (version.components().size() >= 3) { | 203 if (version.components().size() >= 3) { |
185 DCHECK_LT(version.components()[2], 0x100U); | 204 DCHECK_LT(version.components()[2], 0x100U); |
186 major_version += version.components()[2]; | 205 major_version += version.components()[2]; |
187 } | 206 } |
188 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version); | 207 UMA_HISTOGRAM_SPARSE_SLOWLY( |
208 AddHistogramSuffix("SoftwareReporter.MajorVersion", suffix), | |
209 major_version); | |
189 } | 210 } |
190 | 211 |
191 // Reports UwS found by the software reporter tool via UMA and RAPPOR. | 212 // Reports UwS found by the software reporter tool via UMA and RAPPOR. |
192 void ReportFoundUwS() { | 213 void ReportFoundUwS(const std::string& suffix) { |
193 base::win::RegKey reporter_key(HKEY_CURRENT_USER, | 214 base::win::RegKey reporter_key(HKEY_CURRENT_USER, |
194 kSoftwareRemovalToolRegistryKey, | 215 RegistryKeyWithSuffix(suffix).c_str(), |
195 KEY_QUERY_VALUE | KEY_SET_VALUE); | 216 KEY_QUERY_VALUE | KEY_SET_VALUE); |
196 std::vector<base::string16> found_uws_strings; | 217 std::vector<base::string16> found_uws_strings; |
197 if (reporter_key.Valid() && | 218 if (reporter_key.Valid() && |
198 reporter_key.ReadValues(kFoundUwsValueName, &found_uws_strings) == | 219 reporter_key.ReadValues(kFoundUwsValueName, &found_uws_strings) == |
199 ERROR_SUCCESS) { | 220 ERROR_SUCCESS) { |
200 rappor::RapporService* rappor_service = g_browser_process->rappor_service(); | 221 rappor::RapporService* rappor_service = g_browser_process->rappor_service(); |
201 | 222 |
202 bool parse_error = false; | 223 bool parse_error = false; |
203 for (const base::string16& uws_string : found_uws_strings) { | 224 for (const base::string16& uws_string : found_uws_strings) { |
204 // All UwS ids are expected to be integers. | 225 // All UwS ids are expected to be integers. |
205 uint32_t uws_id = 0; | 226 uint32_t uws_id = 0; |
206 if (base::StringToUint(uws_string, &uws_id)) { | 227 if (base::StringToUint(uws_string, &uws_id)) { |
207 UMA_HISTOGRAM_SPARSE_SLOWLY(kFoundUwsMetricName, uws_id); | 228 UMA_HISTOGRAM_SPARSE_SLOWLY(AddHistogramSuffix(kFoundUwsMetricName, |
229 suffix), uws_id); | |
208 if (rappor_service) { | 230 if (rappor_service) { |
209 rappor_service->RecordSample(kFoundUwsMetricName, | 231 rappor_service->RecordSample(kFoundUwsMetricName, |
210 rappor::COARSE_RAPPOR_TYPE, | 232 rappor::COARSE_RAPPOR_TYPE, |
211 base::UTF16ToUTF8(uws_string)); | 233 base::UTF16ToUTF8(uws_string)); |
212 } | 234 } |
213 } else { | 235 } else { |
214 parse_error = true; | 236 parse_error = true; |
215 } | 237 } |
216 } | 238 } |
217 | 239 |
218 // Clean up the old value. | 240 // Clean up the old value. |
219 reporter_key.DeleteValue(kFoundUwsValueName); | 241 reporter_key.DeleteValue(kFoundUwsValueName); |
220 | 242 |
221 UMA_HISTOGRAM_BOOLEAN(kFoundUwsReadErrorMetricName, parse_error); | 243 UMA_HISTOGRAM_BOOLEAN(AddHistogramSuffix(kFoundUwsReadErrorMetricName, |
244 suffix), parse_error); | |
222 } | 245 } |
223 } | 246 } |
224 | 247 |
225 // Reports to UMA the memory usage of the software reporter tool as reported by | 248 // Reports to UMA the memory usage of the software reporter tool as reported by |
226 // the tool itself in the Windows registry. | 249 // the tool itself in the Windows registry. |
227 void ReportSwReporterMemoryUsage() { | 250 void ReportSwReporterMemoryUsage(const std::string& suffix) { |
228 base::win::RegKey reporter_key(HKEY_CURRENT_USER, | 251 base::win::RegKey reporter_key(HKEY_CURRENT_USER, |
229 kSoftwareRemovalToolRegistryKey, | 252 RegistryKeyWithSuffix(suffix).c_str(), |
230 KEY_QUERY_VALUE | KEY_SET_VALUE); | 253 KEY_QUERY_VALUE | KEY_SET_VALUE); |
231 DWORD memory_used = 0; | 254 DWORD memory_used = 0; |
232 if (reporter_key.Valid() && | 255 if (reporter_key.Valid() && |
233 reporter_key.ReadValueDW(kMemoryUsedValueName, &memory_used) == | 256 reporter_key.ReadValueDW(kMemoryUsedValueName, &memory_used) == |
234 ERROR_SUCCESS) { | 257 ERROR_SUCCESS) { |
235 UMA_HISTOGRAM_MEMORY_KB(kMemoryUsedMetricName, memory_used); | 258 UMA_HISTOGRAM_MEMORY_KB(AddHistogramSuffix(kMemoryUsedMetricName, suffix), |
259 memory_used); | |
236 reporter_key.DeleteValue(kMemoryUsedValueName); | 260 reporter_key.DeleteValue(kMemoryUsedValueName); |
237 } | 261 } |
238 } | 262 } |
239 | 263 |
240 } // namespace | 264 } // namespace |
241 | 265 |
242 // Class that will attempt to download the SRT, showing the SRT notification | 266 // Class that will attempt to download the SRT, showing the SRT notification |
243 // bubble when the download operation is complete. Instances of SRTFetcher own | 267 // bubble when the download operation is complete. Instances of SRTFetcher own |
244 // themselves, they will self-delete on completion of the network request when | 268 // themselves, they will self-delete on completion of the network request when |
245 // OnURLFetchComplete is called. | 269 // OnURLFetchComplete is called. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
356 | 380 |
357 // Download the SRT. | 381 // Download the SRT. |
358 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); | 382 RecordReporterStepHistogram(SW_REPORTER_DOWNLOAD_START); |
359 | 383 |
360 // All the work happens in the self-deleting class below. | 384 // All the work happens in the self-deleting class below. |
361 new SRTFetcher(profile); | 385 new SRTFetcher(profile); |
362 } | 386 } |
363 | 387 |
364 // Report the SwReporter run time with UMA both as reported by the tool via | 388 // Report the SwReporter run time with UMA both as reported by the tool via |
365 // the registry and as measured by |ReporterRunner|. | 389 // the registry and as measured by |ReporterRunner|. |
366 void ReportSwReporterRuntime(const base::TimeDelta& reporter_running_time) { | 390 void ReportSwReporterRuntime(const base::TimeDelta& reporter_running_time, |
367 UMA_HISTOGRAM_LONG_TIMES("SoftwareReporter.RunningTimeAccordingToChrome", | 391 const std::string& suffix) { |
368 reporter_running_time); | 392 UMA_HISTOGRAM_LONG_TIMES(AddHistogramSuffix( |
393 "SoftwareReporter.RunningTimeAccordingToChrome", suffix), | |
394 reporter_running_time); | |
369 | 395 |
370 base::win::RegKey reporter_key( | 396 base::win::RegKey reporter_key( |
371 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_ALL_ACCESS); | 397 HKEY_CURRENT_USER, RegistryKeyWithSuffix(suffix).c_str(), KEY_ALL_ACCESS); |
372 if (!reporter_key.Valid()) { | 398 if (!reporter_key.Valid()) { |
373 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, | 399 UMA_HISTOGRAM_ENUMERATION( |
374 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID, | 400 AddHistogramSuffix(kRunningTimeErrorMetricName, suffix), |
375 REPORTER_RUNNING_TIME_ERROR_MAX); | 401 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID, |
402 REPORTER_RUNNING_TIME_ERROR_MAX); | |
376 return; | 403 return; |
377 } | 404 } |
378 | 405 |
379 bool has_start_time = false; | 406 bool has_start_time = false; |
380 int64_t start_time_value = 0; | 407 int64_t start_time_value = 0; |
381 if (reporter_key.HasValue(kStartTimeValueName) && | 408 if (reporter_key.HasValue(kStartTimeValueName) && |
382 reporter_key.ReadInt64(kStartTimeValueName, &start_time_value) == | 409 reporter_key.ReadInt64(kStartTimeValueName, &start_time_value) == |
383 ERROR_SUCCESS) { | 410 ERROR_SUCCESS) { |
384 has_start_time = true; | 411 has_start_time = true; |
385 reporter_key.DeleteValue(kStartTimeValueName); | 412 reporter_key.DeleteValue(kStartTimeValueName); |
386 } | 413 } |
387 | 414 |
388 bool has_end_time = false; | 415 bool has_end_time = false; |
389 int64_t end_time_value = 0; | 416 int64_t end_time_value = 0; |
390 if (reporter_key.HasValue(kEndTimeValueName) && | 417 if (reporter_key.HasValue(kEndTimeValueName) && |
391 reporter_key.ReadInt64(kEndTimeValueName, &end_time_value) == | 418 reporter_key.ReadInt64(kEndTimeValueName, &end_time_value) == |
392 ERROR_SUCCESS) { | 419 ERROR_SUCCESS) { |
393 has_end_time = true; | 420 has_end_time = true; |
394 reporter_key.DeleteValue(kEndTimeValueName); | 421 reporter_key.DeleteValue(kEndTimeValueName); |
395 } | 422 } |
396 | 423 |
397 if (has_start_time && has_end_time) { | 424 if (has_start_time && has_end_time) { |
398 base::TimeDelta registry_run_time = | 425 base::TimeDelta registry_run_time = |
399 base::Time::FromInternalValue(end_time_value) - | 426 base::Time::FromInternalValue(end_time_value) - |
400 base::Time::FromInternalValue(start_time_value); | 427 base::Time::FromInternalValue(start_time_value); |
401 UMA_HISTOGRAM_LONG_TIMES("SoftwareReporter.RunningTime", registry_run_time); | 428 UMA_HISTOGRAM_LONG_TIMES(AddHistogramSuffix("SoftwareReporter.RunningTime", |
402 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, | 429 suffix), registry_run_time); |
403 REPORTER_RUNNING_TIME_ERROR_NO_ERROR, | 430 UMA_HISTOGRAM_ENUMERATION( |
404 REPORTER_RUNNING_TIME_ERROR_MAX); | 431 AddHistogramSuffix(kRunningTimeErrorMetricName, suffix), |
432 REPORTER_RUNNING_TIME_ERROR_NO_ERROR, | |
433 REPORTER_RUNNING_TIME_ERROR_MAX); | |
405 } else if (!has_start_time && !has_end_time) { | 434 } else if (!has_start_time && !has_end_time) { |
406 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, | 435 UMA_HISTOGRAM_ENUMERATION( |
407 REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES, | 436 AddHistogramSuffix(kRunningTimeErrorMetricName, suffix), |
408 REPORTER_RUNNING_TIME_ERROR_MAX); | 437 REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES, |
438 REPORTER_RUNNING_TIME_ERROR_MAX); | |
409 } else if (!has_start_time) { | 439 } else if (!has_start_time) { |
410 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, | 440 UMA_HISTOGRAM_ENUMERATION( |
411 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME, | 441 AddHistogramSuffix(kRunningTimeErrorMetricName, suffix), |
412 REPORTER_RUNNING_TIME_ERROR_MAX); | 442 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME, |
443 REPORTER_RUNNING_TIME_ERROR_MAX); | |
413 } else { | 444 } else { |
414 DCHECK(!has_end_time); | 445 DCHECK(!has_end_time); |
415 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, | 446 UMA_HISTOGRAM_ENUMERATION( |
416 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME, | 447 AddHistogramSuffix(kRunningTimeErrorMetricName, suffix), |
417 REPORTER_RUNNING_TIME_ERROR_MAX); | 448 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME, |
449 REPORTER_RUNNING_TIME_ERROR_MAX); | |
418 } | 450 } |
419 } | 451 } |
420 | 452 |
421 // Report the UwS scan times of the software reporter tool via UMA. | 453 // Report the UwS scan times of the software reporter tool via UMA. |
422 void ReportSwReporterScanTimes() { | 454 void ReportSwReporterScanTimes(const std::string& suffix) { |
423 base::string16 scan_times_key_path = base::StringPrintf( | 455 base::string16 scan_times_key_path = base::StringPrintf( |
424 L"%ls\\%ls", kSoftwareRemovalToolRegistryKey, kScanTimesSubKey); | 456 L"%ls\\%ls", RegistryKeyWithSuffix(suffix).c_str(), kScanTimesSubKey); |
425 base::win::RegKey scan_times_key(HKEY_CURRENT_USER, | 457 base::win::RegKey scan_times_key(HKEY_CURRENT_USER, |
426 scan_times_key_path.c_str(), KEY_ALL_ACCESS); | 458 scan_times_key_path.c_str(), KEY_ALL_ACCESS); |
427 if (!scan_times_key.Valid()) | 459 if (!scan_times_key.Valid()) |
428 return; | 460 return; |
429 | 461 |
430 base::string16 value_name; | 462 base::string16 value_name; |
431 int uws_id = 0; | 463 int uws_id = 0; |
432 int64_t raw_scan_time = 0; | 464 int64_t raw_scan_time = 0; |
433 int num_scan_times = scan_times_key.GetValueCount(); | 465 int num_scan_times = scan_times_key.GetValueCount(); |
434 for (int i = 0; i < num_scan_times; ++i) { | 466 for (int i = 0; i < num_scan_times; ++i) { |
435 if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS && | 467 if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS && |
436 base::StringToInt(value_name, &uws_id) && | 468 base::StringToInt(value_name, &uws_id) && |
437 scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) == | 469 scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) == |
438 ERROR_SUCCESS) { | 470 ERROR_SUCCESS) { |
439 base::TimeDelta scan_time = | 471 base::TimeDelta scan_time = |
440 base::TimeDelta::FromInternalValue(raw_scan_time); | 472 base::TimeDelta::FromInternalValue(raw_scan_time); |
441 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( | 473 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( |
442 kScanTimesMetricName, base::HistogramBase::kUmaTargetedHistogramFlag); | 474 AddHistogramSuffix(kScanTimesMetricName, suffix), |
475 base::HistogramBase::kUmaTargetedHistogramFlag); | |
443 if (histogram) { | 476 if (histogram) { |
444 // We report the number of seconds plus one because it can take less | 477 // We report the number of seconds plus one because it can take less |
445 // than one second to scan some UwS and the count passed to |AddCount| | 478 // than one second to scan some UwS and the count passed to |AddCount| |
446 // must be at least one. | 479 // must be at least one. |
447 histogram->AddCount(uws_id, scan_time.InSeconds() + 1); | 480 histogram->AddCount(uws_id, scan_time.InSeconds() + 1); |
448 } | 481 } |
449 } | 482 } |
450 } | 483 } |
451 // Clean up by deleting the scan times key, which is a subkey of the main | 484 // Clean up by deleting the scan times key, which is a subkey of the main |
452 // reporter key. | 485 // reporter key. |
453 scan_times_key.Close(); | 486 scan_times_key.Close(); |
454 base::win::RegKey reporter_key(HKEY_CURRENT_USER, | 487 base::win::RegKey reporter_key(HKEY_CURRENT_USER, |
455 kSoftwareRemovalToolRegistryKey, | 488 RegistryKeyWithSuffix(suffix).c_str(), |
456 KEY_ENUMERATE_SUB_KEYS); | 489 KEY_ENUMERATE_SUB_KEYS); |
457 if (reporter_key.Valid()) | 490 if (reporter_key.Valid()) |
458 reporter_key.DeleteKey(kScanTimesSubKey); | 491 reporter_key.DeleteKey(kScanTimesSubKey); |
459 } | 492 } |
460 | 493 |
461 // This class tries to run the reporter and reacts to its exit code. It | 494 // This class tries to run the reporter and reacts to its exit code. It |
462 // schedules subsequent runs as needed, or retries as soon as a browser is | 495 // schedules subsequent runs as needed, or retries as soon as a browser is |
463 // available when none is on first try. | 496 // available when none is on first try. |
464 class ReporterRunner : public chrome::BrowserListObserver { | 497 class ReporterRunner : public chrome::BrowserListObserver { |
465 public: | 498 public: |
466 // Starts the sequence of attempts to run the reporter. | 499 // Starts the sequence of attempts to run the reporter. |
467 static void Run( | 500 static void Run( |
468 const base::FilePath& exe_path, | 501 const std::vector<SwReporterInvocation>& invocation_queue, |
469 const base::Version& version, | 502 const base::Version& version, |
470 const scoped_refptr<base::TaskRunner>& main_thread_task_runner, | 503 const scoped_refptr<base::TaskRunner>& main_thread_task_runner, |
471 const scoped_refptr<base::TaskRunner>& blocking_task_runner) { | 504 const scoped_refptr<base::TaskRunner>& blocking_task_runner) { |
472 if (!instance_) | 505 if (!instance_) |
473 instance_ = new ReporterRunner; | 506 instance_ = new ReporterRunner; |
474 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 507 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
475 // There's nothing to do if the path and version of the reporter has not | 508 // There's nothing to do if the path and version of the reporter has not |
476 // changed, we just keep running the tasks that are running now. | 509 // changed, we just keep running the tasks that are running now. |
477 if (instance_->exe_path_ == exe_path && instance_->version_.IsValid() && | 510 if (instance_->invocation_queue_ == invocation_queue && |
511 instance_->version_.IsValid() && | |
478 instance_->version_ == version) | 512 instance_->version_ == version) |
479 return; | 513 return; |
480 bool first_run = instance_->exe_path_.empty(); | 514 bool first_run = instance_->invocation_queue_.empty(); |
481 | 515 |
482 instance_->exe_path_ = exe_path; | 516 instance_->invocation_queue_ = invocation_queue; |
483 instance_->version_ = version; | 517 instance_->version_ = version; |
484 instance_->main_thread_task_runner_ = main_thread_task_runner; | 518 instance_->main_thread_task_runner_ = main_thread_task_runner; |
485 instance_->blocking_task_runner_ = blocking_task_runner; | 519 instance_->blocking_task_runner_ = blocking_task_runner; |
486 | 520 |
487 if (first_run) | 521 if (first_run) |
488 instance_->TryToRun(); | 522 instance_->TryToRun(); |
489 } | 523 } |
490 | 524 |
525 // Launch the command line at the head of the queue. | |
526 void LaunchNextInvocation( | |
527 const std::vector<SwReporterInvocation>& invocation_queue) { | |
528 DCHECK(!invocation_queue.empty()); | |
529 auto head = invocation_queue.begin(); | |
530 std::vector<SwReporterInvocation> tail( | |
531 head + 1, invocation_queue.end()); | |
532 | |
533 base::PostTaskAndReplyWithResult( | |
534 blocking_task_runner_.get(), FROM_HERE, | |
535 | |
536 // Send the head of the queue to the launch callback. | |
537 base::Bind(&LaunchAndWaitForExit, *head), | |
538 | |
539 // Send the tail of the queue to the next callback, which will handle the | |
540 // results of the first launch and then recursively launch everything in | |
541 // the tail. | |
542 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), | |
543 base::Time::Now(), version_, head->suffix, tail)); | |
544 } | |
545 | |
491 private: | 546 private: |
492 ReporterRunner() {} | 547 ReporterRunner() {} |
493 ~ReporterRunner() override {} | 548 ~ReporterRunner() override {} |
494 | 549 |
495 // BrowserListObserver. | 550 // BrowserListObserver. |
496 void OnBrowserSetLastActive(Browser* browser) override {} | 551 void OnBrowserSetLastActive(Browser* browser) override {} |
497 void OnBrowserRemoved(Browser* browser) override {} | 552 void OnBrowserRemoved(Browser* browser) override {} |
498 void OnBrowserAdded(Browser* browser) override { | 553 void OnBrowserAdded(Browser* browser) override { |
499 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 554 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
500 DCHECK(browser); | 555 DCHECK(browser); |
501 MaybeFetchSRT(browser, version_); | 556 MaybeFetchSRT(browser, version_); |
502 BrowserList::RemoveObserver(this); | 557 BrowserList::RemoveObserver(this); |
503 } | 558 } |
504 | 559 |
505 // This method is called on the UI thread when the reporter run has completed. | 560 // This method is called on the UI thread when the reporter run has completed. |
506 // This is run as a task posted from an interruptible worker thread so should | 561 // This is run as a task posted from an interruptible worker thread so should |
507 // be resilient to unexpected shutdown. | 562 // be resilient to unexpected shutdown. |
508 void ReporterDone(const base::Time& reporter_start_time, | 563 void ReporterDone(const base::Time& reporter_start_time, |
509 const base::Version& version, | 564 const base::Version& version, |
510 int exit_code) { | 565 const std::string& suffix, |
566 const std::vector<SwReporterInvocation>& remaining_invocations, | |
567 int exit_code) { | |
511 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 568 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
512 | 569 |
570 bool is_experimental_version = !suffix.empty(); | |
571 | |
513 base::TimeDelta reporter_running_time = | 572 base::TimeDelta reporter_running_time = |
514 base::Time::Now() - reporter_start_time; | 573 base::Time::Now() - reporter_start_time; |
515 // Don't continue when the reporter process failed to launch, but still try | 574 // Don't continue when the reporter process failed to launch, but still try |
516 // again after the regular delay. It's not worth retrying earlier, risking | 575 // again after the regular delay. It's not worth retrying earlier, risking |
517 // running too often if it always fails, since not many users fail here. | 576 // running too often if it always fails, since not many users fail here. |
518 main_thread_task_runner_->PostDelayedTask( | 577 main_thread_task_runner_->PostDelayedTask( |
519 FROM_HERE, | 578 FROM_HERE, |
520 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 579 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
521 base::TimeDelta::FromDays(days_between_reporter_runs_)); | 580 base::TimeDelta::FromDays(days_between_reporter_runs_)); |
522 if (exit_code == kReporterFailureExitCode) | 581 if (exit_code == kReporterFailureExitCode) |
523 return; | 582 return; |
524 | 583 |
525 ReportVersion(version); | 584 ReportVersion(version, suffix); |
526 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); | 585 UMA_HISTOGRAM_SPARSE_SLOWLY(AddHistogramSuffix("SoftwareReporter.ExitCode", |
527 ReportFoundUwS(); | 586 suffix), exit_code); |
587 ReportFoundUwS(suffix); | |
588 | |
589 // Only save results from the canonical version of the software. | |
528 PrefService* local_state = g_browser_process->local_state(); | 590 PrefService* local_state = g_browser_process->local_state(); |
529 if (local_state) { | 591 if (local_state && !is_experimental_version) { |
530 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); | 592 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); |
531 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, | 593 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, |
532 base::Time::Now().ToInternalValue()); | 594 base::Time::Now().ToInternalValue()); |
533 } | 595 } |
534 ReportSwReporterRuntime(reporter_running_time); | 596 |
535 ReportSwReporterScanTimes(); | 597 ReportSwReporterRuntime(reporter_running_time, suffix); |
536 ReportSwReporterMemoryUsage(); | 598 ReportSwReporterScanTimes(suffix); |
599 ReportSwReporterMemoryUsage(suffix); | |
600 | |
601 if (!remaining_invocations.empty()) { | |
602 // Only the experimental version should have multiple invocations. | |
603 DCHECK(is_experimental_version); | |
604 LaunchNextInvocation(remaining_invocations); | |
605 } | |
606 | |
607 // Only continue to launch the prompt for the canonical version. | |
608 if (is_experimental_version) | |
609 return; | |
537 | 610 |
538 if (!IsInSRTPromptFieldTrialGroups()) { | 611 if (!IsInSRTPromptFieldTrialGroups()) { |
539 // Knowing about disabled field trial is more important than reporter not | 612 // Knowing about disabled field trial is more important than reporter not |
540 // finding anything to remove, so check this case first. | 613 // finding anything to remove, so check this case first. |
541 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); | 614 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); |
542 return; | 615 return; |
543 } | 616 } |
544 | 617 |
545 if (exit_code != kSwReporterPostRebootCleanupNeeded && | 618 if (exit_code != kSwReporterPostRebootCleanupNeeded && |
546 exit_code != kSwReporterCleanupNeeded) { | 619 exit_code != kSwReporterCleanupNeeded) { |
(...skipping 13 matching lines...) Expand all Loading... | |
560 BrowserList::AddObserver(this); | 633 BrowserList::AddObserver(this); |
561 } else { | 634 } else { |
562 MaybeFetchSRT(browser, version_); | 635 MaybeFetchSRT(browser, version_); |
563 } | 636 } |
564 } | 637 } |
565 | 638 |
566 void TryToRun() { | 639 void TryToRun() { |
567 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 640 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
568 PrefService* local_state = g_browser_process->local_state(); | 641 PrefService* local_state = g_browser_process->local_state(); |
569 if (!version_.IsValid() || !local_state) { | 642 if (!version_.IsValid() || !local_state) { |
570 DCHECK(exe_path_.empty()); | 643 DCHECK(invocation_queue_.empty()); |
571 return; | 644 return; |
572 } | 645 } |
573 | 646 |
574 // Run the reporter if it hasn't been triggered in the last | 647 // Run the reporter if it hasn't been triggered in the last |
575 // |days_between_reporter_runs_| days, which depends if there is a pending | 648 // |days_between_reporter_runs_| days, which depends if there is a pending |
576 // prompt to be added to Chrome's menu. | 649 // prompt to be added to Chrome's menu. |
577 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { | 650 if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) { |
578 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; | 651 days_between_reporter_runs_ = kDaysBetweenSwReporterRunsForPendingPrompt; |
579 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); | 652 RecordReporterStepHistogram(SW_REPORTER_RAN_DAILY); |
580 } else { | 653 } else { |
581 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 654 days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
582 } | 655 } |
583 const base::Time last_time_triggered = base::Time::FromInternalValue( | 656 const base::Time last_time_triggered = base::Time::FromInternalValue( |
584 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); | 657 local_state->GetInt64(prefs::kSwReporterLastTimeTriggered)); |
585 base::TimeDelta next_trigger_delay( | 658 base::TimeDelta next_trigger_delay( |
586 last_time_triggered + | 659 last_time_triggered + |
587 base::TimeDelta::FromDays(days_between_reporter_runs_) - | 660 base::TimeDelta::FromDays(days_between_reporter_runs_) - |
588 base::Time::Now()); | 661 base::Time::Now()); |
589 if (next_trigger_delay.ToInternalValue() <= 0 || | 662 if (next_trigger_delay.ToInternalValue() <= 0 || |
590 // Also make sure the kSwReporterLastTimeTriggered value is not set in | 663 // Also make sure the kSwReporterLastTimeTriggered value is not set in |
591 // the future. | 664 // the future. |
592 last_time_triggered > base::Time::Now()) { | 665 last_time_triggered > base::Time::Now()) { |
593 // It's OK to simply |PostTaskAndReplyWithResult| so that | 666 // It's OK to simply |PostTaskAndReplyWithResult| so that |
grt (UTC plus 2)
2016/08/10 06:47:01
update comment
Joe Mason
2016/08/15 17:24:39
Done.
| |
594 // |LaunchAndWaitForExit| doesn't need to access | 667 // |LaunchAndWaitForExit| doesn't need to access |
595 // |main_thread_task_runner_| since the callback is not delayed and the | 668 // |main_thread_task_runner_| since the callback is not delayed and the |
596 // test task runner won't need to force it. | 669 // test task runner won't need to force it. |
597 base::PostTaskAndReplyWithResult( | 670 if (!invocation_queue_.empty()) |
598 blocking_task_runner_.get(), FROM_HERE, | 671 LaunchNextInvocation(invocation_queue_); |
599 base::Bind(&LaunchAndWaitForExit, exe_path_), | |
600 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this), | |
601 base::Time::Now(), version_)); | |
602 } else { | 672 } else { |
603 main_thread_task_runner_->PostDelayedTask( | 673 main_thread_task_runner_->PostDelayedTask( |
604 FROM_HERE, | 674 FROM_HERE, |
605 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), | 675 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), |
606 next_trigger_delay); | 676 next_trigger_delay); |
607 } | 677 } |
608 } | 678 } |
609 | 679 |
610 base::FilePath exe_path_; | 680 std::vector<SwReporterInvocation> invocation_queue_; |
611 base::Version version_; | 681 base::Version version_; |
612 scoped_refptr<base::TaskRunner> main_thread_task_runner_; | 682 scoped_refptr<base::TaskRunner> main_thread_task_runner_; |
613 scoped_refptr<base::TaskRunner> blocking_task_runner_; | 683 scoped_refptr<base::TaskRunner> blocking_task_runner_; |
614 | 684 |
615 // This value is used to identify how long to wait before starting a new run | 685 // This value is used to identify how long to wait before starting a new run |
616 // of the reporter. It's initialized with the default value and may be changed | 686 // of the reporter. It's initialized with the default value and may be changed |
617 // to a different value when a prompt is pending and the reporter should be | 687 // to a different value when a prompt is pending and the reporter should be |
618 // run before adding the global error to the Chrome menu. | 688 // run before adding the global error to the Chrome menu. |
619 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; | 689 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; |
620 | 690 |
621 // A single leaky instance. | 691 // A single leaky instance. |
622 static ReporterRunner* instance_; | 692 static ReporterRunner* instance_; |
623 | 693 |
624 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); | 694 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); |
625 }; | 695 }; |
626 | 696 |
627 ReporterRunner* ReporterRunner::instance_ = nullptr; | 697 ReporterRunner* ReporterRunner::instance_ = nullptr; |
628 | 698 |
629 } // namespace | 699 } // namespace |
630 | 700 |
701 SwReporterInvocation::SwReporterInvocation() | |
702 : command_line(0, nullptr) { | |
703 } | |
704 | |
705 SwReporterInvocation::SwReporterInvocation(const base::FilePath& exe_path) | |
706 : command_line(exe_path) { | |
707 } | |
708 | |
709 SwReporterInvocation::SwReporterInvocation( | |
710 const base::CommandLine& command_line, const std::string& suffix) | |
711 : command_line(command_line), suffix(suffix) { | |
712 } | |
713 | |
714 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { | |
715 return command_line.argv() == other.command_line.argv() && | |
716 suffix == other.suffix; | |
717 } | |
718 | |
631 void RunSwReporter( | 719 void RunSwReporter( |
632 const base::FilePath& exe_path, | 720 const base::FilePath& exe_path, |
633 const base::Version& version, | 721 const base::Version& version, |
634 const scoped_refptr<base::TaskRunner>& main_thread_task_runner, | 722 const scoped_refptr<base::TaskRunner>& main_thread_task_runner, |
635 const scoped_refptr<base::TaskRunner>& blocking_task_runner) { | 723 const scoped_refptr<base::TaskRunner>& blocking_task_runner) { |
636 ReporterRunner::Run(exe_path, version, main_thread_task_runner, | 724 std::vector<SwReporterInvocation> invocations = |
725 {SwReporterInvocation(exe_path)}; | |
726 ReporterRunner::Run(invocations, version, main_thread_task_runner, | |
637 blocking_task_runner); | 727 blocking_task_runner); |
638 } | 728 } |
639 | 729 |
730 void RunExperimentalSwReporters( | |
731 const std::vector<SwReporterInvocation>& invocation_queue, | |
732 const base::Version& version, | |
733 const scoped_refptr<base::TaskRunner>& main_thread_task_runner, | |
734 const scoped_refptr<base::TaskRunner>& blocking_task_runner) { | |
735 ReporterRunner::Run(invocation_queue, version, main_thread_task_runner, | |
736 blocking_task_runner); | |
737 } | |
738 | |
640 bool ReporterFoundUws() { | 739 bool ReporterFoundUws() { |
641 PrefService* local_state = g_browser_process->local_state(); | 740 PrefService* local_state = g_browser_process->local_state(); |
642 if (!local_state) | 741 if (!local_state) |
643 return false; | 742 return false; |
644 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); | 743 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); |
645 return exit_code == kSwReporterCleanupNeeded; | 744 return exit_code == kSwReporterCleanupNeeded; |
646 } | 745 } |
647 | 746 |
648 bool UserHasRunCleaner() { | 747 bool UserHasRunCleaner() { |
649 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); | 748 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); |
650 cleaner_key_path.append(L"\\").append(kCleanerSubKey); | 749 cleaner_key_path.append(L"\\").append(kCleanerSubKey); |
651 | 750 |
652 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), | 751 base::win::RegKey srt_cleaner_key(HKEY_CURRENT_USER, cleaner_key_path.c_str(), |
653 KEY_QUERY_VALUE); | 752 KEY_QUERY_VALUE); |
654 | 753 |
655 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; | 754 return srt_cleaner_key.Valid() && srt_cleaner_key.GetValueCount() > 0; |
656 } | 755 } |
657 | 756 |
658 void SetReporterLauncherForTesting(const ReporterLauncher& reporter_launcher) { | 757 void SetReporterLauncherForTesting(const ReporterLauncher& reporter_launcher) { |
659 g_reporter_launcher_ = reporter_launcher; | 758 g_reporter_launcher_ = reporter_launcher; |
660 } | 759 } |
661 | 760 |
662 void SetPromptTriggerForTesting(const PromptTrigger& prompt_trigger) { | 761 void SetPromptTriggerForTesting(const PromptTrigger& prompt_trigger) { |
663 g_prompt_trigger_ = prompt_trigger; | 762 g_prompt_trigger_ = prompt_trigger; |
664 } | 763 } |
665 | 764 |
666 } // namespace safe_browsing | 765 } // namespace safe_browsing |
OLD | NEW |