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

Side by Side Diff: chrome/browser/component_updater/sw_reporter_installer_win.cc

Issue 2278013002: Add support for the ExperimentalSwReporterEngine field trial. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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 (c) 2014 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2014 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/component_updater/sw_reporter_installer_win.h" 5 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <map> 9 #include <map>
10 #include <memory> 10 #include <memory>
11 #include <string> 11 #include <string>
12 #include <utility> 12 #include <utility>
13 #include <vector> 13 #include <vector>
14 14
15 #include "base/base_paths.h" 15 #include "base/base_paths.h"
16 #include "base/bind.h" 16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/feature_list.h"
17 #include "base/files/file_path.h" 19 #include "base/files/file_path.h"
18 #include "base/files/file_util.h" 20 #include "base/files/file_util.h"
19 #include "base/logging.h" 21 #include "base/logging.h"
20 #include "base/metrics/histogram.h" 22 #include "base/metrics/histogram.h"
21 #include "base/metrics/sparse_histogram.h" 23 #include "base/metrics/sparse_histogram.h"
22 #include "base/path_service.h" 24 #include "base/path_service.h"
23 #include "base/strings/string_tokenizer.h" 25 #include "base/strings/string_tokenizer.h"
26 #include "base/sys_info.h"
24 #include "base/threading/thread_task_runner_handle.h" 27 #include "base/threading/thread_task_runner_handle.h"
25 #include "base/threading/worker_pool.h" 28 #include "base/threading/worker_pool.h"
26 #include "base/time/time.h" 29 #include "base/time/time.h"
27 #include "base/win/registry.h" 30 #include "base/win/registry.h"
28 #include "chrome/browser/browser_process.h" 31 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" 32 #include "chrome/browser/safe_browsing/srt_fetcher_win.h"
30 #include "chrome/browser/safe_browsing/srt_field_trial_win.h" 33 #include "chrome/browser/safe_browsing/srt_field_trial_win.h"
31 #include "components/component_updater/component_updater_paths.h" 34 #include "components/component_updater/component_updater_paths.h"
32 #include "components/component_updater/component_updater_service.h" 35 #include "components/component_updater/component_updater_service.h"
33 #include "components/component_updater/pref_names.h" 36 #include "components/component_updater/pref_names.h"
34 #include "components/pref_registry/pref_registry_syncable.h" 37 #include "components/pref_registry/pref_registry_syncable.h"
35 #include "components/prefs/pref_registry_simple.h" 38 #include "components/prefs/pref_registry_simple.h"
36 #include "components/update_client/update_client.h" 39 #include "components/update_client/update_client.h"
37 #include "components/update_client/utils.h" 40 #include "components/update_client/utils.h"
41 #include "components/variations/variations_associated_data.h"
38 #include "content/public/browser/browser_thread.h" 42 #include "content/public/browser/browser_thread.h"
43 #include "third_party/re2/src/re2/re2.h"
Sorin Jianu 2016/08/25 03:04:29 I suggest checking with brettw@ or some other supe
Joe Mason 2016/08/25 13:43:28 Since the use of RE's here is so simple, I'll just
Joe Mason 2016/08/25 15:50:05 Done.
39 44
40 namespace component_updater { 45 namespace component_updater {
41 46
42 namespace { 47 namespace {
43 48
44 // These two sets of values are used to send UMA information and are replicated 49 // These values are used to send UMA information and are replicated in the
45 // in the histograms.xml file, so the order MUST NOT CHANGE. 50 // histograms.xml file, so the order MUST NOT CHANGE.
46 enum SRTCompleted { 51 enum SRTCompleted {
47 SRT_COMPLETED_NOT_YET = 0, 52 SRT_COMPLETED_NOT_YET = 0,
48 SRT_COMPLETED_YES = 1, 53 SRT_COMPLETED_YES = 1,
49 SRT_COMPLETED_LATER = 2, 54 SRT_COMPLETED_LATER = 2,
50 SRT_COMPLETED_MAX, 55 SRT_COMPLETED_MAX,
51 }; 56 };
52 57
53 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was 58 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was
54 // generated in Python with something like this: 59 // generated in Python with something like this:
55 // hashlib.sha256().update(open("<file>.crx").read()[16:16+294]).digest(). 60 // hashlib.sha256().update(open("<file>.crx").read()[16:16+294]).digest().
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 void RunSwReporterAfterStartup( 115 void RunSwReporterAfterStartup(
111 const safe_browsing::SwReporterInvocation& invocation, 116 const safe_browsing::SwReporterInvocation& invocation,
112 const base::Version& version) { 117 const base::Version& version) {
113 content::BrowserThread::PostAfterStartupTask( 118 content::BrowserThread::PostAfterStartupTask(
114 FROM_HERE, base::ThreadTaskRunnerHandle::Get(), 119 FROM_HERE, base::ThreadTaskRunnerHandle::Get(),
115 base::Bind(&safe_browsing::RunSwReporter, invocation, version, 120 base::Bind(&safe_browsing::RunSwReporter, invocation, version,
116 base::ThreadTaskRunnerHandle::Get(), 121 base::ThreadTaskRunnerHandle::Get(),
117 base::WorkerPool::GetTaskRunner(true))); 122 base::WorkerPool::GetTaskRunner(true)));
118 } 123 }
119 124
125 constexpr base::Feature kExperimentalEngineFeature{
grt (UTC plus 2) 2016/08/25 15:42:13 i think it's good practice to put things like enum
126 "ExperimentalSwReporterEngine", base::FEATURE_DISABLED_BY_DEFAULT};
127
128 // These MUST match the values for SwReporterExperimentError in histograms.xml.
129 enum ExperimentError {
130 EXPERIMENT_ERROR_BAD_TAG = 0,
131 EXPERIMENT_ERROR_BAD_PARAMS = 1,
132 EXPERIMENT_ERROR_MAX,
133 };
134
135 void ReportExperimentError(ExperimentError error) {
grt (UTC plus 2) 2016/08/25 15:42:12 you could move this up closer to the top to keep i
136 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.ExperimentErrors", error,
137 EXPERIMENT_ERROR_MAX);
138 }
139
140 // Read the command-line params and an UMA histogram suffix from the manifest,
grt (UTC plus 2) 2016/08/25 15:42:12 // Reads the... and launches the... as per https:/
Joe Mason 2016/08/25 17:52:58 Done.
141 // and launch the SwReporter with those parameters. If anything goes wrong the
Sorin Jianu 2016/08/25 03:04:29 Why two spaces after period?
Joe Mason 2016/08/25 15:50:05 Done.
142 // SwReporter should not be run at all - do not fall back to the default.
143 void RunExperimentalSwReporter(const base::FilePath& exe_path,
144 const base::Version& version,
145 std::unique_ptr<base::DictionaryValue> manifest,
146 const SwReporterRunner& reporter_runner) {
147 // Don't log an error if the launch_params section is entirely missing. This
148 // can happen when the user already has an older version of the software
149 // reporter component, so |ComponentReady| is called on startup before the
150 // experimental version is downloaded.
151 //
152 // Also don't run the old version, though. We want this user to run the
153 // experimental version once it's been downloaded.
154 if (!manifest->HasKey("launch_params"))
155 return;
156
157 const base::ListValue* parameter_list = nullptr;
158 if (!manifest->GetList("launch_params", &parameter_list)) {
159 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
grt (UTC plus 2) 2016/08/25 15:42:12 rather than doing two lookups in the dict, how abo
Joe Mason 2016/08/25 17:52:58 Done.
160 return;
161 }
162
163 // If launch_params exists but is empty, run the experimental reporter once
164 // with no suffix or command-line parameters, to mimic the regular version.
165 // (The control group would be set up this way.)
166 DCHECK(parameter_list);
grt (UTC plus 2) 2016/08/25 15:42:13 remove this. it's impossible thanks to the two ear
Joe Mason 2016/08/25 17:52:58 Done.
167 if (parameter_list->empty()) {
Joe Mason 2016/08/25 13:43:28 With an evening's distance from the code, I can se
Joe Mason 2016/08/25 15:50:05 Done.
168 auto invocation =
169 safe_browsing::SwReporterInvocation::FromFilePath(exe_path);
170 invocation.is_experimental = true;
171 reporter_runner.Run(invocation, version);
172 return;
173 }
174
175 // For now we only support running the reporter once, so only look at the
176 // first set of arguments in the list.
177 const base::DictionaryValue* invocation_params = nullptr;
178 if (!parameter_list->GetDictionary(0, &invocation_params)) {
179 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
180 return;
181 }
182
183 // The suffix is required, and must be a short alphanumeric string.
184 static const re2::RE2 kValidSuffixPattern("[a-zA-Z0-9]{1,256}");
185 std::string suffix;
186 DCHECK(invocation_params);
187 invocation_params->GetString("suffix", &suffix);
188 if (suffix.empty() || !re2::RE2::FullMatch(suffix, kValidSuffixPattern)) {
189 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
190 return;
191 }
192
193 // Build a command line for the reporter out of the executable path and the
194 // (optional) arguments from the manifest.
195 std::vector<base::string16> argv{exe_path.value()};
grt (UTC plus 2) 2016/08/25 15:42:12 ...argv = {exe_path.value()}; as per https://www.c
Joe Mason 2016/08/25 17:52:58 Done.
196 if (invocation_params->HasKey("arguments")) {
197 const base::ListValue* arguments = nullptr;
198 if (!invocation_params->GetList("arguments", &arguments)) {
199 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
200 return;
201 }
202 for (const std::unique_ptr<base::Value>& value : *arguments) {
Sorin Jianu 2016/08/25 03:04:29 using const auto& could be reasonable imho, assumi
Joe Mason 2016/08/25 13:43:28 I think it's better to make the unique_ptr here ex
grt (UTC plus 2) 2016/08/25 15:42:12 I agree. If not, base::ListValue::iterator is more
Joe Mason 2016/08/25 22:03:19 After working with this some more I've come to agr
203 base::string16 argument;
204 if (!value->GetAsString(&argument)) {
205 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
206 return;
207 }
208 argv.push_back(argument);
209 }
210 }
211 base::CommandLine command_line(argv);
212
213 // Add the histogram suffix to the command-line as well, so that the
214 // reporter will add the same suffix to registry keys where it writes
215 // metrics.
216 command_line.AppendSwitchASCII("registry-suffix", suffix);
217
218 auto invocation =
219 safe_browsing::SwReporterInvocation::FromCommandLine(command_line);
220 invocation.suffix = suffix;
221 invocation.is_experimental = true;
222
223 reporter_runner.Run(invocation, version);
224 }
225
120 } // namespace 226 } // namespace
121 227
122 SwReporterInstallerTraits::SwReporterInstallerTraits( 228 SwReporterInstallerTraits::SwReporterInstallerTraits(
123 const SwReporterRunner& reporter_runner) 229 const SwReporterRunner& reporter_runner,
124 : reporter_runner_(reporter_runner) {} 230 bool is_experimental_engine_supported)
231 : reporter_runner_(reporter_runner),
232 is_experimental_engine_supported_(is_experimental_engine_supported) {}
125 233
126 SwReporterInstallerTraits::~SwReporterInstallerTraits() {} 234 SwReporterInstallerTraits::~SwReporterInstallerTraits() {}
127 235
128 bool SwReporterInstallerTraits::VerifyInstallation( 236 bool SwReporterInstallerTraits::VerifyInstallation(
129 const base::DictionaryValue& manifest, 237 const base::DictionaryValue& manifest,
130 const base::FilePath& dir) const { 238 const base::FilePath& dir) const {
131 return base::PathExists(dir.Append(kSwReporterExeName)); 239 return base::PathExists(dir.Append(kSwReporterExeName));
132 } 240 }
133 241
134 bool SwReporterInstallerTraits::SupportsGroupPolicyEnabledComponentUpdates() 242 bool SwReporterInstallerTraits::SupportsGroupPolicyEnabledComponentUpdates()
(...skipping 10 matching lines...) Expand all
145 const base::FilePath& install_dir) { 253 const base::FilePath& install_dir) {
146 return true; 254 return true;
147 } 255 }
148 256
149 void SwReporterInstallerTraits::ComponentReady( 257 void SwReporterInstallerTraits::ComponentReady(
150 const base::Version& version, 258 const base::Version& version,
151 const base::FilePath& install_dir, 259 const base::FilePath& install_dir,
152 std::unique_ptr<base::DictionaryValue> manifest) { 260 std::unique_ptr<base::DictionaryValue> manifest) {
153 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 261 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
154 const base::FilePath exe_path(install_dir.Append(kSwReporterExeName)); 262 const base::FilePath exe_path(install_dir.Append(kSwReporterExeName));
263 if (IsExperimentalEngineEnabled()) {
264 RunExperimentalSwReporter(exe_path, version, std::move(manifest),
265 reporter_runner_);
266 return;
267 }
155 reporter_runner_.Run( 268 reporter_runner_.Run(
156 safe_browsing::SwReporterInvocation::FromFilePath(exe_path), version); 269 safe_browsing::SwReporterInvocation::FromFilePath(exe_path), version);
157 } 270 }
158 271
159 base::FilePath SwReporterInstallerTraits::GetRelativeInstallDir() const { 272 base::FilePath SwReporterInstallerTraits::GetRelativeInstallDir() const {
160 return base::FilePath(FILE_PATH_LITERAL("SwReporter")); 273 return base::FilePath(FILE_PATH_LITERAL("SwReporter"));
161 } 274 }
162 275
163 void SwReporterInstallerTraits::GetHash(std::vector<uint8_t>* hash) const { 276 void SwReporterInstallerTraits::GetHash(std::vector<uint8_t>* hash) const {
164 DCHECK(hash); 277 DCHECK(hash);
165 hash->assign(kSha256Hash, kSha256Hash + sizeof(kSha256Hash)); 278 hash->assign(kSha256Hash, kSha256Hash + sizeof(kSha256Hash));
166 } 279 }
167 280
168 std::string SwReporterInstallerTraits::GetName() const { 281 std::string SwReporterInstallerTraits::GetName() const {
169 return "Software Reporter Tool"; 282 return "Software Reporter Tool";
170 } 283 }
171 284
172 update_client::InstallerAttributes 285 update_client::InstallerAttributes
173 SwReporterInstallerTraits::GetInstallerAttributes() const { 286 SwReporterInstallerTraits::GetInstallerAttributes() const {
174 return update_client::InstallerAttributes(); 287 update_client::InstallerAttributes attributes;
288 if (IsExperimentalEngineEnabled()) {
289 // Pass the "tag" parameter to the installer; it will be used to choose
290 // which binary is downloaded.
291 constexpr char kTagParam[] = "tag";
292 std::string tag = variations::GetVariationParamValueByFeature(
Sorin Jianu 2016/08/25 03:04:29 const?
Joe Mason 2016/08/25 15:50:05 Done.
293 kExperimentalEngineFeature, kTagParam);
294
295 // Validate that the tag is valid (regexp taken from
296 // ComponentInstallerTraits::InstallerAttributes). If not, set it to a
297 // valid but unrecognized value so that nothing will be downloaded.
298 if (tag.empty() ||
299 !re2::RE2::FullMatch(tag, "^[-.,;+_=a-zA-Z0-9]{0,256}$")) {
300 ReportExperimentError(EXPERIMENT_ERROR_BAD_TAG);
301 attributes[kTagParam] = "missing_tag";
302 } else {
303 attributes[kTagParam] = tag;
304 }
305 }
306 return attributes;
175 } 307 }
176 308
177 std::vector<std::string> SwReporterInstallerTraits::GetMimeTypes() const { 309 std::vector<std::string> SwReporterInstallerTraits::GetMimeTypes() const {
178 return std::vector<std::string>(); 310 return std::vector<std::string>();
179 } 311 }
180 312
313 bool SwReporterInstallerTraits::IsExperimentalEngineEnabled() const {
314 if (!is_experimental_engine_supported_)
Sorin Jianu 2016/08/25 03:04:29 could use ?:
Joe Mason 2016/08/25 15:50:05 Or just &&. Done.
315 return false;
316 return base::FeatureList::IsEnabled(kExperimentalEngineFeature);
317 }
318
181 void RegisterSwReporterComponent(ComponentUpdateService* cus) { 319 void RegisterSwReporterComponent(ComponentUpdateService* cus) {
182 if (!safe_browsing::IsSwReporterEnabled()) 320 if (!safe_browsing::IsSwReporterEnabled())
183 return; 321 return;
184 322
185 // Check if we have information from Cleaner and record UMA statistics. 323 // Check if we have information from Cleaner and record UMA statistics.
186 base::string16 cleaner_key_name( 324 base::string16 cleaner_key_name(
187 safe_browsing::kSoftwareRemovalToolRegistryKey); 325 safe_browsing::kSoftwareRemovalToolRegistryKey);
188 cleaner_key_name.append(1, L'\\').append(kCleanerSuffixRegistryKey); 326 cleaner_key_name.append(1, L'\\').append(kCleanerSuffixRegistryKey);
189 base::win::RegKey cleaner_key( 327 base::win::RegKey cleaner_key(
190 HKEY_CURRENT_USER, cleaner_key_name.c_str(), KEY_ALL_ACCESS); 328 HKEY_CURRENT_USER, cleaner_key_name.c_str(), KEY_ALL_ACCESS);
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 ReportUploadsWithUma(upload_results); 385 ReportUploadsWithUma(upload_results);
248 } 386 }
249 } else { 387 } else {
250 if (cleaner_key.HasValue(safe_browsing::kEndTimeValueName)) { 388 if (cleaner_key.HasValue(safe_browsing::kEndTimeValueName)) {
251 SRTHasCompleted(SRT_COMPLETED_LATER); 389 SRTHasCompleted(SRT_COMPLETED_LATER);
252 cleaner_key.DeleteValue(safe_browsing::kEndTimeValueName); 390 cleaner_key.DeleteValue(safe_browsing::kEndTimeValueName);
253 } 391 }
254 } 392 }
255 } 393 }
256 394
395 // The experiment is only enabled on x86. There's no way to check this in the
396 // variations config so we'll hard-code it.
397 bool is_experimental_engine_enabled =
Sorin Jianu 2016/08/25 03:04:29 const?
Joe Mason 2016/08/25 15:50:05 Done.
398 base::SysInfo::OperatingSystemArchitecture() == "x86";
grt (UTC plus 2) 2016/08/25 15:42:13 use this: base::win::OSInfo::GetInstance()->archit
Joe Mason 2016/08/25 17:52:58 Done.
399
257 // Install the component. 400 // Install the component.
258 std::unique_ptr<ComponentInstallerTraits> traits( 401 std::unique_ptr<ComponentInstallerTraits> traits(
259 new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup))); 402 new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup),
403 is_experimental_engine_enabled));
260 // |cus| will take ownership of |installer| during installer->Register(cus). 404 // |cus| will take ownership of |installer| during installer->Register(cus).
261 DefaultComponentInstaller* installer = 405 DefaultComponentInstaller* installer =
262 new DefaultComponentInstaller(std::move(traits)); 406 new DefaultComponentInstaller(std::move(traits));
263 installer->Register(cus, base::Closure()); 407 installer->Register(cus, base::Closure());
264 } 408 }
265 409
266 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { 410 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) {
267 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); 411 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0);
268 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1); 412 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1);
269 registry->RegisterBooleanPref(prefs::kSwReporterPendingPrompt, false); 413 registry->RegisterBooleanPref(prefs::kSwReporterPendingPrompt, false);
270 } 414 }
271 415
272 void RegisterProfilePrefsForSwReporter( 416 void RegisterProfilePrefsForSwReporter(
273 user_prefs::PrefRegistrySyncable* registry) { 417 user_prefs::PrefRegistrySyncable* registry) {
274 registry->RegisterStringPref(prefs::kSwReporterPromptVersion, ""); 418 registry->RegisterStringPref(prefs::kSwReporterPromptVersion, "");
275 419
276 registry->RegisterStringPref(prefs::kSwReporterPromptSeed, ""); 420 registry->RegisterStringPref(prefs::kSwReporterPromptSeed, "");
277 } 421 }
278 422
279 } // namespace component_updater 423 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698