xref: /aosp_15_r20/external/libchrome/base/feature_list.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/feature_list.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
8*635a8641SAndroid Build Coastguard Worker 
9*635a8641SAndroid Build Coastguard Worker #include <utility>
10*635a8641SAndroid Build Coastguard Worker #include <vector>
11*635a8641SAndroid Build Coastguard Worker 
12*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/metrics/field_trial.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/pickle.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
18*635a8641SAndroid Build Coastguard Worker 
19*635a8641SAndroid Build Coastguard Worker namespace base {
20*635a8641SAndroid Build Coastguard Worker 
21*635a8641SAndroid Build Coastguard Worker namespace {
22*635a8641SAndroid Build Coastguard Worker 
23*635a8641SAndroid Build Coastguard Worker // Pointer to the FeatureList instance singleton that was set via
24*635a8641SAndroid Build Coastguard Worker // FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
25*635a8641SAndroid Build Coastguard Worker // have more control over initialization timing. Leaky.
26*635a8641SAndroid Build Coastguard Worker FeatureList* g_feature_list_instance = nullptr;
27*635a8641SAndroid Build Coastguard Worker 
28*635a8641SAndroid Build Coastguard Worker // Tracks whether the FeatureList instance was initialized via an accessor.
29*635a8641SAndroid Build Coastguard Worker bool g_initialized_from_accessor = false;
30*635a8641SAndroid Build Coastguard Worker 
31*635a8641SAndroid Build Coastguard Worker // An allocator entry for a feature in shared memory. The FeatureEntry is
32*635a8641SAndroid Build Coastguard Worker // followed by a base::Pickle object that contains the feature and trial name.
33*635a8641SAndroid Build Coastguard Worker struct FeatureEntry {
34*635a8641SAndroid Build Coastguard Worker   // SHA1(FeatureEntry): Increment this if structure changes!
35*635a8641SAndroid Build Coastguard Worker   static constexpr uint32_t kPersistentTypeId = 0x06567CA6 + 1;
36*635a8641SAndroid Build Coastguard Worker 
37*635a8641SAndroid Build Coastguard Worker   // Expected size for 32/64-bit check.
38*635a8641SAndroid Build Coastguard Worker   static constexpr size_t kExpectedInstanceSize = 8;
39*635a8641SAndroid Build Coastguard Worker 
40*635a8641SAndroid Build Coastguard Worker   // Specifies whether a feature override enables or disables the feature. Same
41*635a8641SAndroid Build Coastguard Worker   // values as the OverrideState enum in feature_list.h
42*635a8641SAndroid Build Coastguard Worker   uint32_t override_state;
43*635a8641SAndroid Build Coastguard Worker 
44*635a8641SAndroid Build Coastguard Worker   // Size of the pickled structure, NOT the total size of this entry.
45*635a8641SAndroid Build Coastguard Worker   uint32_t pickle_size;
46*635a8641SAndroid Build Coastguard Worker 
47*635a8641SAndroid Build Coastguard Worker   // Reads the feature and trial name from the pickle. Calling this is only
48*635a8641SAndroid Build Coastguard Worker   // valid on an initialized entry that's in shared memory.
GetFeatureAndTrialNamebase::__anon621f89f00111::FeatureEntry49*635a8641SAndroid Build Coastguard Worker   bool GetFeatureAndTrialName(StringPiece* feature_name,
50*635a8641SAndroid Build Coastguard Worker                               StringPiece* trial_name) const {
51*635a8641SAndroid Build Coastguard Worker     const char* src =
52*635a8641SAndroid Build Coastguard Worker         reinterpret_cast<const char*>(this) + sizeof(FeatureEntry);
53*635a8641SAndroid Build Coastguard Worker 
54*635a8641SAndroid Build Coastguard Worker     Pickle pickle(src, pickle_size);
55*635a8641SAndroid Build Coastguard Worker     PickleIterator pickle_iter(pickle);
56*635a8641SAndroid Build Coastguard Worker 
57*635a8641SAndroid Build Coastguard Worker     if (!pickle_iter.ReadStringPiece(feature_name))
58*635a8641SAndroid Build Coastguard Worker       return false;
59*635a8641SAndroid Build Coastguard Worker 
60*635a8641SAndroid Build Coastguard Worker     // Return true because we are not guaranteed to have a trial name anyways.
61*635a8641SAndroid Build Coastguard Worker     auto sink = pickle_iter.ReadStringPiece(trial_name);
62*635a8641SAndroid Build Coastguard Worker     ALLOW_UNUSED_LOCAL(sink);
63*635a8641SAndroid Build Coastguard Worker     return true;
64*635a8641SAndroid Build Coastguard Worker   }
65*635a8641SAndroid Build Coastguard Worker };
66*635a8641SAndroid Build Coastguard Worker 
67*635a8641SAndroid Build Coastguard Worker // Some characters are not allowed to appear in feature names or the associated
68*635a8641SAndroid Build Coastguard Worker // field trial names, as they are used as special characters for command-line
69*635a8641SAndroid Build Coastguard Worker // serialization. This function checks that the strings are ASCII (since they
70*635a8641SAndroid Build Coastguard Worker // are used in command-line API functions that require ASCII) and whether there
71*635a8641SAndroid Build Coastguard Worker // are any reserved characters present, returning true if the string is valid.
72*635a8641SAndroid Build Coastguard Worker // Only called in DCHECKs.
IsValidFeatureOrFieldTrialName(const std::string & name)73*635a8641SAndroid Build Coastguard Worker bool IsValidFeatureOrFieldTrialName(const std::string& name) {
74*635a8641SAndroid Build Coastguard Worker   return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
75*635a8641SAndroid Build Coastguard Worker }
76*635a8641SAndroid Build Coastguard Worker 
77*635a8641SAndroid Build Coastguard Worker }  // namespace
78*635a8641SAndroid Build Coastguard Worker 
79*635a8641SAndroid Build Coastguard Worker #if DCHECK_IS_CONFIGURABLE
80*635a8641SAndroid Build Coastguard Worker const Feature kDCheckIsFatalFeature{"DcheckIsFatal",
81*635a8641SAndroid Build Coastguard Worker                                     base::FEATURE_DISABLED_BY_DEFAULT};
82*635a8641SAndroid Build Coastguard Worker #endif  // DCHECK_IS_CONFIGURABLE
83*635a8641SAndroid Build Coastguard Worker 
84*635a8641SAndroid Build Coastguard Worker FeatureList::FeatureList() = default;
85*635a8641SAndroid Build Coastguard Worker 
86*635a8641SAndroid Build Coastguard Worker FeatureList::~FeatureList() = default;
87*635a8641SAndroid Build Coastguard Worker 
InitializeFromCommandLine(const std::string & enable_features,const std::string & disable_features)88*635a8641SAndroid Build Coastguard Worker void FeatureList::InitializeFromCommandLine(
89*635a8641SAndroid Build Coastguard Worker     const std::string& enable_features,
90*635a8641SAndroid Build Coastguard Worker     const std::string& disable_features) {
91*635a8641SAndroid Build Coastguard Worker   DCHECK(!initialized_);
92*635a8641SAndroid Build Coastguard Worker 
93*635a8641SAndroid Build Coastguard Worker   // Process disabled features first, so that disabled ones take precedence over
94*635a8641SAndroid Build Coastguard Worker   // enabled ones (since RegisterOverride() uses insert()).
95*635a8641SAndroid Build Coastguard Worker   RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
96*635a8641SAndroid Build Coastguard Worker   RegisterOverridesFromCommandLine(enable_features, OVERRIDE_ENABLE_FEATURE);
97*635a8641SAndroid Build Coastguard Worker 
98*635a8641SAndroid Build Coastguard Worker   initialized_from_command_line_ = true;
99*635a8641SAndroid Build Coastguard Worker }
100*635a8641SAndroid Build Coastguard Worker 
InitializeFromSharedMemory(PersistentMemoryAllocator * allocator)101*635a8641SAndroid Build Coastguard Worker void FeatureList::InitializeFromSharedMemory(
102*635a8641SAndroid Build Coastguard Worker     PersistentMemoryAllocator* allocator) {
103*635a8641SAndroid Build Coastguard Worker   DCHECK(!initialized_);
104*635a8641SAndroid Build Coastguard Worker 
105*635a8641SAndroid Build Coastguard Worker   PersistentMemoryAllocator::Iterator iter(allocator);
106*635a8641SAndroid Build Coastguard Worker   const FeatureEntry* entry;
107*635a8641SAndroid Build Coastguard Worker   while ((entry = iter.GetNextOfObject<FeatureEntry>()) != nullptr) {
108*635a8641SAndroid Build Coastguard Worker     OverrideState override_state =
109*635a8641SAndroid Build Coastguard Worker         static_cast<OverrideState>(entry->override_state);
110*635a8641SAndroid Build Coastguard Worker 
111*635a8641SAndroid Build Coastguard Worker     StringPiece feature_name;
112*635a8641SAndroid Build Coastguard Worker     StringPiece trial_name;
113*635a8641SAndroid Build Coastguard Worker     if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name))
114*635a8641SAndroid Build Coastguard Worker       continue;
115*635a8641SAndroid Build Coastguard Worker 
116*635a8641SAndroid Build Coastguard Worker     FieldTrial* trial = FieldTrialList::Find(trial_name.as_string());
117*635a8641SAndroid Build Coastguard Worker     RegisterOverride(feature_name, override_state, trial);
118*635a8641SAndroid Build Coastguard Worker   }
119*635a8641SAndroid Build Coastguard Worker }
120*635a8641SAndroid Build Coastguard Worker 
IsFeatureOverriddenFromCommandLine(const std::string & feature_name,OverrideState state) const121*635a8641SAndroid Build Coastguard Worker bool FeatureList::IsFeatureOverriddenFromCommandLine(
122*635a8641SAndroid Build Coastguard Worker     const std::string& feature_name,
123*635a8641SAndroid Build Coastguard Worker     OverrideState state) const {
124*635a8641SAndroid Build Coastguard Worker   auto it = overrides_.find(feature_name);
125*635a8641SAndroid Build Coastguard Worker   return it != overrides_.end() && it->second.overridden_state == state &&
126*635a8641SAndroid Build Coastguard Worker          !it->second.overridden_by_field_trial;
127*635a8641SAndroid Build Coastguard Worker }
128*635a8641SAndroid Build Coastguard Worker 
AssociateReportingFieldTrial(const std::string & feature_name,OverrideState for_overridden_state,FieldTrial * field_trial)129*635a8641SAndroid Build Coastguard Worker void FeatureList::AssociateReportingFieldTrial(
130*635a8641SAndroid Build Coastguard Worker     const std::string& feature_name,
131*635a8641SAndroid Build Coastguard Worker     OverrideState for_overridden_state,
132*635a8641SAndroid Build Coastguard Worker     FieldTrial* field_trial) {
133*635a8641SAndroid Build Coastguard Worker   DCHECK(
134*635a8641SAndroid Build Coastguard Worker       IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
135*635a8641SAndroid Build Coastguard Worker 
136*635a8641SAndroid Build Coastguard Worker   // Only one associated field trial is supported per feature. This is generally
137*635a8641SAndroid Build Coastguard Worker   // enforced server-side.
138*635a8641SAndroid Build Coastguard Worker   OverrideEntry* entry = &overrides_.find(feature_name)->second;
139*635a8641SAndroid Build Coastguard Worker   if (entry->field_trial) {
140*635a8641SAndroid Build Coastguard Worker     NOTREACHED() << "Feature " << feature_name
141*635a8641SAndroid Build Coastguard Worker                  << " already has trial: " << entry->field_trial->trial_name()
142*635a8641SAndroid Build Coastguard Worker                  << ", associating trial: " << field_trial->trial_name();
143*635a8641SAndroid Build Coastguard Worker     return;
144*635a8641SAndroid Build Coastguard Worker   }
145*635a8641SAndroid Build Coastguard Worker 
146*635a8641SAndroid Build Coastguard Worker   entry->field_trial = field_trial;
147*635a8641SAndroid Build Coastguard Worker }
148*635a8641SAndroid Build Coastguard Worker 
RegisterFieldTrialOverride(const std::string & feature_name,OverrideState override_state,FieldTrial * field_trial)149*635a8641SAndroid Build Coastguard Worker void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
150*635a8641SAndroid Build Coastguard Worker                                              OverrideState override_state,
151*635a8641SAndroid Build Coastguard Worker                                              FieldTrial* field_trial) {
152*635a8641SAndroid Build Coastguard Worker   DCHECK(field_trial);
153*635a8641SAndroid Build Coastguard Worker   DCHECK(!ContainsKey(overrides_, feature_name) ||
154*635a8641SAndroid Build Coastguard Worker          !overrides_.find(feature_name)->second.field_trial)
155*635a8641SAndroid Build Coastguard Worker       << "Feature " << feature_name
156*635a8641SAndroid Build Coastguard Worker       << " has conflicting field trial overrides: "
157*635a8641SAndroid Build Coastguard Worker       << overrides_.find(feature_name)->second.field_trial->trial_name()
158*635a8641SAndroid Build Coastguard Worker       << " / " << field_trial->trial_name();
159*635a8641SAndroid Build Coastguard Worker 
160*635a8641SAndroid Build Coastguard Worker   RegisterOverride(feature_name, override_state, field_trial);
161*635a8641SAndroid Build Coastguard Worker }
162*635a8641SAndroid Build Coastguard Worker 
AddFeaturesToAllocator(PersistentMemoryAllocator * allocator)163*635a8641SAndroid Build Coastguard Worker void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) {
164*635a8641SAndroid Build Coastguard Worker   DCHECK(initialized_);
165*635a8641SAndroid Build Coastguard Worker 
166*635a8641SAndroid Build Coastguard Worker   for (const auto& override : overrides_) {
167*635a8641SAndroid Build Coastguard Worker     Pickle pickle;
168*635a8641SAndroid Build Coastguard Worker     pickle.WriteString(override.first);
169*635a8641SAndroid Build Coastguard Worker     if (override.second.field_trial)
170*635a8641SAndroid Build Coastguard Worker       pickle.WriteString(override.second.field_trial->trial_name());
171*635a8641SAndroid Build Coastguard Worker 
172*635a8641SAndroid Build Coastguard Worker     size_t total_size = sizeof(FeatureEntry) + pickle.size();
173*635a8641SAndroid Build Coastguard Worker     FeatureEntry* entry = allocator->New<FeatureEntry>(total_size);
174*635a8641SAndroid Build Coastguard Worker     if (!entry)
175*635a8641SAndroid Build Coastguard Worker       return;
176*635a8641SAndroid Build Coastguard Worker 
177*635a8641SAndroid Build Coastguard Worker     entry->override_state = override.second.overridden_state;
178*635a8641SAndroid Build Coastguard Worker     entry->pickle_size = pickle.size();
179*635a8641SAndroid Build Coastguard Worker 
180*635a8641SAndroid Build Coastguard Worker     char* dst = reinterpret_cast<char*>(entry) + sizeof(FeatureEntry);
181*635a8641SAndroid Build Coastguard Worker     memcpy(dst, pickle.data(), pickle.size());
182*635a8641SAndroid Build Coastguard Worker 
183*635a8641SAndroid Build Coastguard Worker     allocator->MakeIterable(entry);
184*635a8641SAndroid Build Coastguard Worker   }
185*635a8641SAndroid Build Coastguard Worker }
186*635a8641SAndroid Build Coastguard Worker 
GetFeatureOverrides(std::string * enable_overrides,std::string * disable_overrides)187*635a8641SAndroid Build Coastguard Worker void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
188*635a8641SAndroid Build Coastguard Worker                                       std::string* disable_overrides) {
189*635a8641SAndroid Build Coastguard Worker   GetFeatureOverridesImpl(enable_overrides, disable_overrides, false);
190*635a8641SAndroid Build Coastguard Worker }
191*635a8641SAndroid Build Coastguard Worker 
GetCommandLineFeatureOverrides(std::string * enable_overrides,std::string * disable_overrides)192*635a8641SAndroid Build Coastguard Worker void FeatureList::GetCommandLineFeatureOverrides(
193*635a8641SAndroid Build Coastguard Worker     std::string* enable_overrides,
194*635a8641SAndroid Build Coastguard Worker     std::string* disable_overrides) {
195*635a8641SAndroid Build Coastguard Worker   GetFeatureOverridesImpl(enable_overrides, disable_overrides, true);
196*635a8641SAndroid Build Coastguard Worker }
197*635a8641SAndroid Build Coastguard Worker 
198*635a8641SAndroid Build Coastguard Worker // static
IsEnabled(const Feature & feature)199*635a8641SAndroid Build Coastguard Worker bool FeatureList::IsEnabled(const Feature& feature) {
200*635a8641SAndroid Build Coastguard Worker   if (!g_feature_list_instance) {
201*635a8641SAndroid Build Coastguard Worker     g_initialized_from_accessor = true;
202*635a8641SAndroid Build Coastguard Worker     return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
203*635a8641SAndroid Build Coastguard Worker   }
204*635a8641SAndroid Build Coastguard Worker   return g_feature_list_instance->IsFeatureEnabled(feature);
205*635a8641SAndroid Build Coastguard Worker }
206*635a8641SAndroid Build Coastguard Worker 
207*635a8641SAndroid Build Coastguard Worker // static
GetFieldTrial(const Feature & feature)208*635a8641SAndroid Build Coastguard Worker FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
209*635a8641SAndroid Build Coastguard Worker   if (!g_feature_list_instance) {
210*635a8641SAndroid Build Coastguard Worker     g_initialized_from_accessor = true;
211*635a8641SAndroid Build Coastguard Worker     return nullptr;
212*635a8641SAndroid Build Coastguard Worker   }
213*635a8641SAndroid Build Coastguard Worker   return g_feature_list_instance->GetAssociatedFieldTrial(feature);
214*635a8641SAndroid Build Coastguard Worker }
215*635a8641SAndroid Build Coastguard Worker 
216*635a8641SAndroid Build Coastguard Worker // static
SplitFeatureListString(base::StringPiece input)217*635a8641SAndroid Build Coastguard Worker std::vector<base::StringPiece> FeatureList::SplitFeatureListString(
218*635a8641SAndroid Build Coastguard Worker     base::StringPiece input) {
219*635a8641SAndroid Build Coastguard Worker   return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
220*635a8641SAndroid Build Coastguard Worker }
221*635a8641SAndroid Build Coastguard Worker 
222*635a8641SAndroid Build Coastguard Worker // static
InitializeInstance(const std::string & enable_features,const std::string & disable_features)223*635a8641SAndroid Build Coastguard Worker bool FeatureList::InitializeInstance(const std::string& enable_features,
224*635a8641SAndroid Build Coastguard Worker                                      const std::string& disable_features) {
225*635a8641SAndroid Build Coastguard Worker   // We want to initialize a new instance here to support command-line features
226*635a8641SAndroid Build Coastguard Worker   // in testing better. For example, we initialize a dummy instance in
227*635a8641SAndroid Build Coastguard Worker   // base/test/test_suite.cc, and override it in content/browser/
228*635a8641SAndroid Build Coastguard Worker   // browser_main_loop.cc.
229*635a8641SAndroid Build Coastguard Worker   // On the other hand, we want to avoid re-initialization from command line.
230*635a8641SAndroid Build Coastguard Worker   // For example, we initialize an instance in chrome/browser/
231*635a8641SAndroid Build Coastguard Worker   // chrome_browser_main.cc and do not override it in content/browser/
232*635a8641SAndroid Build Coastguard Worker   // browser_main_loop.cc.
233*635a8641SAndroid Build Coastguard Worker   // If the singleton was previously initialized from within an accessor, we
234*635a8641SAndroid Build Coastguard Worker   // want to prevent callers from reinitializing the singleton and masking the
235*635a8641SAndroid Build Coastguard Worker   // accessor call(s) which likely returned incorrect information.
236*635a8641SAndroid Build Coastguard Worker   CHECK(!g_initialized_from_accessor);
237*635a8641SAndroid Build Coastguard Worker   bool instance_existed_before = false;
238*635a8641SAndroid Build Coastguard Worker   if (g_feature_list_instance) {
239*635a8641SAndroid Build Coastguard Worker     if (g_feature_list_instance->initialized_from_command_line_)
240*635a8641SAndroid Build Coastguard Worker       return false;
241*635a8641SAndroid Build Coastguard Worker 
242*635a8641SAndroid Build Coastguard Worker     delete g_feature_list_instance;
243*635a8641SAndroid Build Coastguard Worker     g_feature_list_instance = nullptr;
244*635a8641SAndroid Build Coastguard Worker     instance_existed_before = true;
245*635a8641SAndroid Build Coastguard Worker   }
246*635a8641SAndroid Build Coastguard Worker 
247*635a8641SAndroid Build Coastguard Worker   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
248*635a8641SAndroid Build Coastguard Worker   feature_list->InitializeFromCommandLine(enable_features, disable_features);
249*635a8641SAndroid Build Coastguard Worker   base::FeatureList::SetInstance(std::move(feature_list));
250*635a8641SAndroid Build Coastguard Worker   return !instance_existed_before;
251*635a8641SAndroid Build Coastguard Worker }
252*635a8641SAndroid Build Coastguard Worker 
253*635a8641SAndroid Build Coastguard Worker // static
GetInstance()254*635a8641SAndroid Build Coastguard Worker FeatureList* FeatureList::GetInstance() {
255*635a8641SAndroid Build Coastguard Worker   return g_feature_list_instance;
256*635a8641SAndroid Build Coastguard Worker }
257*635a8641SAndroid Build Coastguard Worker 
258*635a8641SAndroid Build Coastguard Worker // static
SetInstance(std::unique_ptr<FeatureList> instance)259*635a8641SAndroid Build Coastguard Worker void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
260*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_feature_list_instance);
261*635a8641SAndroid Build Coastguard Worker   instance->FinalizeInitialization();
262*635a8641SAndroid Build Coastguard Worker 
263*635a8641SAndroid Build Coastguard Worker   // Note: Intentional leak of global singleton.
264*635a8641SAndroid Build Coastguard Worker   g_feature_list_instance = instance.release();
265*635a8641SAndroid Build Coastguard Worker 
266*635a8641SAndroid Build Coastguard Worker #if DCHECK_IS_CONFIGURABLE
267*635a8641SAndroid Build Coastguard Worker   // Update the behaviour of LOG_DCHECK to match the Feature configuration.
268*635a8641SAndroid Build Coastguard Worker   // DCHECK is also forced to be FATAL if we are running a death-test.
269*635a8641SAndroid Build Coastguard Worker   // TODO(asvitkine): If we find other use-cases that need integrating here
270*635a8641SAndroid Build Coastguard Worker   // then define a proper API/hook for the purpose.
271*635a8641SAndroid Build Coastguard Worker   if (base::FeatureList::IsEnabled(kDCheckIsFatalFeature) ||
272*635a8641SAndroid Build Coastguard Worker       base::CommandLine::ForCurrentProcess()->HasSwitch(
273*635a8641SAndroid Build Coastguard Worker           "gtest_internal_run_death_test")) {
274*635a8641SAndroid Build Coastguard Worker     logging::LOG_DCHECK = logging::LOG_FATAL;
275*635a8641SAndroid Build Coastguard Worker   } else {
276*635a8641SAndroid Build Coastguard Worker     logging::LOG_DCHECK = logging::LOG_INFO;
277*635a8641SAndroid Build Coastguard Worker   }
278*635a8641SAndroid Build Coastguard Worker #endif  // DCHECK_IS_CONFIGURABLE
279*635a8641SAndroid Build Coastguard Worker }
280*635a8641SAndroid Build Coastguard Worker 
281*635a8641SAndroid Build Coastguard Worker // static
ClearInstanceForTesting()282*635a8641SAndroid Build Coastguard Worker std::unique_ptr<FeatureList> FeatureList::ClearInstanceForTesting() {
283*635a8641SAndroid Build Coastguard Worker   FeatureList* old_instance = g_feature_list_instance;
284*635a8641SAndroid Build Coastguard Worker   g_feature_list_instance = nullptr;
285*635a8641SAndroid Build Coastguard Worker   g_initialized_from_accessor = false;
286*635a8641SAndroid Build Coastguard Worker   return base::WrapUnique(old_instance);
287*635a8641SAndroid Build Coastguard Worker }
288*635a8641SAndroid Build Coastguard Worker 
289*635a8641SAndroid Build Coastguard Worker // static
RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance)290*635a8641SAndroid Build Coastguard Worker void FeatureList::RestoreInstanceForTesting(
291*635a8641SAndroid Build Coastguard Worker     std::unique_ptr<FeatureList> instance) {
292*635a8641SAndroid Build Coastguard Worker   DCHECK(!g_feature_list_instance);
293*635a8641SAndroid Build Coastguard Worker   // Note: Intentional leak of global singleton.
294*635a8641SAndroid Build Coastguard Worker   g_feature_list_instance = instance.release();
295*635a8641SAndroid Build Coastguard Worker }
296*635a8641SAndroid Build Coastguard Worker 
FinalizeInitialization()297*635a8641SAndroid Build Coastguard Worker void FeatureList::FinalizeInitialization() {
298*635a8641SAndroid Build Coastguard Worker   DCHECK(!initialized_);
299*635a8641SAndroid Build Coastguard Worker   initialized_ = true;
300*635a8641SAndroid Build Coastguard Worker }
301*635a8641SAndroid Build Coastguard Worker 
IsFeatureEnabled(const Feature & feature)302*635a8641SAndroid Build Coastguard Worker bool FeatureList::IsFeatureEnabled(const Feature& feature) {
303*635a8641SAndroid Build Coastguard Worker   DCHECK(initialized_);
304*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
305*635a8641SAndroid Build Coastguard Worker   DCHECK(CheckFeatureIdentity(feature)) << feature.name;
306*635a8641SAndroid Build Coastguard Worker 
307*635a8641SAndroid Build Coastguard Worker   auto it = overrides_.find(feature.name);
308*635a8641SAndroid Build Coastguard Worker   if (it != overrides_.end()) {
309*635a8641SAndroid Build Coastguard Worker     const OverrideEntry& entry = it->second;
310*635a8641SAndroid Build Coastguard Worker 
311*635a8641SAndroid Build Coastguard Worker     // Activate the corresponding field trial, if necessary.
312*635a8641SAndroid Build Coastguard Worker     if (entry.field_trial)
313*635a8641SAndroid Build Coastguard Worker       entry.field_trial->group();
314*635a8641SAndroid Build Coastguard Worker 
315*635a8641SAndroid Build Coastguard Worker     // TODO(asvitkine) Expand this section as more support is added.
316*635a8641SAndroid Build Coastguard Worker 
317*635a8641SAndroid Build Coastguard Worker     // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below.
318*635a8641SAndroid Build Coastguard Worker     if (entry.overridden_state != OVERRIDE_USE_DEFAULT)
319*635a8641SAndroid Build Coastguard Worker       return entry.overridden_state == OVERRIDE_ENABLE_FEATURE;
320*635a8641SAndroid Build Coastguard Worker   }
321*635a8641SAndroid Build Coastguard Worker   // Otherwise, return the default state.
322*635a8641SAndroid Build Coastguard Worker   return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
323*635a8641SAndroid Build Coastguard Worker }
324*635a8641SAndroid Build Coastguard Worker 
GetAssociatedFieldTrial(const Feature & feature)325*635a8641SAndroid Build Coastguard Worker FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) {
326*635a8641SAndroid Build Coastguard Worker   DCHECK(initialized_);
327*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
328*635a8641SAndroid Build Coastguard Worker   DCHECK(CheckFeatureIdentity(feature)) << feature.name;
329*635a8641SAndroid Build Coastguard Worker 
330*635a8641SAndroid Build Coastguard Worker   auto it = overrides_.find(feature.name);
331*635a8641SAndroid Build Coastguard Worker   if (it != overrides_.end()) {
332*635a8641SAndroid Build Coastguard Worker     const OverrideEntry& entry = it->second;
333*635a8641SAndroid Build Coastguard Worker     return entry.field_trial;
334*635a8641SAndroid Build Coastguard Worker   }
335*635a8641SAndroid Build Coastguard Worker 
336*635a8641SAndroid Build Coastguard Worker   return nullptr;
337*635a8641SAndroid Build Coastguard Worker }
338*635a8641SAndroid Build Coastguard Worker 
RegisterOverridesFromCommandLine(const std::string & feature_list,OverrideState overridden_state)339*635a8641SAndroid Build Coastguard Worker void FeatureList::RegisterOverridesFromCommandLine(
340*635a8641SAndroid Build Coastguard Worker     const std::string& feature_list,
341*635a8641SAndroid Build Coastguard Worker     OverrideState overridden_state) {
342*635a8641SAndroid Build Coastguard Worker   for (const auto& value : SplitFeatureListString(feature_list)) {
343*635a8641SAndroid Build Coastguard Worker     StringPiece feature_name = value;
344*635a8641SAndroid Build Coastguard Worker     base::FieldTrial* trial = nullptr;
345*635a8641SAndroid Build Coastguard Worker 
346*635a8641SAndroid Build Coastguard Worker     // The entry may be of the form FeatureName<FieldTrialName - in which case,
347*635a8641SAndroid Build Coastguard Worker     // this splits off the field trial name and associates it with the override.
348*635a8641SAndroid Build Coastguard Worker     std::string::size_type pos = feature_name.find('<');
349*635a8641SAndroid Build Coastguard Worker     if (pos != std::string::npos) {
350*635a8641SAndroid Build Coastguard Worker       feature_name.set(value.data(), pos);
351*635a8641SAndroid Build Coastguard Worker       trial = base::FieldTrialList::Find(value.substr(pos + 1).as_string());
352*635a8641SAndroid Build Coastguard Worker     }
353*635a8641SAndroid Build Coastguard Worker 
354*635a8641SAndroid Build Coastguard Worker     RegisterOverride(feature_name, overridden_state, trial);
355*635a8641SAndroid Build Coastguard Worker   }
356*635a8641SAndroid Build Coastguard Worker }
357*635a8641SAndroid Build Coastguard Worker 
RegisterOverride(StringPiece feature_name,OverrideState overridden_state,FieldTrial * field_trial)358*635a8641SAndroid Build Coastguard Worker void FeatureList::RegisterOverride(StringPiece feature_name,
359*635a8641SAndroid Build Coastguard Worker                                    OverrideState overridden_state,
360*635a8641SAndroid Build Coastguard Worker                                    FieldTrial* field_trial) {
361*635a8641SAndroid Build Coastguard Worker   DCHECK(!initialized_);
362*635a8641SAndroid Build Coastguard Worker   if (field_trial) {
363*635a8641SAndroid Build Coastguard Worker     DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
364*635a8641SAndroid Build Coastguard Worker         << field_trial->trial_name();
365*635a8641SAndroid Build Coastguard Worker   }
366*635a8641SAndroid Build Coastguard Worker   if (feature_name.starts_with("*")) {
367*635a8641SAndroid Build Coastguard Worker     feature_name = feature_name.substr(1);
368*635a8641SAndroid Build Coastguard Worker     overridden_state = OVERRIDE_USE_DEFAULT;
369*635a8641SAndroid Build Coastguard Worker   }
370*635a8641SAndroid Build Coastguard Worker 
371*635a8641SAndroid Build Coastguard Worker   // Note: The semantics of insert() is that it does not overwrite the entry if
372*635a8641SAndroid Build Coastguard Worker   // one already exists for the key. Thus, only the first override for a given
373*635a8641SAndroid Build Coastguard Worker   // feature name takes effect.
374*635a8641SAndroid Build Coastguard Worker   overrides_.insert(std::make_pair(
375*635a8641SAndroid Build Coastguard Worker       feature_name.as_string(), OverrideEntry(overridden_state, field_trial)));
376*635a8641SAndroid Build Coastguard Worker }
377*635a8641SAndroid Build Coastguard Worker 
GetFeatureOverridesImpl(std::string * enable_overrides,std::string * disable_overrides,bool command_line_only)378*635a8641SAndroid Build Coastguard Worker void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides,
379*635a8641SAndroid Build Coastguard Worker                                           std::string* disable_overrides,
380*635a8641SAndroid Build Coastguard Worker                                           bool command_line_only) {
381*635a8641SAndroid Build Coastguard Worker   DCHECK(initialized_);
382*635a8641SAndroid Build Coastguard Worker 
383*635a8641SAndroid Build Coastguard Worker   enable_overrides->clear();
384*635a8641SAndroid Build Coastguard Worker   disable_overrides->clear();
385*635a8641SAndroid Build Coastguard Worker 
386*635a8641SAndroid Build Coastguard Worker   // Note: Since |overrides_| is a std::map, iteration will be in alphabetical
387*635a8641SAndroid Build Coastguard Worker   // order. This is not guaranteed to users of this function, but is useful for
388*635a8641SAndroid Build Coastguard Worker   // tests to assume the order.
389*635a8641SAndroid Build Coastguard Worker   for (const auto& entry : overrides_) {
390*635a8641SAndroid Build Coastguard Worker     if (command_line_only &&
391*635a8641SAndroid Build Coastguard Worker         (entry.second.field_trial != nullptr ||
392*635a8641SAndroid Build Coastguard Worker          entry.second.overridden_state == OVERRIDE_USE_DEFAULT)) {
393*635a8641SAndroid Build Coastguard Worker       continue;
394*635a8641SAndroid Build Coastguard Worker     }
395*635a8641SAndroid Build Coastguard Worker 
396*635a8641SAndroid Build Coastguard Worker     std::string* target_list = nullptr;
397*635a8641SAndroid Build Coastguard Worker     switch (entry.second.overridden_state) {
398*635a8641SAndroid Build Coastguard Worker       case OVERRIDE_USE_DEFAULT:
399*635a8641SAndroid Build Coastguard Worker       case OVERRIDE_ENABLE_FEATURE:
400*635a8641SAndroid Build Coastguard Worker         target_list = enable_overrides;
401*635a8641SAndroid Build Coastguard Worker         break;
402*635a8641SAndroid Build Coastguard Worker       case OVERRIDE_DISABLE_FEATURE:
403*635a8641SAndroid Build Coastguard Worker         target_list = disable_overrides;
404*635a8641SAndroid Build Coastguard Worker         break;
405*635a8641SAndroid Build Coastguard Worker     }
406*635a8641SAndroid Build Coastguard Worker 
407*635a8641SAndroid Build Coastguard Worker     if (!target_list->empty())
408*635a8641SAndroid Build Coastguard Worker       target_list->push_back(',');
409*635a8641SAndroid Build Coastguard Worker     if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT)
410*635a8641SAndroid Build Coastguard Worker       target_list->push_back('*');
411*635a8641SAndroid Build Coastguard Worker     target_list->append(entry.first);
412*635a8641SAndroid Build Coastguard Worker     if (entry.second.field_trial) {
413*635a8641SAndroid Build Coastguard Worker       target_list->push_back('<');
414*635a8641SAndroid Build Coastguard Worker       target_list->append(entry.second.field_trial->trial_name());
415*635a8641SAndroid Build Coastguard Worker     }
416*635a8641SAndroid Build Coastguard Worker   }
417*635a8641SAndroid Build Coastguard Worker }
418*635a8641SAndroid Build Coastguard Worker 
CheckFeatureIdentity(const Feature & feature)419*635a8641SAndroid Build Coastguard Worker bool FeatureList::CheckFeatureIdentity(const Feature& feature) {
420*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(feature_identity_tracker_lock_);
421*635a8641SAndroid Build Coastguard Worker 
422*635a8641SAndroid Build Coastguard Worker   auto it = feature_identity_tracker_.find(feature.name);
423*635a8641SAndroid Build Coastguard Worker   if (it == feature_identity_tracker_.end()) {
424*635a8641SAndroid Build Coastguard Worker     // If it's not tracked yet, register it.
425*635a8641SAndroid Build Coastguard Worker     feature_identity_tracker_[feature.name] = &feature;
426*635a8641SAndroid Build Coastguard Worker     return true;
427*635a8641SAndroid Build Coastguard Worker   }
428*635a8641SAndroid Build Coastguard Worker   // Compare address of |feature| to the existing tracked entry.
429*635a8641SAndroid Build Coastguard Worker   return it->second == &feature;
430*635a8641SAndroid Build Coastguard Worker }
431*635a8641SAndroid Build Coastguard Worker 
OverrideEntry(OverrideState overridden_state,FieldTrial * field_trial)432*635a8641SAndroid Build Coastguard Worker FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
433*635a8641SAndroid Build Coastguard Worker                                           FieldTrial* field_trial)
434*635a8641SAndroid Build Coastguard Worker     : overridden_state(overridden_state),
435*635a8641SAndroid Build Coastguard Worker       field_trial(field_trial),
436*635a8641SAndroid Build Coastguard Worker       overridden_by_field_trial(field_trial != nullptr) {}
437*635a8641SAndroid Build Coastguard Worker 
438*635a8641SAndroid Build Coastguard Worker }  // namespace base
439