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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/component_updater/sw_reporter_installer_win.cc
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index cad962c7d29a8f83f4a2a8fb84770271fee87a19..eb16773aca18439d340cc526c78735e9fdcf4b89 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -14,6 +14,8 @@
#include "base/base_paths.h"
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
@@ -21,6 +23,7 @@
#include "base/metrics/sparse_histogram.h"
#include "base/path_service.h"
#include "base/strings/string_tokenizer.h"
+#include "base/sys_info.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/threading/worker_pool.h"
#include "base/time/time.h"
@@ -35,14 +38,16 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/update_client/update_client.h"
#include "components/update_client/utils.h"
+#include "components/variations/variations_associated_data.h"
#include "content/public/browser/browser_thread.h"
+#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.
namespace component_updater {
namespace {
-// These two sets of values are used to send UMA information and are replicated
-// in the histograms.xml file, so the order MUST NOT CHANGE.
+// These values are used to send UMA information and are replicated in the
+// histograms.xml file, so the order MUST NOT CHANGE.
enum SRTCompleted {
SRT_COMPLETED_NOT_YET = 0,
SRT_COMPLETED_YES = 1,
@@ -117,11 +122,114 @@ void RunSwReporterAfterStartup(
base::WorkerPool::GetTaskRunner(true)));
}
+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
+ "ExperimentalSwReporterEngine", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// These MUST match the values for SwReporterExperimentError in histograms.xml.
+enum ExperimentError {
+ EXPERIMENT_ERROR_BAD_TAG = 0,
+ EXPERIMENT_ERROR_BAD_PARAMS = 1,
+ EXPERIMENT_ERROR_MAX,
+};
+
+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
+ UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.ExperimentErrors", error,
+ EXPERIMENT_ERROR_MAX);
+}
+
+// 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.
+// 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.
+// SwReporter should not be run at all - do not fall back to the default.
+void RunExperimentalSwReporter(const base::FilePath& exe_path,
+ const base::Version& version,
+ std::unique_ptr<base::DictionaryValue> manifest,
+ const SwReporterRunner& reporter_runner) {
+ // Don't log an error if the launch_params section is entirely missing. This
+ // can happen when the user already has an older version of the software
+ // reporter component, so |ComponentReady| is called on startup before the
+ // experimental version is downloaded.
+ //
+ // Also don't run the old version, though. We want this user to run the
+ // experimental version once it's been downloaded.
+ if (!manifest->HasKey("launch_params"))
+ return;
+
+ const base::ListValue* parameter_list = nullptr;
+ if (!manifest->GetList("launch_params", &parameter_list)) {
+ 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.
+ return;
+ }
+
+ // If launch_params exists but is empty, run the experimental reporter once
+ // with no suffix or command-line parameters, to mimic the regular version.
+ // (The control group would be set up this way.)
+ 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.
+ 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.
+ auto invocation =
+ safe_browsing::SwReporterInvocation::FromFilePath(exe_path);
+ invocation.is_experimental = true;
+ reporter_runner.Run(invocation, version);
+ return;
+ }
+
+ // For now we only support running the reporter once, so only look at the
+ // first set of arguments in the list.
+ const base::DictionaryValue* invocation_params = nullptr;
+ if (!parameter_list->GetDictionary(0, &invocation_params)) {
+ ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
+ return;
+ }
+
+ // The suffix is required, and must be a short alphanumeric string.
+ static const re2::RE2 kValidSuffixPattern("[a-zA-Z0-9]{1,256}");
+ std::string suffix;
+ DCHECK(invocation_params);
+ invocation_params->GetString("suffix", &suffix);
+ if (suffix.empty() || !re2::RE2::FullMatch(suffix, kValidSuffixPattern)) {
+ ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
+ return;
+ }
+
+ // Build a command line for the reporter out of the executable path and the
+ // (optional) arguments from the manifest.
+ 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.
+ if (invocation_params->HasKey("arguments")) {
+ const base::ListValue* arguments = nullptr;
+ if (!invocation_params->GetList("arguments", &arguments)) {
+ ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
+ return;
+ }
+ 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
+ base::string16 argument;
+ if (!value->GetAsString(&argument)) {
+ ReportExperimentError(EXPERIMENT_ERROR_BAD_PARAMS);
+ return;
+ }
+ argv.push_back(argument);
+ }
+ }
+ base::CommandLine command_line(argv);
+
+ // Add the histogram suffix to the command-line as well, so that the
+ // reporter will add the same suffix to registry keys where it writes
+ // metrics.
+ command_line.AppendSwitchASCII("registry-suffix", suffix);
+
+ auto invocation =
+ safe_browsing::SwReporterInvocation::FromCommandLine(command_line);
+ invocation.suffix = suffix;
+ invocation.is_experimental = true;
+
+ reporter_runner.Run(invocation, version);
+}
+
} // namespace
SwReporterInstallerTraits::SwReporterInstallerTraits(
- const SwReporterRunner& reporter_runner)
- : reporter_runner_(reporter_runner) {}
+ const SwReporterRunner& reporter_runner,
+ bool is_experimental_engine_supported)
+ : reporter_runner_(reporter_runner),
+ is_experimental_engine_supported_(is_experimental_engine_supported) {}
SwReporterInstallerTraits::~SwReporterInstallerTraits() {}
@@ -152,6 +260,11 @@ void SwReporterInstallerTraits::ComponentReady(
std::unique_ptr<base::DictionaryValue> manifest) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const base::FilePath exe_path(install_dir.Append(kSwReporterExeName));
+ if (IsExperimentalEngineEnabled()) {
+ RunExperimentalSwReporter(exe_path, version, std::move(manifest),
+ reporter_runner_);
+ return;
+ }
reporter_runner_.Run(
safe_browsing::SwReporterInvocation::FromFilePath(exe_path), version);
}
@@ -171,13 +284,38 @@ std::string SwReporterInstallerTraits::GetName() const {
update_client::InstallerAttributes
SwReporterInstallerTraits::GetInstallerAttributes() const {
- return update_client::InstallerAttributes();
+ update_client::InstallerAttributes attributes;
+ if (IsExperimentalEngineEnabled()) {
+ // Pass the "tag" parameter to the installer; it will be used to choose
+ // which binary is downloaded.
+ constexpr char kTagParam[] = "tag";
+ std::string tag = variations::GetVariationParamValueByFeature(
Sorin Jianu 2016/08/25 03:04:29 const?
Joe Mason 2016/08/25 15:50:05 Done.
+ kExperimentalEngineFeature, kTagParam);
+
+ // Validate that the tag is valid (regexp taken from
+ // ComponentInstallerTraits::InstallerAttributes). If not, set it to a
+ // valid but unrecognized value so that nothing will be downloaded.
+ if (tag.empty() ||
+ !re2::RE2::FullMatch(tag, "^[-.,;+_=a-zA-Z0-9]{0,256}$")) {
+ ReportExperimentError(EXPERIMENT_ERROR_BAD_TAG);
+ attributes[kTagParam] = "missing_tag";
+ } else {
+ attributes[kTagParam] = tag;
+ }
+ }
+ return attributes;
}
std::vector<std::string> SwReporterInstallerTraits::GetMimeTypes() const {
return std::vector<std::string>();
}
+bool SwReporterInstallerTraits::IsExperimentalEngineEnabled() const {
+ 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.
+ return false;
+ return base::FeatureList::IsEnabled(kExperimentalEngineFeature);
+}
+
void RegisterSwReporterComponent(ComponentUpdateService* cus) {
if (!safe_browsing::IsSwReporterEnabled())
return;
@@ -254,9 +392,15 @@ void RegisterSwReporterComponent(ComponentUpdateService* cus) {
}
}
+ // The experiment is only enabled on x86. There's no way to check this in the
+ // variations config so we'll hard-code it.
+ bool is_experimental_engine_enabled =
Sorin Jianu 2016/08/25 03:04:29 const?
Joe Mason 2016/08/25 15:50:05 Done.
+ 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.
+
// Install the component.
std::unique_ptr<ComponentInstallerTraits> traits(
- new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup)));
+ new SwReporterInstallerTraits(base::Bind(&RunSwReporterAfterStartup),
+ is_experimental_engine_enabled));
// |cus| will take ownership of |installer| during installer->Register(cus).
DefaultComponentInstaller* installer =
new DefaultComponentInstaller(std::move(traits));

Powered by Google App Engine
This is Rietveld 408576698