Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |