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

Side by Side Diff: base/feature_list.cc

Issue 2138923002: Updating FeatureList default initialization pattern (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2785
Patch Set: Created 4 years, 5 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
« no previous file with comments | « base/feature_list.h ('k') | base/feature_list_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "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>
11 11
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/field_trial.h" 13 #include "base/metrics/field_trial.h"
14 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
16 16
17 namespace base { 17 namespace base {
18 18
19 namespace { 19 namespace {
20 20
21 // Pointer to the FeatureList instance singleton that was set via 21 // Pointer to the FeatureList instance singleton that was set via
22 // FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to 22 // FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
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 // Tracks whether the FeatureList instance was initialized via an accessor.
27 bool g_initialized_from_accessor = false;
28
26 // Some characters are not allowed to appear in feature names or the associated 29 // 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 30 // 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 31 // 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 32 // 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. 33 // are any reserved characters present, returning true if the string is valid.
31 // Only called in DCHECKs. 34 // Only called in DCHECKs.
32 bool IsValidFeatureOrFieldTrialName(const std::string& name) { 35 bool IsValidFeatureOrFieldTrialName(const std::string& name) {
33 return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos; 36 return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
34 } 37 }
35 38
36 } // namespace 39 } // namespace
37 40
38 FeatureList::FeatureList() 41 FeatureList::FeatureList() {}
39 : initialized_(false),
40 initialized_from_command_line_(false) {
41 }
42 42
43 FeatureList::~FeatureList() {} 43 FeatureList::~FeatureList() {}
44 44
45 void FeatureList::InitializeFromCommandLine( 45 void FeatureList::InitializeFromCommandLine(
46 const std::string& enable_features, 46 const std::string& enable_features,
47 const std::string& disable_features) { 47 const std::string& disable_features) {
48 DCHECK(!initialized_); 48 DCHECK(!initialized_);
49 49
50 // Process disabled features first, so that disabled ones take precedence over 50 // Process disabled features first, so that disabled ones take precedence over
51 // enabled ones (since RegisterOverride() uses insert()). 51 // enabled ones (since RegisterOverride() uses insert()).
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 target_list->append(entry.first); 126 target_list->append(entry.first);
127 if (entry.second.field_trial) { 127 if (entry.second.field_trial) {
128 target_list->push_back('<'); 128 target_list->push_back('<');
129 target_list->append(entry.second.field_trial->trial_name()); 129 target_list->append(entry.second.field_trial->trial_name());
130 } 130 }
131 } 131 }
132 } 132 }
133 133
134 // static 134 // static
135 bool FeatureList::IsEnabled(const Feature& feature) { 135 bool FeatureList::IsEnabled(const Feature& feature) {
136 return GetInstance()->IsFeatureEnabled(feature); 136 if (!g_instance) {
137 g_initialized_from_accessor = true;
138 return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
139 }
140 return g_instance->IsFeatureEnabled(feature);
137 } 141 }
138 142
139 // static 143 // static
140 FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) { 144 FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
141 return GetInstance()->GetAssociatedFieldTrial(feature); 145 return GetInstance()->GetAssociatedFieldTrial(feature);
142 } 146 }
143 147
144 // static 148 // static
145 std::vector<std::string> FeatureList::SplitFeatureListString( 149 std::vector<std::string> FeatureList::SplitFeatureListString(
146 const std::string& input) { 150 const std::string& input) {
147 return SplitString(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); 151 return SplitString(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
148 } 152 }
149 153
150 // static 154 // static
151 bool FeatureList::InitializeInstance(const std::string& enable_features, 155 bool FeatureList::InitializeInstance(const std::string& enable_features,
152 const std::string& disable_features) { 156 const std::string& disable_features) {
153 // We want to initialize a new instance here to support command-line features 157 // We want to initialize a new instance here to support command-line features
154 // in testing better. For example, we initialize a dummy instance in 158 // in testing better. For example, we initialize a dummy instance in
155 // base/test/test_suite.cc, and override it in content/browser/ 159 // base/test/test_suite.cc, and override it in content/browser/
156 // browser_main_loop.cc. 160 // browser_main_loop.cc.
157 // On the other hand, we want to avoid re-initialization from command line. 161 // On the other hand, we want to avoid re-initialization from command line.
158 // For example, we initialize an instance in chrome/browser/ 162 // For example, we initialize an instance in chrome/browser/
159 // chrome_browser_main.cc and do not override it in content/browser/ 163 // chrome_browser_main.cc and do not override it in content/browser/
160 // browser_main_loop.cc. 164 // browser_main_loop.cc.
165 // If the singleton was previously initialized from within an accessor, we
166 // want to prevent callers from reinitializing the singleton and masking the
167 // accessor call(s) which likely returned incorrect information.
168 CHECK(!g_initialized_from_accessor);
161 bool instance_existed_before = false; 169 bool instance_existed_before = false;
162 if (g_instance) { 170 if (g_instance) {
163 if (g_instance->initialized_from_command_line_) 171 if (g_instance->initialized_from_command_line_)
164 return false; 172 return false;
165 173
166 delete g_instance; 174 delete g_instance;
167 g_instance = nullptr; 175 g_instance = nullptr;
168 instance_existed_before = true; 176 instance_existed_before = true;
169 } 177 }
170 178
(...skipping 14 matching lines...) Expand all
185 instance->FinalizeInitialization(); 193 instance->FinalizeInitialization();
186 194
187 // Note: Intentional leak of global singleton. 195 // Note: Intentional leak of global singleton.
188 g_instance = instance.release(); 196 g_instance = instance.release();
189 } 197 }
190 198
191 // static 199 // static
192 void FeatureList::ClearInstanceForTesting() { 200 void FeatureList::ClearInstanceForTesting() {
193 delete g_instance; 201 delete g_instance;
194 g_instance = nullptr; 202 g_instance = nullptr;
203 g_initialized_from_accessor = false;
195 } 204 }
196 205
197 void FeatureList::FinalizeInitialization() { 206 void FeatureList::FinalizeInitialization() {
198 DCHECK(!initialized_); 207 DCHECK(!initialized_);
199 initialized_ = true; 208 initialized_ = true;
200 } 209 }
201 210
202 bool FeatureList::IsFeatureEnabled(const Feature& feature) { 211 bool FeatureList::IsFeatureEnabled(const Feature& feature) {
203 DCHECK(initialized_); 212 DCHECK(initialized_);
204 DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name; 213 DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 return it->second == &feature; 297 return it->second == &feature;
289 } 298 }
290 299
291 FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state, 300 FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
292 FieldTrial* field_trial) 301 FieldTrial* field_trial)
293 : overridden_state(overridden_state), 302 : overridden_state(overridden_state),
294 field_trial(field_trial), 303 field_trial(field_trial),
295 overridden_by_field_trial(field_trial != nullptr) {} 304 overridden_by_field_trial(field_trial != nullptr) {}
296 305
297 } // namespace base 306 } // namespace base
OLDNEW
« no previous file with comments | « base/feature_list.h ('k') | base/feature_list_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698