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

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: enabled -> supported Created 4 years, 3 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 <algorithm>
9 #include <map> 10 #include <map>
10 #include <memory> 11 #include <memory>
11 #include <string> 12 #include <string>
12 #include <utility> 13 #include <utility>
13 #include <vector> 14 #include <vector>
14 15
15 #include "base/base_paths.h" 16 #include "base/base_paths.h"
16 #include "base/bind.h" 17 #include "base/bind.h"
18 #include "base/command_line.h"
19 #include "base/feature_list.h"
17 #include "base/files/file_path.h" 20 #include "base/files/file_path.h"
18 #include "base/files/file_util.h" 21 #include "base/files/file_util.h"
19 #include "base/logging.h" 22 #include "base/logging.h"
20 #include "base/metrics/histogram.h" 23 #include "base/metrics/histogram.h"
21 #include "base/metrics/sparse_histogram.h" 24 #include "base/metrics/sparse_histogram.h"
22 #include "base/path_service.h" 25 #include "base/path_service.h"
23 #include "base/strings/string_tokenizer.h" 26 #include "base/strings/string_tokenizer.h"
27 #include "base/strings/string_util.h"
24 #include "base/threading/thread_task_runner_handle.h" 28 #include "base/threading/thread_task_runner_handle.h"
25 #include "base/threading/worker_pool.h" 29 #include "base/threading/worker_pool.h"
26 #include "base/time/time.h" 30 #include "base/time/time.h"
27 #include "base/win/registry.h" 31 #include "base/win/registry.h"
32 #include "base/win/windows_version.h"
28 #include "chrome/browser/browser_process.h" 33 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" 34 #include "chrome/browser/safe_browsing/srt_fetcher_win.h"
30 #include "chrome/browser/safe_browsing/srt_field_trial_win.h" 35 #include "chrome/browser/safe_browsing/srt_field_trial_win.h"
31 #include "components/component_updater/component_updater_paths.h" 36 #include "components/component_updater/component_updater_paths.h"
32 #include "components/component_updater/component_updater_service.h" 37 #include "components/component_updater/component_updater_service.h"
33 #include "components/component_updater/pref_names.h" 38 #include "components/component_updater/pref_names.h"
34 #include "components/pref_registry/pref_registry_syncable.h" 39 #include "components/pref_registry/pref_registry_syncable.h"
35 #include "components/prefs/pref_registry_simple.h" 40 #include "components/prefs/pref_registry_simple.h"
36 #include "components/update_client/update_client.h" 41 #include "components/update_client/update_client.h"
37 #include "components/update_client/utils.h" 42 #include "components/update_client/utils.h"
43 #include "components/variations/variations_associated_data.h"
38 #include "content/public/browser/browser_thread.h" 44 #include "content/public/browser/browser_thread.h"
39 45
40 namespace component_updater { 46 namespace component_updater {
41 47
42 namespace { 48 namespace {
43 49
44 // These two sets of values are used to send UMA information and are replicated 50 // 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. 51 // histograms.xml file, so the order MUST NOT CHANGE.
46 enum SRTCompleted { 52 enum SRTCompleted {
47 SRT_COMPLETED_NOT_YET = 0, 53 SRT_COMPLETED_NOT_YET = 0,
48 SRT_COMPLETED_YES = 1, 54 SRT_COMPLETED_YES = 1,
49 SRT_COMPLETED_LATER = 2, 55 SRT_COMPLETED_LATER = 2,
50 SRT_COMPLETED_MAX, 56 SRT_COMPLETED_MAX,
51 }; 57 };
52 58
53 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was 59 // CRX hash. The extension id is: gkmgaooipdjhmangpemjhigmamcehddo. The hash was
54 // generated in Python with something like this: 60 // generated in Python with something like this:
55 // hashlib.sha256().update(open("<file>.crx").read()[16:16+294]).digest(). 61 // 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( 116 void RunSwReporterAfterStartup(
111 const safe_browsing::SwReporterInvocation& invocation, 117 const safe_browsing::SwReporterInvocation& invocation,
112 const base::Version& version) { 118 const base::Version& version) {
113 content::BrowserThread::PostAfterStartupTask( 119 content::BrowserThread::PostAfterStartupTask(
114 FROM_HERE, base::ThreadTaskRunnerHandle::Get(), 120 FROM_HERE, base::ThreadTaskRunnerHandle::Get(),
115 base::Bind(&safe_browsing::RunSwReporter, invocation, version, 121 base::Bind(&safe_browsing::RunSwReporter, invocation, version,
116 base::ThreadTaskRunnerHandle::Get(), 122 base::ThreadTaskRunnerHandle::Get(),
117 base::WorkerPool::GetTaskRunner(true))); 123 base::WorkerPool::GetTaskRunner(true)));
118 } 124 }
119 125
126 // Constants and helper functions for the Experimental Engine feature.
127
128 constexpr base::Feature kExperimentalEngineFeature{
csharp 2016/08/25 19:47:27 The constants and enum can probably be moved up to
Joe Mason 2016/08/25 22:03:20 I see I'm outnumbered here. Done.
129 "ExperimentalSwReporterEngine", base::FEATURE_DISABLED_BY_DEFAULT};
130
131 // Max length of an installer attribute (taken from the regexp in
132 // ComponentInstallerTraits::InstallerAttributes).
133 constexpr size_t kMaxAttributeLength = 256;
134
135 // Max length of the registry and histogram suffix. Fairly arbitrary: the
136 // Windows registry accepts much longer keys, but we need to display this
137 // string in histograms as well.
138 constexpr size_t kMaxSuffixLength = 80;
139
140 // These MUST match the values for SwReporterExperimentError in histograms.xml.
141 enum ExperimentError {
142 EXPERIMENT_ERROR_BAD_TAG = 0,
143 EXPERIMENT_ERROR_BAD_PARAMS = 1,
144 EXPERIMENT_ERROR_MAX,
145 };
146
147 void ReportExperimentError(ExperimentError error) {
148 UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.ExperimentErrors", error,
149 EXPERIMENT_ERROR_MAX);
150 }
151
152 // Ensures |str| contains only alphanumeric characters and characters from
153 // |extras|, and is not longer than |max_length|.
154 bool ValidateString(const std::string& str,
155 const std::string& extras,
156 size_t max_length) {
157 return str.size() <= max_length &&
158 std::all_of(str.cbegin(), str.cend(), [&extras](char c) {
159 return base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
160 extras.find(c) != std::string::npos;
161 });
162 }
163
164 // Reads the command-line params and an UMA histogram suffix from the manifest,
165 // and launch the SwReporter with those parameters. If anything goes wrong the
166 // SwReporter should not be run at all, instead of falling back to the default.
167 void RunExperimentalSwReporter(const base::FilePath& exe_path,
168 const base::Version& version,
169 std::unique_ptr<base::DictionaryValue> manifest,
170 const SwReporterRunner& reporter_runner) {
171 // Don't log an error if the launch_params section is entirely missing. This
172 // can happen when the user already has an older version of the software
173 // reporter component, so |ComponentReady| is called on startup before the
174 // experimental version is downloaded.
175 //
176 // Also don't run the old version, though. We want this user to run the
csharp 2016/08/25 19:47:27 nit: This comment doesn't really add much since th
Joe Mason 2016/08/25 22:03:20 Actually the old version can run here, if we're no
177 // experimental version once it's been downloaded.
178 base::Value* launch_params = nullptr;
179 if (!manifest->Get("launch_params", &launch_params))
180 return;
181
182 const base::ListValue* parameter_list = nullptr;
183 if (!launch_params->GetAsList(&parameter_list) || parameter_list->empty()) {
184 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
185 return;
186 }
187
188 // For now we only support running the reporter once, so only look at the
csharp 2016/08/25 19:47:28 Nit: Instead of this comments what about just addi
Joe Mason 2016/08/25 22:03:19 Done.
189 // first set of arguments in the list.
190 const base::DictionaryValue* invocation_params = nullptr;
191 if (!parameter_list->GetDictionary(0, &invocation_params)) {
192 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
193 return;
194 }
195
196 // The suffix is optional. If present, it must be a short alphanumeric string.
197 std::string suffix;
198 const base::Value* suffix_value = nullptr;
199 if (invocation_params->Get("suffix", &suffix_value)) {
200 if (!suffix_value->GetAsString(&suffix)) {
201 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
202 return;
203 }
204 if (!suffix.empty() &&
csharp 2016/08/25 19:47:28 nit: I wonder if it'd be clear to merge this with
Joe Mason 2016/08/25 22:03:20 Done.
205 !ValidateString(suffix, std::string(), kMaxSuffixLength)) {
206 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
207 return;
208 }
209 }
210
211 // Build a command line for the reporter out of the executable path and the
212 // (optional) arguments from the manifest.
213 std::vector<base::string16> argv = {exe_path.value()};
214 const base::Value* arguments_value = nullptr;
215 if (invocation_params->Get("arguments", &arguments_value)) {
216 const base::ListValue* arguments = nullptr;
217 if (!arguments_value->GetAsList(&arguments)) {
218 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
219 return;
220 }
221 for (const std::unique_ptr<base::Value>& value : *arguments) {
222 base::string16 argument;
223 if (!value->GetAsString(&argument)) {
224 ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
225 return;
226 }
227 if (!argument.empty())
csharp 2016/08/25 19:47:27 An empty argument seems like an error, move into t
Joe Mason 2016/08/25 22:03:19 I don't see any reason to ban an explicit empty st
228 argv.push_back(argument);
229 }
230 }
231 base::CommandLine command_line(argv);
232
233 // Add the histogram suffix to the command-line as well, so that the
234 // reporter will add the same suffix to registry keys where it writes
235 // metrics.
236 if (!suffix.empty())
237 command_line.AppendSwitchASCII("registry-suffix", suffix);
238
239 auto invocation =
240 safe_browsing::SwReporterInvocation::FromCommandLine(command_line);
241 invocation.suffix = suffix;
242 invocation.is_experimental = true;
243
244 reporter_runner.Run(invocation, version);
245 }
246
120 } // namespace 247 } // namespace
121 248
122 SwReporterInstallerTraits::SwReporterInstallerTraits( 249 SwReporterInstallerTraits::SwReporterInstallerTraits(
123 const SwReporterRunner& reporter_runner) 250 const SwReporterRunner& reporter_runner,
124 : reporter_runner_(reporter_runner) {} 251 bool is_experimental_engine_supported)
252 : reporter_runner_(reporter_runner),
253 is_experimental_engine_supported_(is_experimental_engine_supported) {}
125 254
126 SwReporterInstallerTraits::~SwReporterInstallerTraits() {} 255 SwReporterInstallerTraits::~SwReporterInstallerTraits() {}
127 256
128 bool SwReporterInstallerTraits::VerifyInstallation( 257 bool SwReporterInstallerTraits::VerifyInstallation(
129 const base::DictionaryValue& manifest, 258 const base::DictionaryValue& manifest,
130 const base::FilePath& dir) const { 259 const base::FilePath& dir) const {
131 return base::PathExists(dir.Append(kSwReporterExeName)); 260 return base::PathExists(dir.Append(kSwReporterExeName));
132 } 261 }
133 262
134 bool SwReporterInstallerTraits::SupportsGroupPolicyEnabledComponentUpdates() 263 bool SwReporterInstallerTraits::SupportsGroupPolicyEnabledComponentUpdates()
(...skipping 10 matching lines...) Expand all
145 const base::FilePath& install_dir) { 274 const base::FilePath& install_dir) {
146 return true; 275 return true;
147 } 276 }
148 277
149 void SwReporterInstallerTraits::ComponentReady( 278 void SwReporterInstallerTraits::ComponentReady(
150 const base::Version& version, 279 const base::Version& version,
151 const base::FilePath& install_dir, 280 const base::FilePath& install_dir,
152 std::unique_ptr<base::DictionaryValue> manifest) { 281 std::unique_ptr<base::DictionaryValue> manifest) {
153 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 282 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
154 const base::FilePath exe_path(install_dir.Append(kSwReporterExeName)); 283 const base::FilePath exe_path(install_dir.Append(kSwReporterExeName));
284 if (IsExperimentalEngineEnabled()) {
285 RunExperimentalSwReporter(exe_path, version, std::move(manifest),
286 reporter_runner_);
287 return;
csharp 2016/08/25 19:47:27 nit: Instead of a return here what about just addi
Joe Mason 2016/08/25 22:03:19 Done.
288 }
155 reporter_runner_.Run( 289 reporter_runner_.Run(
156 safe_browsing::SwReporterInvocation::FromFilePath(exe_path), version); 290 safe_browsing::SwReporterInvocation::FromFilePath(exe_path), version);
157 } 291 }
158 292
159 base::FilePath SwReporterInstallerTraits::GetRelativeInstallDir() const { 293 base::FilePath SwReporterInstallerTraits::GetRelativeInstallDir() const {
160 return base::FilePath(FILE_PATH_LITERAL("SwReporter")); 294 return base::FilePath(FILE_PATH_LITERAL("SwReporter"));
161 } 295 }
162 296
163 void SwReporterInstallerTraits::GetHash(std::vector<uint8_t>* hash) const { 297 void SwReporterInstallerTraits::GetHash(std::vector<uint8_t>* hash) const {
164 DCHECK(hash); 298 DCHECK(hash);
165 hash->assign(kSha256Hash, kSha256Hash + sizeof(kSha256Hash)); 299 hash->assign(kSha256Hash, kSha256Hash + sizeof(kSha256Hash));
166 } 300 }
167 301
168 std::string SwReporterInstallerTraits::GetName() const { 302 std::string SwReporterInstallerTraits::GetName() const {
169 return "Software Reporter Tool"; 303 return "Software Reporter Tool";
170 } 304 }
171 305
172 update_client::InstallerAttributes 306 update_client::InstallerAttributes
173 SwReporterInstallerTraits::GetInstallerAttributes() const { 307 SwReporterInstallerTraits::GetInstallerAttributes() const {
174 return update_client::InstallerAttributes(); 308 update_client::InstallerAttributes attributes;
309 if (IsExperimentalEngineEnabled()) {
310 // Pass the "tag" parameter to the installer; it will be used to choose
311 // which binary is downloaded.
312 constexpr char kTagParam[] = "tag";
313 const std::string tag = variations::GetVariationParamValueByFeature(
314 kExperimentalEngineFeature, kTagParam);
315
316 // If the tag is not a valid attribute (see the regexp in
317 // ComponentInstallerTraits::InstallerAttributes), set it to a valid but
318 // unrecognized value so that nothing will be downloaded.
319 if (tag.empty() || !ValidateString(tag, "_.,;+_=", kMaxAttributeLength)) {
csharp 2016/08/25 19:47:28 nit: Please put "_.,;+_=" into a named constant
Joe Mason 2016/08/25 22:03:20 Done.
320 ReportExperimentError(EXPERIMENT_ERROR_BAD_TAG);
321 attributes[kTagParam] = "missing_tag";
322 } else {
323 attributes[kTagParam] = tag;
324 }
325 }
326 return attributes;
175 } 327 }
176 328
177 std::vector<std::string> SwReporterInstallerTraits::GetMimeTypes() const { 329 std::vector<std::string> SwReporterInstallerTraits::GetMimeTypes() const {
178 return std::vector<std::string>(); 330 return std::vector<std::string>();
179 } 331 }
180 332
333 bool SwReporterInstallerTraits::IsExperimentalEngineEnabled() const {
334 return is_experimental_engine_supported_ &&
335 base::FeatureList::IsEnabled(kExperimentalEngineFeature);
336 }
337
181 void RegisterSwReporterComponent(ComponentUpdateService* cus) { 338 void RegisterSwReporterComponent(ComponentUpdateService* cus) {
182 if (!safe_browsing::IsSwReporterEnabled()) 339 if (!safe_browsing::IsSwReporterEnabled())
183 return; 340 return;
184 341
185 // Check if we have information from Cleaner and record UMA statistics. 342 // Check if we have information from Cleaner and record UMA statistics.
186 base::string16 cleaner_key_name( 343 base::string16 cleaner_key_name(
187 safe_browsing::kSoftwareRemovalToolRegistryKey); 344 safe_browsing::kSoftwareRemovalToolRegistryKey);
188 cleaner_key_name.append(1, L'\\').append(kCleanerSuffixRegistryKey); 345 cleaner_key_name.append(1, L'\\').append(kCleanerSuffixRegistryKey);
189 base::win::RegKey cleaner_key( 346 base::win::RegKey cleaner_key(
190 HKEY_CURRENT_USER, cleaner_key_name.c_str(), KEY_ALL_ACCESS); 347 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); 404 ReportUploadsWithUma(upload_results);
248 } 405 }
249 } else { 406 } else {
250 if (cleaner_key.HasValue(safe_browsing::kEndTimeValueName)) { 407 if (cleaner_key.HasValue(safe_browsing::kEndTimeValueName)) {
251 SRTHasCompleted(SRT_COMPLETED_LATER); 408 SRTHasCompleted(SRT_COMPLETED_LATER);
252 cleaner_key.DeleteValue(safe_browsing::kEndTimeValueName); 409 cleaner_key.DeleteValue(safe_browsing::kEndTimeValueName);
253 } 410 }
254 } 411 }
255 } 412 }
256 413
414 // The experiment is only enabled on x86. There's no way to check this in the
415 // variations config so we'll hard-code it.
416 const bool is_experimental_engine_supported =
417 base::win::OSInfo::GetInstance()->architecture() ==
418 base::win::OSInfo::X86_ARCHITECTURE;
419
257 // Install the component. 420 // Install the component.
258 std::unique_ptr<ComponentInstallerTraits> traits( 421 std::unique_ptr<ComponentInstallerTraits> traits(
259 new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup))); 422 new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup),
423 is_experimental_engine_supported));
260 // |cus| will take ownership of |installer| during installer->Register(cus). 424 // |cus| will take ownership of |installer| during installer->Register(cus).
261 DefaultComponentInstaller* installer = 425 DefaultComponentInstaller* installer =
262 new DefaultComponentInstaller(std::move(traits)); 426 new DefaultComponentInstaller(std::move(traits));
263 installer->Register(cus, base::Closure()); 427 installer->Register(cus, base::Closure());
264 } 428 }
265 429
266 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) { 430 void RegisterPrefsForSwReporter(PrefRegistrySimple* registry) {
267 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0); 431 registry->RegisterInt64Pref(prefs::kSwReporterLastTimeTriggered, 0);
268 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1); 432 registry->RegisterIntegerPref(prefs::kSwReporterLastExitCode, -1);
269 registry->RegisterBooleanPref(prefs::kSwReporterPendingPrompt, false); 433 registry->RegisterBooleanPref(prefs::kSwReporterPendingPrompt, false);
270 } 434 }
271 435
272 void RegisterProfilePrefsForSwReporter( 436 void RegisterProfilePrefsForSwReporter(
273 user_prefs::PrefRegistrySyncable* registry) { 437 user_prefs::PrefRegistrySyncable* registry) {
274 registry->RegisterStringPref(prefs::kSwReporterPromptVersion, ""); 438 registry->RegisterStringPref(prefs::kSwReporterPromptVersion, "");
275 439
276 registry->RegisterStringPref(prefs::kSwReporterPromptSeed, ""); 440 registry->RegisterStringPref(prefs::kSwReporterPromptSeed, "");
277 } 441 }
278 442
279 } // namespace component_updater 443 } // namespace component_updater
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698