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

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

Issue 2226133005: Add support for the ExperimentalSwReporterEngine field trial. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Refactor, split some prep work into a different patch Created 4 years, 4 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" 5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 #include <queue>
10 #include <vector> 11 #include <vector>
11 12
12 #include "base/bind.h" 13 #include "base/bind.h"
13 #include "base/bind_helpers.h" 14 #include "base/bind_helpers.h"
14 #include "base/callback_helpers.h" 15 #include "base/callback_helpers.h"
15 #include "base/command_line.h" 16 #include "base/command_line.h"
16 #include "base/files/file_path.h" 17 #include "base/files/file_path.h"
17 #include "base/macros.h" 18 #include "base/macros.h"
18 #include "base/metrics/field_trial.h" 19 #include "base/metrics/field_trial.h"
19 #include "base/metrics/histogram_macros.h" 20 #include "base/metrics/histogram.h"
20 #include "base/metrics/sparse_histogram.h" 21 #include "base/metrics/sparse_histogram.h"
21 #include "base/process/launch.h" 22 #include "base/process/launch.h"
22 #include "base/strings/string_number_conversions.h" 23 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/stringprintf.h" 24 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h" 25 #include "base/strings/utf_string_conversions.h"
25 #include "base/task_runner_util.h" 26 #include "base/task_runner_util.h"
26 #include "base/time/time.h" 27 #include "base/time/time.h"
27 #include "base/win/registry.h" 28 #include "base/win/registry.h"
28 #include "chrome/browser/browser_process.h" 29 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" 30 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 const wchar_t kFoundUwsValueName[] = L"FoundUws"; 114 const wchar_t kFoundUwsValueName[] = L"FoundUws";
114 const wchar_t kMemoryUsedValueName[] = L"MemoryUsed"; 115 const wchar_t kMemoryUsedValueName[] = L"MemoryUsed";
115 116
116 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS"; 117 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS";
117 const char kFoundUwsReadErrorMetricName[] = 118 const char kFoundUwsReadErrorMetricName[] =
118 "SoftwareReporter.FoundUwSReadError"; 119 "SoftwareReporter.FoundUwSReadError";
119 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes"; 120 const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes";
120 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed"; 121 const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed";
121 122
122 // Reports metrics about the software reporter via UMA (and sometimes Rappor). 123 // Reports metrics about the software reporter via UMA (and sometimes Rappor).
124 //
125 // This will format the names of the histograms at runtime by adding an
126 // optional suffix, so the UMA_HISTOGRAM macros won't work. Use RecordHistogram
127 // and related helper methods instead.
123 class UMAHistogramReporter { 128 class UMAHistogramReporter {
124 public: 129 public:
130 UMAHistogramReporter(const std::string& suffix = std::string())
131 : suffix_(suffix),
132 registry_key_(suffix.empty()
133 ? kSoftwareRemovalToolRegistryKey
134 : base::StringPrintf(L"%s\\%s",
135 kSoftwareRemovalToolRegistryKey,
136 base::UTF8ToUTF16(suffix))) {}
137
125 // Reports the software reporter tool's version via UMA. 138 // Reports the software reporter tool's version via UMA.
126 void ReportVersion(const base::Version& version) const { 139 void ReportVersion(const base::Version& version) const {
127 DCHECK(!version.components().empty()); 140 DCHECK(!version.components().empty());
128 // The minor version is the 2nd last component of the version, 141 // The minor version is the 2nd last component of the version,
129 // or just the first component if there is only 1. 142 // or just the first component if there is only 1.
130 uint32_t minor_version = 0; 143 uint32_t minor_version = 0;
131 if (version.components().size() > 1) 144 if (version.components().size() > 1)
132 minor_version = version.components()[version.components().size() - 2]; 145 minor_version = version.components()[version.components().size() - 2];
133 else 146 else
134 minor_version = version.components()[0]; 147 minor_version = version.components()[0];
135 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MinorVersion", minor_version); 148 RecordSparseHistogram("SoftwareReporter.MinorVersion", minor_version);
136 149
137 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional 150 // The major version for X.Y.Z is X*256^3+Y*256+Z. If there are additional
138 // components, only the first three count, and if there are less than 3, the 151 // components, only the first three count, and if there are less than 3, the
139 // missing values are just replaced by zero. So 1 is equivalent 1.0.0. 152 // missing values are just replaced by zero. So 1 is equivalent 1.0.0.
140 DCHECK_LT(version.components()[0], 0x100U); 153 DCHECK_LT(version.components()[0], 0x100U);
141 uint32_t major_version = 0x1000000 * version.components()[0]; 154 uint32_t major_version = 0x1000000 * version.components()[0];
142 if (version.components().size() >= 2) { 155 if (version.components().size() >= 2) {
143 DCHECK_LT(version.components()[1], 0x10000U); 156 DCHECK_LT(version.components()[1], 0x10000U);
144 major_version += 0x100 * version.components()[1]; 157 major_version += 0x100 * version.components()[1];
145 } 158 }
146 if (version.components().size() >= 3) { 159 if (version.components().size() >= 3) {
147 DCHECK_LT(version.components()[2], 0x100U); 160 DCHECK_LT(version.components()[2], 0x100U);
148 major_version += version.components()[2]; 161 major_version += version.components()[2];
149 } 162 }
150 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.MajorVersion", major_version); 163 RecordSparseHistogram("SoftwareReporter.MajorVersion", major_version);
151 } 164 }
152 165
153 void ReportExitCode(int exit_code) const { 166 void ReportExitCode(int exit_code) const {
154 UMA_HISTOGRAM_SPARSE_SLOWLY("SoftwareReporter.ExitCode", exit_code); 167 RecordSparseHistogram("SoftwareReporter.ExitCode", exit_code);
155 } 168 }
156 169
157 // Reports UwS found by the software reporter tool via UMA and RAPPOR. 170 // Reports UwS found by the software reporter tool via UMA and RAPPOR.
158 void ReportFoundUwS() const { 171 void ReportFoundUwS(bool use_rappor) const {
159 base::win::RegKey reporter_key(HKEY_CURRENT_USER, 172 base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(),
160 kSoftwareRemovalToolRegistryKey,
161 KEY_QUERY_VALUE | KEY_SET_VALUE); 173 KEY_QUERY_VALUE | KEY_SET_VALUE);
162 std::vector<base::string16> found_uws_strings; 174 std::vector<base::string16> found_uws_strings;
163 if (reporter_key.Valid() && 175 if (reporter_key.Valid() &&
164 reporter_key.ReadValues(kFoundUwsValueName, &found_uws_strings) == 176 reporter_key.ReadValues(kFoundUwsValueName, &found_uws_strings) ==
165 ERROR_SUCCESS) { 177 ERROR_SUCCESS) {
166 rappor::RapporService* rappor_service = 178 rappor::RapporService* rappor_service = nullptr;
167 g_browser_process->rappor_service(); 179 if (use_rappor)
180 rappor_service = g_browser_process->rappor_service();
168 181
169 bool parse_error = false; 182 bool parse_error = false;
170 for (const base::string16& uws_string : found_uws_strings) { 183 for (const base::string16& uws_string : found_uws_strings) {
171 // All UwS ids are expected to be integers. 184 // All UwS ids are expected to be integers.
172 uint32_t uws_id = 0; 185 uint32_t uws_id = 0;
173 if (base::StringToUint(uws_string, &uws_id)) { 186 if (base::StringToUint(uws_string, &uws_id)) {
174 UMA_HISTOGRAM_SPARSE_SLOWLY(kFoundUwsMetricName, uws_id); 187 RecordSparseHistogram(kFoundUwsMetricName, uws_id);
175 if (rappor_service) { 188 if (rappor_service) {
176 rappor_service->RecordSample(kFoundUwsMetricName, 189 rappor_service->RecordSample(kFoundUwsMetricName,
177 rappor::COARSE_RAPPOR_TYPE, 190 rappor::COARSE_RAPPOR_TYPE,
178 base::UTF16ToUTF8(uws_string)); 191 base::UTF16ToUTF8(uws_string));
179 } 192 }
180 } else { 193 } else {
181 parse_error = true; 194 parse_error = true;
182 } 195 }
183 } 196 }
184 197
185 // Clean up the old value. 198 // Clean up the old value.
186 reporter_key.DeleteValue(kFoundUwsValueName); 199 reporter_key.DeleteValue(kFoundUwsValueName);
187 200
188 UMA_HISTOGRAM_BOOLEAN(kFoundUwsReadErrorMetricName, parse_error); 201 RecordBooleanHistogram(kFoundUwsReadErrorMetricName, parse_error);
189 } 202 }
190 } 203 }
191 204
192 // Reports to UMA the memory usage of the software reporter tool as reported 205 // Reports to UMA the memory usage of the software reporter tool as reported
193 // by 206 // by
194 // the tool itself in the Windows registry. 207 // the tool itself in the Windows registry.
195 void ReportMemoryUsage() const { 208 void ReportMemoryUsage() const {
196 base::win::RegKey reporter_key(HKEY_CURRENT_USER, 209 base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(),
197 kSoftwareRemovalToolRegistryKey,
198 KEY_QUERY_VALUE | KEY_SET_VALUE); 210 KEY_QUERY_VALUE | KEY_SET_VALUE);
199 DWORD memory_used = 0; 211 DWORD memory_used = 0;
200 if (reporter_key.Valid() && 212 if (reporter_key.Valid() &&
201 reporter_key.ReadValueDW(kMemoryUsedValueName, &memory_used) == 213 reporter_key.ReadValueDW(kMemoryUsedValueName, &memory_used) ==
202 ERROR_SUCCESS) { 214 ERROR_SUCCESS) {
203 UMA_HISTOGRAM_MEMORY_KB(kMemoryUsedMetricName, memory_used); 215 RecordMemoryKBHistogram(kMemoryUsedMetricName, memory_used);
204 reporter_key.DeleteValue(kMemoryUsedValueName); 216 reporter_key.DeleteValue(kMemoryUsedValueName);
205 } 217 }
206 } 218 }
207 219
208 // Report the SwReporter run time with UMA both as reported by the tool via 220 // Report the SwReporter run time with UMA both as reported by the tool via
209 // the registry and as measured by |ReporterRunner|. 221 // the registry and as measured by |ReporterRunner|.
210 void ReportRuntime(const base::TimeDelta& reporter_running_time) const { 222 void ReportRuntime(const base::TimeDelta& reporter_running_time) const {
211 UMA_HISTOGRAM_LONG_TIMES("SoftwareReporter.RunningTimeAccordingToChrome", 223 RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome",
212 reporter_running_time); 224 reporter_running_time);
213 225
214 base::win::RegKey reporter_key( 226 base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(),
215 HKEY_CURRENT_USER, kSoftwareRemovalToolRegistryKey, KEY_ALL_ACCESS); 227 KEY_ALL_ACCESS);
216 if (!reporter_key.Valid()) { 228 if (!reporter_key.Valid()) {
217 UMA_HISTOGRAM_ENUMERATION( 229 RecordEnumerationHistogram(
218 kRunningTimeErrorMetricName, 230 kRunningTimeErrorMetricName,
219 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID, 231 REPORTER_RUNNING_TIME_ERROR_REGISTRY_KEY_INVALID,
220 REPORTER_RUNNING_TIME_ERROR_MAX); 232 REPORTER_RUNNING_TIME_ERROR_MAX);
221 return; 233 return;
222 } 234 }
223 235
224 bool has_start_time = false; 236 bool has_start_time = false;
225 int64_t start_time_value = 0; 237 int64_t start_time_value = 0;
226 if (reporter_key.HasValue(kStartTimeValueName) && 238 if (reporter_key.HasValue(kStartTimeValueName) &&
227 reporter_key.ReadInt64(kStartTimeValueName, &start_time_value) == 239 reporter_key.ReadInt64(kStartTimeValueName, &start_time_value) ==
228 ERROR_SUCCESS) { 240 ERROR_SUCCESS) {
229 has_start_time = true; 241 has_start_time = true;
230 reporter_key.DeleteValue(kStartTimeValueName); 242 reporter_key.DeleteValue(kStartTimeValueName);
231 } 243 }
232 244
233 bool has_end_time = false; 245 bool has_end_time = false;
234 int64_t end_time_value = 0; 246 int64_t end_time_value = 0;
235 if (reporter_key.HasValue(kEndTimeValueName) && 247 if (reporter_key.HasValue(kEndTimeValueName) &&
236 reporter_key.ReadInt64(kEndTimeValueName, &end_time_value) == 248 reporter_key.ReadInt64(kEndTimeValueName, &end_time_value) ==
237 ERROR_SUCCESS) { 249 ERROR_SUCCESS) {
238 has_end_time = true; 250 has_end_time = true;
239 reporter_key.DeleteValue(kEndTimeValueName); 251 reporter_key.DeleteValue(kEndTimeValueName);
240 } 252 }
241 253
242 if (has_start_time && has_end_time) { 254 if (has_start_time && has_end_time) {
243 base::TimeDelta registry_run_time = 255 base::TimeDelta registry_run_time =
244 base::Time::FromInternalValue(end_time_value) - 256 base::Time::FromInternalValue(end_time_value) -
245 base::Time::FromInternalValue(start_time_value); 257 base::Time::FromInternalValue(start_time_value);
246 UMA_HISTOGRAM_LONG_TIMES("SoftwareReporter.RunningTime", 258 RecordLongTimesHistogram("SoftwareReporter.RunningTime",
247 registry_run_time); 259 registry_run_time);
248 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, 260 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
249 REPORTER_RUNNING_TIME_ERROR_NO_ERROR, 261 REPORTER_RUNNING_TIME_ERROR_NO_ERROR,
250 REPORTER_RUNNING_TIME_ERROR_MAX); 262 REPORTER_RUNNING_TIME_ERROR_MAX);
251 } else if (!has_start_time && !has_end_time) { 263 } else if (!has_start_time && !has_end_time) {
252 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, 264 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
253 REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES, 265 REPORTER_RUNNING_TIME_ERROR_MISSING_BOTH_TIMES,
254 REPORTER_RUNNING_TIME_ERROR_MAX); 266 REPORTER_RUNNING_TIME_ERROR_MAX);
255 } else if (!has_start_time) { 267 } else if (!has_start_time) {
256 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, 268 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
257 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME, 269 REPORTER_RUNNING_TIME_ERROR_MISSING_START_TIME,
258 REPORTER_RUNNING_TIME_ERROR_MAX); 270 REPORTER_RUNNING_TIME_ERROR_MAX);
259 } else { 271 } else {
260 DCHECK(!has_end_time); 272 DCHECK(!has_end_time);
261 UMA_HISTOGRAM_ENUMERATION(kRunningTimeErrorMetricName, 273 RecordEnumerationHistogram(kRunningTimeErrorMetricName,
262 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME, 274 REPORTER_RUNNING_TIME_ERROR_MISSING_END_TIME,
263 REPORTER_RUNNING_TIME_ERROR_MAX); 275 REPORTER_RUNNING_TIME_ERROR_MAX);
264 } 276 }
265 } 277 }
266 278
267 // Report the UwS scan times of the software reporter tool via UMA. 279 // Report the UwS scan times of the software reporter tool via UMA.
268 void ReportScanTimes() const { 280 void ReportScanTimes() const {
269 base::string16 scan_times_key_path = base::StringPrintf( 281 base::string16 scan_times_key_path = base::StringPrintf(
270 L"%ls\\%ls", kSoftwareRemovalToolRegistryKey, kScanTimesSubKey); 282 L"%ls\\%ls", registry_key_.c_str(), kScanTimesSubKey);
271 base::win::RegKey scan_times_key( 283 base::win::RegKey scan_times_key(
272 HKEY_CURRENT_USER, scan_times_key_path.c_str(), KEY_ALL_ACCESS); 284 HKEY_CURRENT_USER, scan_times_key_path.c_str(), KEY_ALL_ACCESS);
273 if (!scan_times_key.Valid()) 285 if (!scan_times_key.Valid())
274 return; 286 return;
275 287
276 base::string16 value_name; 288 base::string16 value_name;
277 int uws_id = 0; 289 int uws_id = 0;
278 int64_t raw_scan_time = 0; 290 int64_t raw_scan_time = 0;
279 int num_scan_times = scan_times_key.GetValueCount(); 291 int num_scan_times = scan_times_key.GetValueCount();
280 for (int i = 0; i < num_scan_times; ++i) { 292 for (int i = 0; i < num_scan_times; ++i) {
281 if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS && 293 if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS &&
282 base::StringToInt(value_name, &uws_id) && 294 base::StringToInt(value_name, &uws_id) &&
283 scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) == 295 scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) ==
284 ERROR_SUCCESS) { 296 ERROR_SUCCESS) {
285 base::TimeDelta scan_time = 297 base::TimeDelta scan_time =
286 base::TimeDelta::FromInternalValue(raw_scan_time); 298 base::TimeDelta::FromInternalValue(raw_scan_time);
287 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( 299 // We report the number of seconds plus one because it can take less
288 kScanTimesMetricName, 300 // than one second to scan some UwS and the count passed to |AddCount|
289 base::HistogramBase::kUmaTargetedHistogramFlag); 301 // must be at least one.
290 if (histogram) { 302 RecordSparseHistogramCount(kScanTimesMetricName, uws_id,
291 // We report the number of seconds plus one because it can take less 303 scan_time.InSeconds() + 1);
292 // than one second to scan some UwS and the count passed to |AddCount|
293 // must be at least one.
294 histogram->AddCount(uws_id, scan_time.InSeconds() + 1);
295 }
296 } 304 }
297 } 305 }
298 // Clean up by deleting the scan times key, which is a subkey of the main 306 // Clean up by deleting the scan times key, which is a subkey of the main
299 // reporter key. 307 // reporter key.
300 scan_times_key.Close(); 308 scan_times_key.Close();
301 base::win::RegKey reporter_key(HKEY_CURRENT_USER, 309 base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(),
302 kSoftwareRemovalToolRegistryKey,
303 KEY_ENUMERATE_SUB_KEYS); 310 KEY_ENUMERATE_SUB_KEYS);
304 if (reporter_key.Valid()) 311 if (reporter_key.Valid())
305 reporter_key.DeleteKey(kScanTimesSubKey); 312 reporter_key.DeleteKey(kScanTimesSubKey);
306 } 313 }
314
315 void RecordReporterStep(SwReporterUmaValue value) {
316 RecordEnumerationHistogram("SoftwareReporter.Step", value, SW_REPORTER_MAX);
317 }
318
319 private:
320 std::string FullName(const std::string& name) const {
321 if (suffix_.empty())
322 return name;
323 return base::StringPrintf("%s_%s", name, suffix_);
324 }
325
326 template <typename HistogramType, typename SampleType>
327 void RecordHistogram(const std::string& name, SampleType sample) const {
328 base::HistogramBase* histogram = HistogramType::FactoryGet(
329 FullName(name), base::HistogramBase::kUmaTargetedHistogramFlag);
330 if (histogram)
331 histogram->Add(sample);
332 }
333
334 template <typename SampleType>
335 void RecordBooleanHistogram(const std::string& name,
336 SampleType sample) const {
337 RecordHistogram<base::BooleanHistogram, SampleType>(name, sample);
338 }
339
340 template <typename SampleType>
341 void RecordEnumerationHistogram(const std::string& name,
342 SampleType sample,
343 SampleType boundary) const {
344 // See HISTOGRAM_ENUMERATION_WITH_FLAG.
345 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
346 FullName(name), 1, boundary, boundary + 1,
347 base::HistogramBase::kUmaTargetedHistogramFlag);
348 if (histogram)
349 histogram->Add(sample);
350 }
351
352 template <typename SampleType>
353 void RecordLongTimesHistogram(const std::string& name,
354 SampleType sample) const {
355 // See UMA_HISTOGRAM_LONG_TIMES.
356 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet(
357 FullName(name), base::TimeDelta::FromMilliseconds(1),
358 base::TimeDelta::FromHours(1), 100,
359 base::HistogramBase::kUmaTargetedHistogramFlag);
360 if (histogram)
361 histogram->AddTime(sample);
362 }
363
364 template <typename SampleType>
365 void RecordMemoryKBHistogram(const std::string& name,
366 SampleType sample) const {
367 // See UMA_HISTOGRAM_MEMORY_KB.
368 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
369 FullName(name), 1000, 500000, 50,
370 base::HistogramBase::kUmaTargetedHistogramFlag);
371 if (histogram)
372 histogram->Add(sample);
373 }
374
375 template <typename SampleType>
376 void RecordSparseHistogram(const std::string& name, SampleType sample) const {
377 RecordHistogram<base::SparseHistogram, SampleType>(name, sample);
378 }
379
380 template <typename SampleType>
381 void RecordSparseHistogramCount(const std::string& name,
382 SampleType sample,
383 int count) const {
384 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
385 FullName(name), base::HistogramBase::kUmaTargetedHistogramFlag);
386 if (histogram)
387 histogram->AddCount(sample, count);
388 }
389
390 std::string suffix_;
391 std::wstring registry_key_;
307 }; 392 };
308 393
309 void RecordReporterStepHistogram(SwReporterUmaValue value) { 394 void RecordReporterStepHistogram(SwReporterUmaValue value) {
310 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.Step", value, SW_REPORTER_MAX); 395 UMAHistogramReporter uma;
396 uma.RecordReporterStep(value);
311 } 397 }
312 398
313 void DisplaySRTPrompt(const base::FilePath& download_path) { 399 void DisplaySRTPrompt(const base::FilePath& download_path) {
314 // Find the last active browser, which may be NULL, in which case we won't 400 // Find the last active browser, which may be NULL, in which case we won't
315 // show the prompt this time and will wait until the next run of the 401 // show the prompt this time and will wait until the next run of the
316 // reporter. We can't use other ways of finding a browser because we don't 402 // reporter. We can't use other ways of finding a browser because we don't
317 // have a profile. 403 // have a profile.
318 Browser* browser = chrome::FindLastActive(); 404 Browser* browser = chrome::FindLastActive();
319 if (!browser) 405 if (!browser)
320 return; 406 return;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 // interrupted by a shutdown at any time, so it shouldn't depend on anything 450 // interrupted by a shutdown at any time, so it shouldn't depend on anything
365 // external that could be shut down beforehand. 451 // external that could be shut down beforehand.
366 int LaunchAndWaitForExit(const SwReporterInvocation& invocation) { 452 int LaunchAndWaitForExit(const SwReporterInvocation& invocation) {
367 if (!g_reporter_launcher_.is_null()) 453 if (!g_reporter_launcher_.is_null())
368 return g_reporter_launcher_.Run(invocation); 454 return g_reporter_launcher_.Run(invocation);
369 base::Process reporter_process = 455 base::Process reporter_process =
370 base::LaunchProcess(invocation.command_line, base::LaunchOptions()); 456 base::LaunchProcess(invocation.command_line, base::LaunchOptions());
371 // This exit code is used to identify that a reporter run didn't happen, so 457 // This exit code is used to identify that a reporter run didn't happen, so
372 // the result should be ignored and a rerun scheduled for the usual delay. 458 // the result should be ignored and a rerun scheduled for the usual delay.
373 int exit_code = kReporterFailureExitCode; 459 int exit_code = kReporterFailureExitCode;
460 UMAHistogramReporter uma(invocation.suffix);
374 if (reporter_process.IsValid()) { 461 if (reporter_process.IsValid()) {
375 RecordReporterStepHistogram(SW_REPORTER_START_EXECUTION); 462 uma.RecordReporterStep(SW_REPORTER_START_EXECUTION);
376 bool success = reporter_process.WaitForExit(&exit_code); 463 bool success = reporter_process.WaitForExit(&exit_code);
377 DCHECK(success); 464 DCHECK(success);
378 } else { 465 } else {
379 RecordReporterStepHistogram(SW_REPORTER_FAILED_TO_START); 466 uma.RecordReporterStep(SW_REPORTER_FAILED_TO_START);
380 } 467 }
381 return exit_code; 468 return exit_code;
382 } 469 }
383 470
384 } // namespace 471 } // namespace
385 472
386 // Class that will attempt to download the SRT, showing the SRT notification 473 // Class that will attempt to download the SRT, showing the SRT notification
387 // bubble when the download operation is complete. Instances of SRTFetcher own 474 // bubble when the download operation is complete. Instances of SRTFetcher own
388 // themselves, they will self-delete on completion of the network request when 475 // themselves, they will self-delete on completion of the network request when
389 // OnURLFetchComplete is called. 476 // OnURLFetchComplete is called.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 new SRTFetcher(profile); 592 new SRTFetcher(profile);
506 } 593 }
507 594
508 // This class tries to run the reporter and reacts to its exit code. It 595 // This class tries to run the reporter and reacts to its exit code. It
509 // schedules subsequent runs as needed, or retries as soon as a browser is 596 // schedules subsequent runs as needed, or retries as soon as a browser is
510 // available when none is on first try. 597 // available when none is on first try.
511 class ReporterRunner : public chrome::BrowserListObserver { 598 class ReporterRunner : public chrome::BrowserListObserver {
512 public: 599 public:
513 // Starts the sequence of attempts to run the reporter. 600 // Starts the sequence of attempts to run the reporter.
514 static void Run( 601 static void Run(
515 const SwReporterInvocation& invocation, 602 const std::queue<SwReporterInvocation>& invocations,
516 const base::Version& version, 603 const base::Version& version,
517 const scoped_refptr<base::TaskRunner>& main_thread_task_runner, 604 const scoped_refptr<base::TaskRunner>& main_thread_task_runner,
518 const scoped_refptr<base::TaskRunner>& blocking_task_runner) { 605 const scoped_refptr<base::TaskRunner>& blocking_task_runner) {
519 if (!instance_) 606 if (!instance_)
520 instance_ = new ReporterRunner; 607 instance_ = new ReporterRunner;
521 DCHECK_CURRENTLY_ON(BrowserThread::UI); 608 DCHECK_CURRENTLY_ON(BrowserThread::UI);
522 // There's nothing to do if the path and version of the reporter has not 609 // There's nothing to do if the path and version of the reporter has not
523 // changed, we just keep running the tasks that are running now. 610 // changed, we just keep running the tasks that are running now.
524 if (instance_->invocation_ == invocation && instance_->version_.IsValid() && 611 if (instance_->invocations_ == invocations &&
525 instance_->version_ == version) 612 instance_->version_.IsValid() && instance_->version_ == version)
526 return; 613 return;
527 614
528 instance_->invocation_ = invocation; 615 instance_->invocations_ = invocations;
529 instance_->version_ = version; 616 instance_->version_ = version;
530 instance_->main_thread_task_runner_ = main_thread_task_runner; 617 instance_->main_thread_task_runner_ = main_thread_task_runner;
531 instance_->blocking_task_runner_ = blocking_task_runner; 618 instance_->blocking_task_runner_ = blocking_task_runner;
532 619
533 if (instance_->first_run_) { 620 if (instance_->first_run_) {
534 instance_->first_run_ = false; 621 instance_->first_run_ = false;
535 instance_->TryToRun(); 622 instance_->TryToRun();
536 } 623 }
537 } 624 }
538 625
626 // Launch the command line at the head of the queue.
627 void LaunchNextInvocation(
628 const std::queue<SwReporterInvocation>& invocations) {
629 DCHECK(!invocations.empty());
630 // Make a non-const copy of the queue so it can be manipulated.
631 auto remaining_invocations = invocations;
632 auto next_invocation = remaining_invocations.front();
633 remaining_invocations.pop();
634
635 // It's OK to simply |PostTaskAndReplyWithResult| so that
636 // |LaunchAndWaitForExit| doesn't need to access |main_thread_task_runner_|
637 // since the callback is not delayed and the test task runner won't need to
638 // force it.
639 base::PostTaskAndReplyWithResult(
640 blocking_task_runner_.get(), FROM_HERE,
641
642 // Send the head of the queue to the launch callback.
643 base::Bind(&LaunchAndWaitForExit, next_invocation),
644
645 // Send the tail of the queue to the next callback, which will handle
646 // the
647 // results of the first launch and then recursively launch everything in
648 // the tail.
649 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this),
650 base::Time::Now(), version_, next_invocation,
651 remaining_invocations));
652 }
653
539 private: 654 private:
540 ReporterRunner() : first_run_(true) {} 655 ReporterRunner() : first_run_(true) {}
541 ~ReporterRunner() override {} 656 ~ReporterRunner() override {}
542 657
543 // BrowserListObserver. 658 // BrowserListObserver.
544 void OnBrowserSetLastActive(Browser* browser) override {} 659 void OnBrowserSetLastActive(Browser* browser) override {}
545 void OnBrowserRemoved(Browser* browser) override {} 660 void OnBrowserRemoved(Browser* browser) override {}
546 void OnBrowserAdded(Browser* browser) override { 661 void OnBrowserAdded(Browser* browser) override {
547 DCHECK_CURRENTLY_ON(BrowserThread::UI); 662 DCHECK_CURRENTLY_ON(BrowserThread::UI);
548 DCHECK(browser); 663 DCHECK(browser);
549 MaybeFetchSRT(browser, version_); 664 MaybeFetchSRT(browser, version_);
550 BrowserList::RemoveObserver(this); 665 BrowserList::RemoveObserver(this);
551 } 666 }
552 667
553 // This method is called on the UI thread when the reporter run has completed. 668 // This method is called on the UI thread when the reporter run has completed.
554 // This is run as a task posted from an interruptible worker thread so should 669 // This is run as a task posted from an interruptible worker thread so should
555 // be resilient to unexpected shutdown. 670 // be resilient to unexpected shutdown.
556 void ReporterDone(const base::Time& reporter_start_time, 671 void ReporterDone(
557 const base::Version& version, 672 const base::Time& reporter_start_time,
558 int exit_code) { 673 const base::Version& version,
674 const SwReporterInvocation& finished_invocation,
675 const std::queue<SwReporterInvocation>& remaining_invocations,
676 int exit_code) {
559 DCHECK_CURRENTLY_ON(BrowserThread::UI); 677 DCHECK_CURRENTLY_ON(BrowserThread::UI);
560 678
561 if (g_reporter_done_notifier_) 679 if (g_reporter_done_notifier_)
562 g_reporter_done_notifier_.Run(); 680 g_reporter_done_notifier_.Run();
563 681
564 base::TimeDelta reporter_running_time = 682 base::TimeDelta reporter_running_time =
565 base::Time::Now() - reporter_start_time; 683 base::Time::Now() - reporter_start_time;
566 // Don't continue when the reporter process failed to launch, but still try 684 // Don't continue when the reporter process failed to launch, but still try
567 // again after the regular delay. It's not worth retrying earlier, risking 685 // again after the regular delay. It's not worth retrying earlier, risking
568 // running too often if it always fails, since not many users fail here. 686 // running too often if it always fails, since not many users fail here.
569 main_thread_task_runner_->PostDelayedTask( 687 main_thread_task_runner_->PostDelayedTask(
570 FROM_HERE, 688 FROM_HERE,
571 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), 689 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
572 base::TimeDelta::FromDays(days_between_reporter_runs_)); 690 base::TimeDelta::FromDays(days_between_reporter_runs_));
573 if (exit_code == kReporterFailureExitCode) 691 if (exit_code == kReporterFailureExitCode)
574 return; 692 return;
575 693
576 UMAHistogramReporter uma; 694 UMAHistogramReporter uma(finished_invocation.suffix);
577 uma.ReportVersion(version); 695 uma.ReportVersion(version);
578 uma.ReportExitCode(exit_code); 696 uma.ReportExitCode(exit_code);
579 uma.ReportFoundUwS(); 697 uma.ReportFoundUwS(!finished_invocation.is_experimental /*use_rappor*/);
698
699 // Only save results from the canonical version of the software.
580 PrefService* local_state = g_browser_process->local_state(); 700 PrefService* local_state = g_browser_process->local_state();
581 if (local_state) { 701 if (local_state && !finished_invocation.is_experimental) {
582 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code); 702 local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code);
583 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered, 703 local_state->SetInt64(prefs::kSwReporterLastTimeTriggered,
584 base::Time::Now().ToInternalValue()); 704 base::Time::Now().ToInternalValue());
585 } 705 }
586 uma.ReportRuntime(reporter_running_time); 706 uma.ReportRuntime(reporter_running_time);
587 uma.ReportScanTimes(); 707 uma.ReportScanTimes();
588 uma.ReportMemoryUsage(); 708 uma.ReportMemoryUsage();
589 709
710 if (!remaining_invocations.empty()) {
711 // Only the experimental version should have multiple invocations.
712 DCHECK(finished_invocation.is_experimental);
713 LaunchNextInvocation(remaining_invocations);
714 }
715
716 // Only continue to launch the prompt for the canonical version.
717 if (finished_invocation.is_experimental)
718 return;
719
590 if (!IsInSRTPromptFieldTrialGroups()) { 720 if (!IsInSRTPromptFieldTrialGroups()) {
591 // Knowing about disabled field trial is more important than reporter not 721 // Knowing about disabled field trial is more important than reporter not
592 // finding anything to remove, so check this case first. 722 // finding anything to remove, so check this case first.
593 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_FIELD_TRIAL); 723 uma.RecordReporterStep(SW_REPORTER_NO_PROMPT_FIELD_TRIAL);
594 return; 724 return;
595 } 725 }
596 726
597 if (exit_code != kSwReporterPostRebootCleanupNeeded && 727 if (exit_code != kSwReporterPostRebootCleanupNeeded &&
598 exit_code != kSwReporterCleanupNeeded) { 728 exit_code != kSwReporterCleanupNeeded) {
599 RecordReporterStepHistogram(SW_REPORTER_NO_PROMPT_NEEDED); 729 uma.RecordReporterStep(SW_REPORTER_NO_PROMPT_NEEDED);
600 return; 730 return;
601 } 731 }
602 732
603 // Find the last active browser, which may be NULL, in which case we need 733 // Find the last active browser, which may be NULL, in which case we need
604 // to wait for one to be available. We can't use other ways of finding a 734 // to wait for one to be available. We can't use other ways of finding a
605 // browser because we don't have a profile. And we need a browser to get to 735 // browser because we don't have a profile. And we need a browser to get to
606 // a profile, which we need, to tell whether we should prompt or not. 736 // a profile, which we need, to tell whether we should prompt or not.
607 // TODO(mad): crbug.com/503269, investigate whether we should change how we 737 // TODO(mad): crbug.com/503269, investigate whether we should change how we
608 // decide when it's time to download the SRT and when to display the prompt. 738 // decide when it's time to download the SRT and when to display the prompt.
609 Browser* browser = chrome::FindLastActive(); 739 Browser* browser = chrome::FindLastActive();
610 if (!browser) { 740 if (!browser) {
611 RecordReporterStepHistogram(SW_REPORTER_NO_BROWSER); 741 uma.RecordReporterStep(SW_REPORTER_NO_BROWSER);
612 BrowserList::AddObserver(this); 742 BrowserList::AddObserver(this);
613 } else { 743 } else {
614 MaybeFetchSRT(browser, version_); 744 MaybeFetchSRT(browser, version_);
615 } 745 }
616 } 746 }
617 747
618 void TryToRun() { 748 void TryToRun() {
619 DCHECK_CURRENTLY_ON(BrowserThread::UI); 749 DCHECK_CURRENTLY_ON(BrowserThread::UI);
620 PrefService* local_state = g_browser_process->local_state(); 750 PrefService* local_state = g_browser_process->local_state();
621 if (!version_.IsValid() || !local_state) { 751 if (!version_.IsValid() || !local_state) {
(...skipping 16 matching lines...) Expand all
638 last_time_triggered + 768 last_time_triggered +
639 base::TimeDelta::FromDays(days_between_reporter_runs_) - 769 base::TimeDelta::FromDays(days_between_reporter_runs_) -
640 base::Time::Now()); 770 base::Time::Now());
641 if (next_trigger_delay.ToInternalValue() <= 0 || 771 if (next_trigger_delay.ToInternalValue() <= 0 ||
642 // Also make sure the kSwReporterLastTimeTriggered value is not set in 772 // Also make sure the kSwReporterLastTimeTriggered value is not set in
643 // the future. 773 // the future.
644 last_time_triggered > base::Time::Now()) { 774 last_time_triggered > base::Time::Now()) {
645 if (g_launch_ready_notifier_) 775 if (g_launch_ready_notifier_)
646 g_launch_ready_notifier_.Run(); 776 g_launch_ready_notifier_.Run();
647 777
648 // It's OK to simply |PostTaskAndReplyWithResult| so that 778 if (!invocations_.empty())
649 // |LaunchAndWaitForExit| doesn't need to access 779 LaunchNextInvocation(invocations_);
650 // |main_thread_task_runner_| since the callback is not delayed and the
651 // test task runner won't need to force it.
652 base::PostTaskAndReplyWithResult(
653 blocking_task_runner_.get(), FROM_HERE,
654 base::Bind(&LaunchAndWaitForExit, invocation_),
655 base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this),
656 base::Time::Now(), version_));
657 } else { 780 } else {
658 main_thread_task_runner_->PostDelayedTask( 781 main_thread_task_runner_->PostDelayedTask(
659 FROM_HERE, 782 FROM_HERE,
660 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)), 783 base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
661 next_trigger_delay); 784 next_trigger_delay);
662 } 785 }
663 } 786 }
664 787
665 bool first_run_; 788 bool first_run_;
666 SwReporterInvocation invocation_; 789 std::queue<SwReporterInvocation> invocations_;
667 base::Version version_; 790 base::Version version_;
668 scoped_refptr<base::TaskRunner> main_thread_task_runner_; 791 scoped_refptr<base::TaskRunner> main_thread_task_runner_;
669 scoped_refptr<base::TaskRunner> blocking_task_runner_; 792 scoped_refptr<base::TaskRunner> blocking_task_runner_;
670 793
671 // This value is used to identify how long to wait before starting a new run 794 // This value is used to identify how long to wait before starting a new run
672 // of the reporter. It's initialized with the default value and may be changed 795 // of the reporter. It's initialized with the default value and may be changed
673 // to a different value when a prompt is pending and the reporter should be 796 // to a different value when a prompt is pending and the reporter should be
674 // run before adding the global error to the Chrome menu. 797 // run before adding the global error to the Chrome menu.
675 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns; 798 int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns;
676 799
677 // A single leaky instance. 800 // A single leaky instance.
678 static ReporterRunner* instance_; 801 static ReporterRunner* instance_;
679 802
680 DISALLOW_COPY_AND_ASSIGN(ReporterRunner); 803 DISALLOW_COPY_AND_ASSIGN(ReporterRunner);
681 }; 804 };
682 805
683 ReporterRunner* ReporterRunner::instance_ = nullptr; 806 ReporterRunner* ReporterRunner::instance_ = nullptr;
684 807
685 } // namespace 808 } // namespace
686 809
687 SwReporterInvocation::SwReporterInvocation() : command_line(0, nullptr) {} 810 SwReporterInvocation::SwReporterInvocation()
811 : command_line(0, nullptr), is_experimental(false) {}
688 812
689 SwReporterInvocation::SwReporterInvocation(const base::FilePath& exe_path) 813 SwReporterInvocation::SwReporterInvocation(const base::FilePath& exe_path)
690 : command_line(exe_path) {} 814 : command_line(exe_path), is_experimental(false) {}
691 815
692 SwReporterInvocation::SwReporterInvocation( 816 SwReporterInvocation::SwReporterInvocation(
693 const base::CommandLine& command_line) 817 const base::CommandLine& command_line)
694 : command_line(command_line) {} 818 : command_line(command_line), is_experimental(false) {}
695 819
696 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const { 820 bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const {
697 return command_line.argv() == other.command_line.argv(); 821 return command_line.argv() == other.command_line.argv() &&
822 suffix == other.suffix && is_experimental == other.is_experimental;
698 } 823 }
699 824
700 void RunSwReporter(const SwReporterInvocation& invocation, 825 void RunSwReporter(const SwReporterInvocation& invocation,
701 const base::Version& version, 826 const base::Version& version,
702 scoped_refptr<base::TaskRunner> main_thread_task_runner, 827 scoped_refptr<base::TaskRunner> main_thread_task_runner,
703 scoped_refptr<base::TaskRunner> blocking_task_runner) { 828 scoped_refptr<base::TaskRunner> blocking_task_runner) {
704 ReporterRunner::Run(invocation, version, main_thread_task_runner, 829 std::queue<SwReporterInvocation> invocations;
830 invocations.push(invocation);
831 ReporterRunner::Run(invocations, version, main_thread_task_runner,
705 blocking_task_runner); 832 blocking_task_runner);
706 } 833 }
707 834
835 void RunSwReporters(const std::queue<SwReporterInvocation>& invocations,
836 const base::Version& version,
837 scoped_refptr<base::TaskRunner> main_thread_task_runner,
838 scoped_refptr<base::TaskRunner> blocking_task_runner) {
839 ReporterRunner::Run(invocations, version, main_thread_task_runner,
840 blocking_task_runner);
841 }
842
708 bool ReporterFoundUws() { 843 bool ReporterFoundUws() {
709 PrefService* local_state = g_browser_process->local_state(); 844 PrefService* local_state = g_browser_process->local_state();
710 if (!local_state) 845 if (!local_state)
711 return false; 846 return false;
712 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode); 847 int exit_code = local_state->GetInteger(prefs::kSwReporterLastExitCode);
713 return exit_code == kSwReporterCleanupNeeded; 848 return exit_code == kSwReporterCleanupNeeded;
714 } 849 }
715 850
716 bool UserHasRunCleaner() { 851 bool UserHasRunCleaner() {
717 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey); 852 base::string16 cleaner_key_path(kSoftwareRemovalToolRegistryKey);
(...skipping 15 matching lines...) Expand all
733 868
734 void SetLaunchReadyNotifierForTesting(const LaunchReadyNotifier& notifier) { 869 void SetLaunchReadyNotifierForTesting(const LaunchReadyNotifier& notifier) {
735 g_launch_ready_notifier_ = notifier; 870 g_launch_ready_notifier_ = notifier;
736 } 871 }
737 872
738 void SetReporterDoneNotifierForTesting(const ReporterDoneNotifier& notifier) { 873 void SetReporterDoneNotifierForTesting(const ReporterDoneNotifier& notifier) {
739 g_reporter_done_notifier_ = notifier; 874 g_reporter_done_notifier_ = notifier;
740 } 875 }
741 876
742 } // namespace safe_browsing 877 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698