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

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

Issue 2036193002: Allow overriding variation parameter via chrome://flags. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Minor polish #3 + Adding a unittest Created 4 years, 6 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 "base/callback.h" 7 #include "base/callback.h"
8 #include "base/feature_list.h" 8 #include "base/feature_list.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/metrics/field_trial.h"
11 #include "base/stl_util.h" 12 #include "base/stl_util.h"
12 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "build/build_config.h" 16 #include "build/build_config.h"
16 #include "components/flags_ui/feature_entry.h" 17 #include "components/flags_ui/feature_entry.h"
17 #include "components/flags_ui/flags_storage.h" 18 #include "components/flags_ui/flags_storage.h"
18 #include "components/flags_ui/flags_ui_switches.h" 19 #include "components/flags_ui/flags_ui_switches.h"
20 #include "components/variations/variations_associated_data.h"
19 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/l10n/l10n_util.h"
20 22
21 namespace flags_ui { 23 namespace flags_ui {
22 24
23 namespace { 25 namespace {
24 26
25 // Convert switch constants to proper CommandLine::StringType strings. 27 // Convert switch constants to proper CommandLine::StringType strings.
26 base::CommandLine::StringType GetSwitchString(const std::string& flag) { 28 base::CommandLine::StringType GetSwitchString(const std::string& flag) {
27 base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM); 29 base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
28 cmd_line.AppendSwitch(flag); 30 cmd_line.AppendSwitch(flag);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 // Adds the internal names for the specified entry to |names|. 91 // Adds the internal names for the specified entry to |names|.
90 void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) { 92 void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) {
91 switch (e.type) { 93 switch (e.type) {
92 case FeatureEntry::SINGLE_VALUE: 94 case FeatureEntry::SINGLE_VALUE:
93 case FeatureEntry::SINGLE_DISABLE_VALUE: 95 case FeatureEntry::SINGLE_DISABLE_VALUE:
94 names->insert(e.internal_name); 96 names->insert(e.internal_name);
95 break; 97 break;
96 case FeatureEntry::MULTI_VALUE: 98 case FeatureEntry::MULTI_VALUE:
97 case FeatureEntry::ENABLE_DISABLE_VALUE: 99 case FeatureEntry::ENABLE_DISABLE_VALUE:
98 case FeatureEntry::FEATURE_VALUE: 100 case FeatureEntry::FEATURE_VALUE:
99 for (int i = 0; i < e.num_choices; ++i) 101 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
100 names->insert(e.NameForChoice(i)); 102 for (int i = 0; i < e.num_options; ++i)
103 names->insert(e.NameForOption(i));
101 break; 104 break;
102 } 105 }
103 } 106 }
104 107
105 // Confirms that an entry is valid, used in a DCHECK in 108 // Confirms that an entry is valid, used in a DCHECK in
106 // SanitizeList below. 109 // SanitizeList below.
107 bool ValidateFeatureEntry(const FeatureEntry& e) { 110 bool ValidateFeatureEntry(const FeatureEntry& e) {
108 switch (e.type) { 111 switch (e.type) {
109 case FeatureEntry::SINGLE_VALUE: 112 case FeatureEntry::SINGLE_VALUE:
110 case FeatureEntry::SINGLE_DISABLE_VALUE: 113 case FeatureEntry::SINGLE_DISABLE_VALUE:
111 DCHECK_EQ(0, e.num_choices); 114 DCHECK_EQ(0, e.num_options);
112 DCHECK(!e.choices); 115 DCHECK(!e.choices);
113 return true; 116 return true;
114 case FeatureEntry::MULTI_VALUE: 117 case FeatureEntry::MULTI_VALUE:
115 DCHECK_GT(e.num_choices, 0); 118 DCHECK_GT(e.num_options, 0);
116 DCHECK(e.choices); 119 DCHECK(e.choices);
117 DCHECK(e.choices[0].command_line_switch); 120 DCHECK(e.choices[0].command_line_switch);
118 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]); 121 DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
119 return true; 122 return true;
120 case FeatureEntry::ENABLE_DISABLE_VALUE: 123 case FeatureEntry::ENABLE_DISABLE_VALUE:
121 DCHECK_EQ(3, e.num_choices); 124 DCHECK_EQ(3, e.num_options);
122 DCHECK(!e.choices); 125 DCHECK(!e.choices);
123 DCHECK(e.command_line_switch); 126 DCHECK(e.command_line_switch);
124 DCHECK(e.command_line_value); 127 DCHECK(e.command_line_value);
125 DCHECK(e.disable_command_line_switch); 128 DCHECK(e.disable_command_line_switch);
126 DCHECK(e.disable_command_line_value); 129 DCHECK(e.disable_command_line_value);
127 return true; 130 return true;
128 case FeatureEntry::FEATURE_VALUE: 131 case FeatureEntry::FEATURE_VALUE:
129 DCHECK_EQ(3, e.num_choices); 132 DCHECK_EQ(3, e.num_options);
130 DCHECK(!e.choices); 133 DCHECK(!e.choices);
131 DCHECK(e.feature); 134 DCHECK(e.feature);
132 return true; 135 return true;
136 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
137 DCHECK_GT(e.num_options, 2);
138 DCHECK(!e.choices);
139 DCHECK(e.feature);
140 DCHECK(e.feature_variations);
141 DCHECK(e.feature_trial);
142 return true;
133 } 143 }
134 NOTREACHED(); 144 NOTREACHED();
135 return false; 145 return false;
136 } 146 }
137 147
138 // Returns true if none of this entry's options have been enabled. 148 // Returns true if none of this entry's options have been enabled.
139 bool IsDefaultValue(const FeatureEntry& entry, 149 bool IsDefaultValue(const FeatureEntry& entry,
140 const std::set<std::string>& enabled_entries) { 150 const std::set<std::string>& enabled_entries) {
141 switch (entry.type) { 151 switch (entry.type) {
142 case FeatureEntry::SINGLE_VALUE: 152 case FeatureEntry::SINGLE_VALUE:
143 case FeatureEntry::SINGLE_DISABLE_VALUE: 153 case FeatureEntry::SINGLE_DISABLE_VALUE:
144 return enabled_entries.count(entry.internal_name) == 0; 154 return enabled_entries.count(entry.internal_name) == 0;
145 case FeatureEntry::MULTI_VALUE: 155 case FeatureEntry::MULTI_VALUE:
146 case FeatureEntry::ENABLE_DISABLE_VALUE: 156 case FeatureEntry::ENABLE_DISABLE_VALUE:
147 case FeatureEntry::FEATURE_VALUE: 157 case FeatureEntry::FEATURE_VALUE:
148 for (int i = 0; i < entry.num_choices; ++i) { 158 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
149 if (enabled_entries.count(entry.NameForChoice(i)) > 0) 159 for (int i = 0; i < entry.num_options; ++i) {
160 if (enabled_entries.count(entry.NameForOption(i)) > 0)
150 return false; 161 return false;
151 } 162 }
152 return true; 163 return true;
153 } 164 }
154 NOTREACHED(); 165 NOTREACHED();
155 return true; 166 return true;
156 } 167 }
157 168
158 // Returns the Value representing the choice data in the specified entry. 169 // Returns the Value representing the choice data in the specified entry.
159 base::Value* CreateChoiceData(const FeatureEntry& entry, 170 base::Value* CreateOptionsData(const FeatureEntry& entry,
160 const std::set<std::string>& enabled_entries) { 171 const std::set<std::string>& enabled_entries) {
161 DCHECK(entry.type == FeatureEntry::MULTI_VALUE || 172 DCHECK(entry.type == FeatureEntry::MULTI_VALUE ||
162 entry.type == FeatureEntry::ENABLE_DISABLE_VALUE || 173 entry.type == FeatureEntry::ENABLE_DISABLE_VALUE ||
163 entry.type == FeatureEntry::FEATURE_VALUE); 174 entry.type == FeatureEntry::FEATURE_VALUE ||
175 entry.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
164 base::ListValue* result = new base::ListValue; 176 base::ListValue* result = new base::ListValue;
165 for (int i = 0; i < entry.num_choices; ++i) { 177 for (int i = 0; i < entry.num_options; ++i) {
166 base::DictionaryValue* value = new base::DictionaryValue; 178 base::DictionaryValue* value = new base::DictionaryValue;
167 const std::string name = entry.NameForChoice(i); 179 const std::string name = entry.NameForOption(i);
168 value->SetString("internal_name", name); 180 value->SetString("internal_name", name);
169 value->SetString("description", entry.DescriptionForChoice(i)); 181 value->SetString("description", entry.DescriptionForOption(i));
170 value->SetBoolean("selected", enabled_entries.count(name) > 0); 182 value->SetBoolean("selected", enabled_entries.count(name) > 0);
171 result->Append(value); 183 result->Append(value);
172 } 184 }
173 return result; 185 return result;
174 } 186 }
175 187
176 } // namespace 188 } // namespace
177 189
178 // Keeps track of affected switches for each FeatureEntry, based on which 190 // Keeps track of affected switches for each FeatureEntry, based on which
179 // choice is selected for it. 191 // choice is selected for it.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 std::map<std::string, SwitchEntry> name_to_switch_map; 226 std::map<std::string, SwitchEntry> name_to_switch_map;
215 for (size_t i = 0; i < num_feature_entries_; ++i) { 227 for (size_t i = 0; i < num_feature_entries_; ++i) {
216 const FeatureEntry& e = feature_entries_[i]; 228 const FeatureEntry& e = feature_entries_[i];
217 switch (e.type) { 229 switch (e.type) {
218 case FeatureEntry::SINGLE_VALUE: 230 case FeatureEntry::SINGLE_VALUE:
219 case FeatureEntry::SINGLE_DISABLE_VALUE: 231 case FeatureEntry::SINGLE_DISABLE_VALUE:
220 AddSwitchMapping(e.internal_name, e.command_line_switch, 232 AddSwitchMapping(e.internal_name, e.command_line_switch,
221 e.command_line_value, &name_to_switch_map); 233 e.command_line_value, &name_to_switch_map);
222 break; 234 break;
223 case FeatureEntry::MULTI_VALUE: 235 case FeatureEntry::MULTI_VALUE:
224 for (int j = 0; j < e.num_choices; ++j) { 236 for (int j = 0; j < e.num_options; ++j) {
225 AddSwitchMapping(e.NameForChoice(j), e.choices[j].command_line_switch, 237 AddSwitchMapping(e.NameForOption(j), e.choices[j].command_line_switch,
226 e.choices[j].command_line_value, 238 e.choices[j].command_line_value,
227 &name_to_switch_map); 239 &name_to_switch_map);
228 } 240 }
229 break; 241 break;
230 case FeatureEntry::ENABLE_DISABLE_VALUE: 242 case FeatureEntry::ENABLE_DISABLE_VALUE:
231 AddSwitchMapping(e.NameForChoice(0), std::string(), std::string(), 243 AddSwitchMapping(e.NameForOption(0), std::string(), std::string(),
232 &name_to_switch_map); 244 &name_to_switch_map);
233 AddSwitchMapping(e.NameForChoice(1), e.command_line_switch, 245 AddSwitchMapping(e.NameForOption(1), e.command_line_switch,
234 e.command_line_value, &name_to_switch_map); 246 e.command_line_value, &name_to_switch_map);
235 AddSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch, 247 AddSwitchMapping(e.NameForOption(2), e.disable_command_line_switch,
236 e.disable_command_line_value, &name_to_switch_map); 248 e.disable_command_line_value, &name_to_switch_map);
237 break; 249 break;
238 case FeatureEntry::FEATURE_VALUE: 250 case FeatureEntry::FEATURE_VALUE:
239 AddFeatureMapping(e.NameForChoice(0), std::string(), false, 251 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
240 &name_to_switch_map); 252 for (int j = 0; j < e.num_options; ++j) {
241 AddFeatureMapping(e.NameForChoice(1), e.feature->name, true, 253 FeatureEntry::State state = e.StateForOption(j);
242 &name_to_switch_map); 254 if (state == FeatureEntry::State::DEFAULT) {
243 AddFeatureMapping(e.NameForChoice(2), e.feature->name, false, 255 AddFeatureMapping(e.NameForOption(j), std::string(), false,
244 &name_to_switch_map); 256 &name_to_switch_map);
257 } else {
258 const std::string& key = e.NameForOption(j);
Alexei Svitkine (slow) 2016/06/08 18:54:35 Nit: Just inline this below
jkrcal 2016/06/09 09:55:15 Done.
259 AddFeatureMapping(key, e.feature->name,
260 state == FeatureEntry::State::ENABLED,
261 &name_to_switch_map);
262 }
263 }
245 break; 264 break;
246 } 265 }
247 } 266 }
248 267
249 AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels, 268 AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels,
250 command_line, enable_features_flag_name, 269 command_line, enable_features_flag_name,
251 disable_features_flag_name); 270 disable_features_flag_name);
252 } 271 }
253 272
254 bool FlagsState::IsRestartNeededToCommitChanges() { 273 bool FlagsState::IsRestartNeededToCommitChanges() {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 else 314 else
296 needs_restart_ |= (enabled_entries.erase(internal_name) > 0); 315 needs_restart_ |= (enabled_entries.erase(internal_name) > 0);
297 } else if (e->type == FeatureEntry::SINGLE_DISABLE_VALUE) { 316 } else if (e->type == FeatureEntry::SINGLE_DISABLE_VALUE) {
298 if (!enable) 317 if (!enable)
299 needs_restart_ |= enabled_entries.insert(internal_name).second; 318 needs_restart_ |= enabled_entries.insert(internal_name).second;
300 else 319 else
301 needs_restart_ |= (enabled_entries.erase(internal_name) > 0); 320 needs_restart_ |= (enabled_entries.erase(internal_name) > 0);
302 } else { 321 } else {
303 if (enable) { 322 if (enable) {
304 // Enable the first choice. 323 // Enable the first choice.
305 needs_restart_ |= enabled_entries.insert(e->NameForChoice(0)).second; 324 needs_restart_ |= enabled_entries.insert(e->NameForOption(0)).second;
306 } else { 325 } else {
307 // Find the currently enabled choice and disable it. 326 // Find the currently enabled choice and disable it.
308 for (int i = 0; i < e->num_choices; ++i) { 327 for (int i = 0; i < e->num_options; ++i) {
309 std::string choice_name = e->NameForChoice(i); 328 std::string choice_name = e->NameForOption(i);
310 if (enabled_entries.find(choice_name) != enabled_entries.end()) { 329 if (enabled_entries.find(choice_name) != enabled_entries.end()) {
311 needs_restart_ = true; 330 needs_restart_ = true;
312 enabled_entries.erase(choice_name); 331 enabled_entries.erase(choice_name);
313 // Continue on just in case there's a bug and more than one 332 // Continue on just in case there's a bug and more than one
314 // entry for this choice was enabled. 333 // entry for this choice was enabled.
315 } 334 }
316 } 335 }
317 } 336 }
318 } 337 }
319 338
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 std::set<std::string> no_entries; 389 std::set<std::string> no_entries;
371 flags_storage->SetFlags(no_entries); 390 flags_storage->SetFlags(no_entries);
372 } 391 }
373 392
374 void FlagsState::Reset() { 393 void FlagsState::Reset() {
375 needs_restart_ = false; 394 needs_restart_ = false;
376 flags_switches_.clear(); 395 flags_switches_.clear();
377 appended_switches_.clear(); 396 appended_switches_.clear();
378 } 397 }
379 398
399 void FlagsState::RegisterFeatureVariationParameters(
400 FlagsStorage* flags_storage) {
401 std::set<std::string> enabled_entries;
402 GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries);
403
404 for (size_t i = 0; i < num_feature_entries_; ++i) {
405 const FeatureEntry& e = feature_entries_[i];
406 if (e.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) {
407 for (int j = 0; j < e.num_options; ++j) {
408 const std::string& key = e.NameForOption(j);
409 const FeatureEntry::FeatureVariation* variation =
410 e.VariationForOption(j);
411 if (enabled_entries.count(key) && variation != nullptr) {
412 // If the option is selected by the user & has variation, register it.
413 std::map<std::string, std::string> params;
414 for (int i = 0; i < variation->num_params; ++i) {
415 params[variation->params[i].param_name] =
416 variation->params[i].param_value;
417 }
418
419 bool success = variations::AssociateVariationParams(
420 e.feature_trial, kTrialGroupAboutFlags, params);
421 if (success) {
422 // Successful association also means that no group is created and
423 // selected for the trial. Thus, create the trial to make it active
424 // and to select the group.
425 // This way, the parameters cannot get overwritten in later phases
426 // (such as from the server).
427 base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
428 e.feature_trial, kTrialGroupAboutFlags);
429 if (!trial) {
430 DLOG(WARNING) << "Could not create the trial " << e.feature_trial
431 << " with group " << kTrialGroupAboutFlags;
432 }
433 }
434 }
Alexei Svitkine (slow) 2016/06/08 18:54:35 This is a lot of nesting. Can you make the refacto
jkrcal 2016/06/09 09:55:15 Done. I moved it out one block deeper, I think it
435 }
436 }
437 }
438 }
439
380 void FlagsState::GetFlagFeatureEntries( 440 void FlagsState::GetFlagFeatureEntries(
381 FlagsStorage* flags_storage, 441 FlagsStorage* flags_storage,
382 FlagAccess access, 442 FlagAccess access,
383 base::ListValue* supported_entries, 443 base::ListValue* supported_entries,
384 base::ListValue* unsupported_entries, 444 base::ListValue* unsupported_entries,
385 base::Callback<bool(const FeatureEntry&)> skip_feature_entry) { 445 base::Callback<bool(const FeatureEntry&)> skip_feature_entry) {
386 std::set<std::string> enabled_entries; 446 std::set<std::string> enabled_entries;
387 GetSanitizedEnabledFlags(flags_storage, &enabled_entries); 447 GetSanitizedEnabledFlags(flags_storage, &enabled_entries);
388 448
389 int current_platform = GetCurrentPlatform(); 449 int current_platform = GetCurrentPlatform();
(...skipping 21 matching lines...) Expand all
411 case FeatureEntry::SINGLE_DISABLE_VALUE: 471 case FeatureEntry::SINGLE_DISABLE_VALUE:
412 data->SetBoolean( 472 data->SetBoolean(
413 "enabled", 473 "enabled",
414 (!is_default_value && entry.type == FeatureEntry::SINGLE_VALUE) || 474 (!is_default_value && entry.type == FeatureEntry::SINGLE_VALUE) ||
415 (is_default_value && 475 (is_default_value &&
416 entry.type == FeatureEntry::SINGLE_DISABLE_VALUE)); 476 entry.type == FeatureEntry::SINGLE_DISABLE_VALUE));
417 break; 477 break;
418 case FeatureEntry::MULTI_VALUE: 478 case FeatureEntry::MULTI_VALUE:
419 case FeatureEntry::ENABLE_DISABLE_VALUE: 479 case FeatureEntry::ENABLE_DISABLE_VALUE:
420 case FeatureEntry::FEATURE_VALUE: 480 case FeatureEntry::FEATURE_VALUE:
421 data->Set("choices", CreateChoiceData(entry, enabled_entries)); 481 case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
482 data->Set("options", CreateOptionsData(entry, enabled_entries));
422 break; 483 break;
423 } 484 }
424 485
425 bool supported = (entry.supported_platforms & current_platform) != 0; 486 bool supported = (entry.supported_platforms & current_platform) != 0;
426 #if defined(OS_CHROMEOS) 487 #if defined(OS_CHROMEOS)
427 if (access == kOwnerAccessToFlags && 488 if (access == kOwnerAccessToFlags &&
428 (entry.supported_platforms & kOsCrOSOwnerOnly) != 0) { 489 (entry.supported_platforms & kOsCrOSOwnerOnly) != 0) {
429 supported = true; 490 supported = true;
430 } 491 }
431 #endif 492 #endif
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 } 692 }
632 693
633 std::set<std::string> new_enabled_entries = 694 std::set<std::string> new_enabled_entries =
634 base::STLSetIntersection<std::set<std::string>>(platform_entries, 695 base::STLSetIntersection<std::set<std::string>>(platform_entries,
635 *result); 696 *result);
636 697
637 result->swap(new_enabled_entries); 698 result->swap(new_enabled_entries);
638 } 699 }
639 700
640 } // namespace flags_ui 701 } // namespace flags_ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698