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

Side by Side Diff: components/flags_ui/flags_state.cc

Issue 2707013002: [chrome://flags] Let features override params in the same trial (Closed)
Patch Set: Created 3 years, 10 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 "components/flags_ui/flags_state.h" 5 #include "components/flags_ui/flags_state.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/feature_list.h" 11 #include "base/feature_list.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/metrics/field_trial.h" 14 #include "base/metrics/field_trial.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "base/values.h" 18 #include "base/values.h"
19 #include "build/build_config.h" 19 #include "build/build_config.h"
20 #include "components/flags_ui/feature_entry.h" 20 #include "components/flags_ui/feature_entry.h"
21 #include "components/flags_ui/flags_storage.h" 21 #include "components/flags_ui/flags_storage.h"
22 #include "components/flags_ui/flags_ui_switches.h" 22 #include "components/flags_ui/flags_ui_switches.h"
23 #include "components/variations/variations_associated_data.h" 23 #include "components/variations/variations_associated_data.h"
24 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
25 25
26 namespace flags_ui { 26 namespace flags_ui {
27 27
28 namespace internal { 28 namespace internal {
29 const char kTrialGroupAboutFlags[] = "AboutFlags"; 29 const char kDefaultGroupNameAboutFlags[] = "AboutFlags";
30 const char kDefaultTrialNameAboutFlags[] = "AboutFlagsTrial";
30 } // namespace internal 31 } // namespace internal
31 32
32 namespace { 33 namespace {
33 34
34 // Convert switch constants to proper CommandLine::StringType strings. 35 // Convert switch constants to proper CommandLine::StringType strings.
35 base::CommandLine::StringType GetSwitchString(const std::string& flag) { 36 base::CommandLine::StringType GetSwitchString(const std::string& flag) {
36 base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM); 37 base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
37 cmd_line.AppendSwitch(flag); 38 cmd_line.AppendSwitch(flag);
38 DCHECK_EQ(2U, cmd_line.argv().size()); 39 DCHECK_EQ(2U, cmd_line.argv().size());
39 return cmd_line.argv()[1]; 40 return cmd_line.argv()[1];
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 case FeatureEntry::FEATURE_VALUE: 139 case FeatureEntry::FEATURE_VALUE:
139 DCHECK_EQ(3, e.num_options); 140 DCHECK_EQ(3, e.num_options);
140 DCHECK(!e.choices); 141 DCHECK(!e.choices);
141 DCHECK(e.feature); 142 DCHECK(e.feature);
142 return true; 143 return true;
143 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE: 144 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
144 DCHECK_GT(e.num_options, 2); 145 DCHECK_GT(e.num_options, 2);
145 DCHECK(!e.choices); 146 DCHECK(!e.choices);
146 DCHECK(e.feature); 147 DCHECK(e.feature);
147 DCHECK(e.feature_variations); 148 DCHECK(e.feature_variations);
148 DCHECK(e.feature_trial_name);
149 return true; 149 return true;
150 } 150 }
151 NOTREACHED(); 151 NOTREACHED();
152 return false; 152 return false;
153 } 153 }
154 154
155 // Returns true if none of this entry's options have been enabled. 155 // Returns true if none of this entry's options have been enabled.
156 bool IsDefaultValue(const FeatureEntry& entry, 156 bool IsDefaultValue(const FeatureEntry& entry,
157 const std::set<std::string>& enabled_entries) { 157 const std::set<std::string>& enabled_entries) {
158 switch (entry.type) { 158 switch (entry.type) {
(...skipping 26 matching lines...) Expand all
185 std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue); 185 std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
186 const std::string name = entry.NameForOption(i); 186 const std::string name = entry.NameForOption(i);
187 value->SetString("internal_name", name); 187 value->SetString("internal_name", name);
188 value->SetString("description", entry.DescriptionForOption(i)); 188 value->SetString("description", entry.DescriptionForOption(i));
189 value->SetBoolean("selected", enabled_entries.count(name) > 0); 189 value->SetBoolean("selected", enabled_entries.count(name) > 0);
190 result->Append(std::move(value)); 190 result->Append(std::move(value));
191 } 191 }
192 return result; 192 return result;
193 } 193 }
194 194
195 // Registers variation parameters specified by |feature_variation| for the field 195 // Registers variation parameters specified by |feature_variation_params| for
196 // trial named |feature_trial_name|, unless a group for this trial has already 196 // the field trial named |feature_trial_name|, unless a group for this trial has
197 // been created (e.g. via command-line switches that take precedence over 197 // already been created (e.g. via command-line switches that take precedence
198 // about:flags). In the trial, the function creates a new constant group called 198 // over about:flags). In the trial, the function creates a new constant group
199 // |kTrialGroupAboutFlags|. 199 // called |kDefaultGroupNameAboutFlags|.
200 base::FieldTrial* RegisterFeatureVariationParameters( 200 base::FieldTrial* RegisterFeatureVariationParameters(
201 const std::string& feature_trial_name, 201 const std::string& feature_trial_name,
202 const FeatureEntry::FeatureVariation* feature_variation) { 202 const std::map<std::string, std::string>& feature_variation_params) {
203 std::map<std::string, std::string> params;
204 if (feature_variation) {
205 // Copy the parameters for non-null variations.
206 for (int i = 0; i < feature_variation->num_params; ++i) {
207 params[feature_variation->params[i].param_name] =
208 feature_variation->params[i].param_value;
209 }
210 }
211
212 bool success = variations::AssociateVariationParams( 203 bool success = variations::AssociateVariationParams(
213 feature_trial_name, internal::kTrialGroupAboutFlags, params); 204 feature_trial_name, internal::kDefaultGroupNameAboutFlags,
205 feature_variation_params);
214 if (!success) 206 if (!success)
215 return nullptr; 207 return nullptr;
216 // Successful association also means that no group is created and selected 208 // Successful association also means that no group is created and selected
217 // for the trial, yet. Thus, create the trial to select the group. This way, 209 // for the trial, yet. Thus, create the trial to select the group. This way,
218 // the parameters cannot get overwritten in later phases (such as from the 210 // the parameters cannot get overwritten in later phases (such as from the
219 // server). 211 // server).
220 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial( 212 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
221 feature_trial_name, internal::kTrialGroupAboutFlags); 213 feature_trial_name, internal::kDefaultGroupNameAboutFlags);
222 if (!trial) { 214 if (!trial) {
223 DLOG(WARNING) << "Could not create the trial " << feature_trial_name 215 DLOG(WARNING) << "Could not create the trial " << feature_trial_name
224 << " with group " << internal::kTrialGroupAboutFlags; 216 << " with group " << internal::kDefaultGroupNameAboutFlags;
225 } 217 }
226 return trial; 218 return trial;
227 } 219 }
228 220
229 } // namespace 221 } // namespace
230 222
231 struct FlagsState::SwitchEntry { 223 struct FlagsState::SwitchEntry {
232 // Corresponding base::Feature to toggle. 224 // Corresponding base::Feature to toggle.
233 std::string feature_name; 225 std::string feature_name;
234 226
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 flags_switches_.clear(); 426 flags_switches_.clear();
435 appended_switches_.clear(); 427 appended_switches_.clear();
436 } 428 }
437 429
438 std::vector<std::string> FlagsState::RegisterAllFeatureVariationParameters( 430 std::vector<std::string> FlagsState::RegisterAllFeatureVariationParameters(
439 FlagsStorage* flags_storage, 431 FlagsStorage* flags_storage,
440 base::FeatureList* feature_list) { 432 base::FeatureList* feature_list) {
441 std::set<std::string> enabled_entries; 433 std::set<std::string> enabled_entries;
442 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries); 434 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries);
443 std::vector<std::string> variation_ids; 435 std::vector<std::string> variation_ids;
436 std::map<std::string, std::set<std::string>> enabled_features_by_trial_name;
437 std::map<std::string, std::map<std::string, std::string>>
438 params_by_trial_name;
444 439
440 // First collect all the data for each trial.
445 for (size_t i = 0; i < num_feature_entries_; ++i) { 441 for (size_t i = 0; i < num_feature_entries_; ++i) {
446 const FeatureEntry& e = feature_entries_[i]; 442 const FeatureEntry& e = feature_entries_[i];
447 if (e.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) { 443 if (e.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) {
448 for (int j = 0; j < e.num_options; ++j) { 444 for (int j = 0; j < e.num_options; ++j) {
449 const FeatureEntry::FeatureVariation* variation =
450 e.VariationForOption(j);
451 if (e.StateForOption(j) == FeatureEntry::FeatureState::ENABLED && 445 if (e.StateForOption(j) == FeatureEntry::FeatureState::ENABLED &&
452 enabled_entries.count(e.NameForOption(j))) { 446 enabled_entries.count(e.NameForOption(j))) {
453 // If the option is selected by the user & has variation, register it. 447 std::string trial_name = e.feature_trial_name
454 base::FieldTrial* field_trial = RegisterFeatureVariationParameters( 448 ? e.feature_trial_name
455 e.feature_trial_name, variation); 449 : internal::kDefaultTrialNameAboutFlags;
Alexei Svitkine (slow) 2017/02/24 16:18:20 What happens if the user toggles multiple about:fl
jkrcal 2017/02/27 08:04:36 All the features from these multiple about:flags w
Alexei Svitkine (slow) 2017/02/28 18:45:35 I'm not a fan of this. This could cause conflicts
jkrcal 2017/03/01 18:35:53 Fair point. Removed the support of empty trial nam
450 // The user has chosen to enable the feature by this option.
451 enabled_features_by_trial_name[trial_name].insert(e.feature->name);
456 452
457 if (!field_trial) 453 const FeatureEntry::FeatureVariation* variation =
454 e.VariationForOption(j);
455 if (!variation)
458 continue; 456 continue;
459 feature_list->RegisterFieldTrialOverride(
460 e.feature->name,
461 base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
462 field_trial);
463 457
464 if (variation && variation->variation_id) 458 // The selected variation is non-default, collect its params & id.
459
460 for (int i = 0; i < variation->num_params; ++i) {
461 auto insert_result = params_by_trial_name[trial_name].insert(
462 std::make_pair(variation->params[i].param_name,
463 variation->params[i].param_value));
464 DCHECK(insert_result.second)
vitaliii 2017/02/21 15:43:27 Drive-by nit: As of now the message looks like "
jkrcal 2017/03/01 18:35:53 Done.
465 << "multiple values for the same parameter '"
466 << variation->params[i].param_name
467 << "'specified in chrome://flags!";
468 }
469 if (variation->variation_id)
465 variation_ids.push_back(variation->variation_id); 470 variation_ids.push_back(variation->variation_id);
466 } 471 }
467 } 472 }
468 } 473 }
469 } 474 }
475
476 // Now create the trials and associate the features to them.
477 for (const auto& kv : enabled_features_by_trial_name) {
478 const std::string& trial_name = kv.first;
479 const std::set<std::string>& trial_features = kv.second;
480
481 base::FieldTrial* field_trial = RegisterFeatureVariationParameters(
482 trial_name, params_by_trial_name[trial_name]);
483 if (!field_trial)
484 continue;
485
486 for (const std::string& feature_name : trial_features) {
487 feature_list->RegisterFieldTrialOverride(
488 feature_name,
489 base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
490 field_trial);
491 }
492 }
493
470 return variation_ids; 494 return variation_ids;
471 } 495 }
472 496
473 void FlagsState::GetFlagFeatureEntries( 497 void FlagsState::GetFlagFeatureEntries(
474 FlagsStorage* flags_storage, 498 FlagsStorage* flags_storage,
475 FlagAccess access, 499 FlagAccess access,
476 base::ListValue* supported_entries, 500 base::ListValue* supported_entries,
477 base::ListValue* unsupported_entries, 501 base::ListValue* unsupported_entries,
478 base::Callback<bool(const FeatureEntry&)> skip_feature_entry) { 502 base::Callback<bool(const FeatureEntry&)> skip_feature_entry) {
479 std::set<std::string> enabled_entries; 503 std::set<std::string> enabled_entries;
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
772 state == FeatureEntry::FeatureState::ENABLED, 796 state == FeatureEntry::FeatureState::ENABLED,
773 name_to_switch_map); 797 name_to_switch_map);
774 } 798 }
775 } 799 }
776 break; 800 break;
777 } 801 }
778 } 802 }
779 } 803 }
780 804
781 } // namespace flags_ui 805 } // namespace flags_ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698