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 "base/feature_list.h" | 5 #include "base/feature_list.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
(...skipping 12 matching lines...) Expand all Loading... |
23 // have more control over initialization timing. Leaky. | 23 // have more control over initialization timing. Leaky. |
24 FeatureList* g_instance = nullptr; | 24 FeatureList* g_instance = nullptr; |
25 | 25 |
26 // Some characters are not allowed to appear in feature names or the associated | 26 // Some characters are not allowed to appear in feature names or the associated |
27 // field trial names, as they are used as special characters for command-line | 27 // field trial names, as they are used as special characters for command-line |
28 // serialization. This function checks that the strings are ASCII (since they | 28 // serialization. This function checks that the strings are ASCII (since they |
29 // are used in command-line API functions that require ASCII) and whether there | 29 // are used in command-line API functions that require ASCII) and whether there |
30 // are any reserved characters present, returning true if the string is valid. | 30 // are any reserved characters present, returning true if the string is valid. |
31 // Only called in DCHECKs. | 31 // Only called in DCHECKs. |
32 bool IsValidFeatureOrFieldTrialName(const std::string& name) { | 32 bool IsValidFeatureOrFieldTrialName(const std::string& name) { |
33 return IsStringASCII(name) && name.find_first_of(",<") == std::string::npos; | 33 return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos; |
34 } | 34 } |
35 | 35 |
36 } // namespace | 36 } // namespace |
37 | 37 |
38 FeatureList::FeatureList() : initialized_(false) {} | 38 FeatureList::FeatureList() : initialized_(false) {} |
39 | 39 |
40 FeatureList::~FeatureList() {} | 40 FeatureList::~FeatureList() {} |
41 | 41 |
42 void FeatureList::InitializeFromCommandLine( | 42 void FeatureList::InitializeFromCommandLine( |
43 const std::string& enable_features, | 43 const std::string& enable_features, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 RegisterOverride(feature_name, override_state, field_trial); | 92 RegisterOverride(feature_name, override_state, field_trial); |
93 } | 93 } |
94 | 94 |
95 void FeatureList::GetFeatureOverrides(std::string* enable_overrides, | 95 void FeatureList::GetFeatureOverrides(std::string* enable_overrides, |
96 std::string* disable_overrides) { | 96 std::string* disable_overrides) { |
97 DCHECK(initialized_); | 97 DCHECK(initialized_); |
98 | 98 |
99 enable_overrides->clear(); | 99 enable_overrides->clear(); |
100 disable_overrides->clear(); | 100 disable_overrides->clear(); |
101 | 101 |
| 102 // Note: Since |overrides_| is a std::map, iteration will be in alphabetical |
| 103 // order. This not guaranteed to users of this function, but is useful for |
| 104 // tests to assume the order. |
102 for (const auto& entry : overrides_) { | 105 for (const auto& entry : overrides_) { |
103 std::string* target_list = nullptr; | 106 std::string* target_list = nullptr; |
104 switch (entry.second.overridden_state) { | 107 switch (entry.second.overridden_state) { |
| 108 case OVERRIDE_USE_DEFAULT: |
105 case OVERRIDE_ENABLE_FEATURE: | 109 case OVERRIDE_ENABLE_FEATURE: |
106 target_list = enable_overrides; | 110 target_list = enable_overrides; |
107 break; | 111 break; |
108 case OVERRIDE_DISABLE_FEATURE: | 112 case OVERRIDE_DISABLE_FEATURE: |
109 target_list = disable_overrides; | 113 target_list = disable_overrides; |
110 break; | 114 break; |
111 case OVERRIDE_USE_DEFAULT: | |
112 continue; | |
113 } | 115 } |
114 | 116 |
115 if (!target_list->empty()) | 117 if (!target_list->empty()) |
116 target_list->push_back(','); | 118 target_list->push_back(','); |
| 119 if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT) |
| 120 target_list->push_back('*'); |
117 target_list->append(entry.first); | 121 target_list->append(entry.first); |
118 if (entry.second.field_trial) { | 122 if (entry.second.field_trial) { |
119 target_list->push_back('<'); | 123 target_list->push_back('<'); |
120 target_list->append(entry.second.field_trial->trial_name()); | 124 target_list->append(entry.second.field_trial->trial_name()); |
121 } | 125 } |
122 } | 126 } |
123 } | 127 } |
124 | 128 |
125 // static | 129 // static |
126 bool FeatureList::IsEnabled(const Feature& feature) { | 130 bool FeatureList::IsEnabled(const Feature& feature) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 } | 212 } |
209 | 213 |
210 void FeatureList::RegisterOverride(StringPiece feature_name, | 214 void FeatureList::RegisterOverride(StringPiece feature_name, |
211 OverrideState overridden_state, | 215 OverrideState overridden_state, |
212 FieldTrial* field_trial) { | 216 FieldTrial* field_trial) { |
213 DCHECK(!initialized_); | 217 DCHECK(!initialized_); |
214 if (field_trial) { | 218 if (field_trial) { |
215 DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name())) | 219 DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name())) |
216 << field_trial->trial_name(); | 220 << field_trial->trial_name(); |
217 } | 221 } |
| 222 if (feature_name.starts_with("*")) { |
| 223 feature_name = feature_name.substr(1); |
| 224 overridden_state = OVERRIDE_USE_DEFAULT; |
| 225 } |
218 | 226 |
219 // Note: The semantics of insert() is that it does not overwrite the entry if | 227 // Note: The semantics of insert() is that it does not overwrite the entry if |
220 // one already exists for the key. Thus, only the first override for a given | 228 // one already exists for the key. Thus, only the first override for a given |
221 // feature name takes effect. | 229 // feature name takes effect. |
222 overrides_.insert(std::make_pair( | 230 overrides_.insert(std::make_pair( |
223 feature_name.as_string(), OverrideEntry(overridden_state, field_trial))); | 231 feature_name.as_string(), OverrideEntry(overridden_state, field_trial))); |
224 } | 232 } |
225 | 233 |
226 bool FeatureList::CheckFeatureIdentity(const Feature& feature) { | 234 bool FeatureList::CheckFeatureIdentity(const Feature& feature) { |
227 AutoLock auto_lock(feature_identity_tracker_lock_); | 235 AutoLock auto_lock(feature_identity_tracker_lock_); |
228 | 236 |
229 auto it = feature_identity_tracker_.find(feature.name); | 237 auto it = feature_identity_tracker_.find(feature.name); |
230 if (it == feature_identity_tracker_.end()) { | 238 if (it == feature_identity_tracker_.end()) { |
231 // If it's not tracked yet, register it. | 239 // If it's not tracked yet, register it. |
232 feature_identity_tracker_[feature.name] = &feature; | 240 feature_identity_tracker_[feature.name] = &feature; |
233 return true; | 241 return true; |
234 } | 242 } |
235 // Compare address of |feature| to the existing tracked entry. | 243 // Compare address of |feature| to the existing tracked entry. |
236 return it->second == &feature; | 244 return it->second == &feature; |
237 } | 245 } |
238 | 246 |
239 FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state, | 247 FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state, |
240 FieldTrial* field_trial) | 248 FieldTrial* field_trial) |
241 : overridden_state(overridden_state), | 249 : overridden_state(overridden_state), |
242 field_trial(field_trial), | 250 field_trial(field_trial), |
243 overridden_by_field_trial(field_trial != nullptr) {} | 251 overridden_by_field_trial(field_trial != nullptr) {} |
244 | 252 |
245 } // namespace base | 253 } // namespace base |
OLD | NEW |