• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/feature_list.h"
6 
7 #include <string>
8 #include <tuple>
9 
10 #include <stddef.h>
11 
12 #include "base/base_switches.h"
13 #include "base/debug/crash_logging.h"
14 #include "base/debug/dump_without_crashing.h"
15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/metrics/field_trial.h"
19 #include "base/metrics/field_trial_param_associator.h"
20 #include "base/metrics/field_trial_params.h"
21 #include "base/metrics/persistent_memory_allocator.h"
22 #include "base/no_destructor.h"
23 #include "base/notreached.h"
24 #include "base/pickle.h"
25 #include "base/rand_util.h"
26 #include "base/strings/string_piece.h"
27 #include "base/strings/string_split.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "build/build_config.h"
31 
32 namespace base {
33 
34 namespace {
35 
36 // Pointer to the FeatureList instance singleton that was set via
37 // FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
38 // have more control over initialization timing. Leaky.
39 FeatureList* g_feature_list_instance = nullptr;
40 
41 // Tracks access to Feature state before FeatureList registration.
42 class EarlyFeatureAccessTracker {
43  public:
GetInstance()44   static EarlyFeatureAccessTracker* GetInstance() {
45     static NoDestructor<EarlyFeatureAccessTracker> instance;
46     return instance.get();
47   }
48 
49   // Invoked when `feature` is accessed before FeatureList registration.
AccessedFeature(const Feature & feature)50   void AccessedFeature(const Feature& feature) {
51     AutoLock lock(lock_);
52     if (fail_instantly_)
53       Fail(&feature);
54     else if (!feature_)
55       feature_ = &feature;
56   }
57 
58   // Asserts that no feature was accessed before FeatureList registration.
AssertNoAccess()59   void AssertNoAccess() {
60     AutoLock lock(lock_);
61     if (feature_)
62       Fail(feature_);
63   }
64 
65   // Makes calls to AccessedFeature() fail instantly.
FailOnFeatureAccessWithoutFeatureList()66   void FailOnFeatureAccessWithoutFeatureList() {
67     AutoLock lock(lock_);
68     if (feature_)
69       Fail(feature_);
70     fail_instantly_ = true;
71   }
72 
73   // Resets the state of this tracker.
Reset()74   void Reset() {
75     AutoLock lock(lock_);
76     feature_ = nullptr;
77     fail_instantly_ = false;
78   }
79 
80  private:
Fail(const Feature * feature)81   void Fail(const Feature* feature) {
82     // TODO(crbug.com/1358639): Enable this check on all platforms.
83 #if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
84 #if !BUILDFLAG(IS_NACL)
85     // Create a crash key with the name of the feature accessed too early, to
86     // facilitate crash triage.
87     SCOPED_CRASH_KEY_STRING256("FeatureList", "feature-accessed-too-early",
88                                feature->name);
89 #endif  // !BUILDFLAG(IS_NACL)
90     // Fail if DCHECKs are enabled.
91     DCHECK(!feature) << "Accessed feature " << feature->name
92                      << " before FeatureList registration.";
93     // TODO(crbug.com/1383852): When we believe that all early accesses have
94     // been fixed, remove this base::debug::DumpWithoutCrashing() and change the
95     // above DCHECK to a CHECK.
96     base::debug::DumpWithoutCrashing();
97 #endif  // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) &&
98         // !BUILDFLAG(IS_CHROMEOS)
99   }
100 
101   friend class NoDestructor<EarlyFeatureAccessTracker>;
102 
103   EarlyFeatureAccessTracker() = default;
104   ~EarlyFeatureAccessTracker() = default;
105 
106   Lock lock_;
107 
108   // First feature to be accessed before FeatureList registration.
109   raw_ptr<const Feature> feature_ GUARDED_BY(lock_) = nullptr;
110 
111   // Whether AccessedFeature() should fail instantly.
112   bool fail_instantly_ GUARDED_BY(lock_) = false;
113 };
114 
115 #if DCHECK_IS_ON()
116 const char* g_reason_overrides_disallowed = nullptr;
117 
DCheckOverridesAllowed()118 void DCheckOverridesAllowed() {
119   const bool feature_overrides_allowed = !g_reason_overrides_disallowed;
120   DCHECK(feature_overrides_allowed) << g_reason_overrides_disallowed;
121 }
122 #else
DCheckOverridesAllowed()123 void DCheckOverridesAllowed() {}
124 #endif
125 
126 // An allocator entry for a feature in shared memory. The FeatureEntry is
127 // followed by a base::Pickle object that contains the feature and trial name.
128 struct FeatureEntry {
129   // SHA1(FeatureEntry): Increment this if structure changes!
130   static constexpr uint32_t kPersistentTypeId = 0x06567CA6 + 2;
131 
132   // Expected size for 32/64-bit check.
133   static constexpr size_t kExpectedInstanceSize = 16;
134 
135   // Specifies whether a feature override enables or disables the feature. Same
136   // values as the OverrideState enum in feature_list.h
137   uint32_t override_state;
138 
139   // On e.g. x86, alignof(uint64_t) is 4.  Ensure consistent size and alignment
140   // of `pickle_size` across platforms.
141   uint32_t padding;
142 
143   // Size of the pickled structure, NOT the total size of this entry.
144   uint64_t pickle_size;
145 
146   // Reads the feature and trial name from the pickle. Calling this is only
147   // valid on an initialized entry that's in shared memory.
GetFeatureAndTrialNamebase::__anon796c87f50111::FeatureEntry148   bool GetFeatureAndTrialName(StringPiece* feature_name,
149                               StringPiece* trial_name) const {
150     const char* src =
151         reinterpret_cast<const char*>(this) + sizeof(FeatureEntry);
152 
153     Pickle pickle(src, checked_cast<size_t>(pickle_size));
154     PickleIterator pickle_iter(pickle);
155 
156     if (!pickle_iter.ReadStringPiece(feature_name))
157       return false;
158 
159     // Return true because we are not guaranteed to have a trial name anyways.
160     std::ignore = pickle_iter.ReadStringPiece(trial_name);
161     return true;
162   }
163 };
164 
165 // Splits |text| into two parts by the |separator| where the first part will be
166 // returned updated in |first| and the second part will be returned as |second|.
167 // This function returns false if there is more than one |separator| in |first|.
168 // If there is no |separator| presented in |first|, this function will not
169 // modify |first| and |second|. It's used for splitting the |enable_features|
170 // flag into feature name, field trial name and feature parameters.
SplitIntoTwo(StringPiece text,StringPiece separator,StringPiece * first,std::string * second)171 bool SplitIntoTwo(StringPiece text,
172                   StringPiece separator,
173                   StringPiece* first,
174                   std::string* second) {
175   std::vector<StringPiece> parts =
176       SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL);
177   if (parts.size() == 2) {
178     *second = std::string(parts[1]);
179   } else if (parts.size() > 2) {
180     DLOG(ERROR) << "Only one '" << separator
181                 << "' is allowed but got: " << *first;
182     return false;
183   }
184   *first = parts[0];
185   return true;
186 }
187 
188 // Checks and parses the |enable_features| flag and sets
189 // |parsed_enable_features| to be a comma-separated list of features,
190 // |force_fieldtrials| to be a comma-separated list of field trials that each
191 // feature want to associate with and |force_fieldtrial_params| to be the field
192 // trial parameters for each field trial.
193 // Returns true if |enable_features| is parsable, otherwise false.
ParseEnableFeatures(const std::string & enable_features,std::string * parsed_enable_features,std::string * force_fieldtrials,std::string * force_fieldtrial_params)194 bool ParseEnableFeatures(const std::string& enable_features,
195                          std::string* parsed_enable_features,
196                          std::string* force_fieldtrials,
197                          std::string* force_fieldtrial_params) {
198   std::vector<std::string> enable_features_list;
199   std::vector<std::string> force_fieldtrials_list;
200   std::vector<std::string> force_fieldtrial_params_list;
201   for (const auto& enable_feature :
202        FeatureList::SplitFeatureListString(enable_features)) {
203     std::string feature_name;
204     std::string study;
205     std::string group;
206     std::string feature_params;
207     if (!FeatureList::ParseEnableFeatureString(
208             enable_feature, &feature_name, &study, &group, &feature_params)) {
209       return false;
210     }
211 
212     // If feature params were set but group and study weren't, associate the
213     // feature and its feature params to a synthetic field trial as the
214     // feature params only make sense when it's combined with a field trial.
215     if (!feature_params.empty()) {
216       force_fieldtrials_list.push_back(study + "/" + group);
217       force_fieldtrial_params_list.push_back(study + "." + group + ":" +
218                                              feature_params);
219     }
220     enable_features_list.push_back(
221         study.empty() ? feature_name : (feature_name + "<" + study));
222   }
223 
224   *parsed_enable_features = JoinString(enable_features_list, ",");
225   // Field trial separator is currently a slash. See
226   // |kPersistentStringSeparator| in base/metrics/field_trial.cc.
227   *force_fieldtrials = JoinString(force_fieldtrials_list, "/");
228   *force_fieldtrial_params = JoinString(force_fieldtrial_params_list, ",");
229   return true;
230 }
231 
UnpackFeatureCache(uint32_t packed_cache_value)232 std::pair<FeatureList::OverrideState, uint16_t> UnpackFeatureCache(
233     uint32_t packed_cache_value) {
234   return std::make_pair(
235       static_cast<FeatureList::OverrideState>(packed_cache_value >> 24),
236       packed_cache_value & 0xFFFF);
237 }
238 
PackFeatureCache(FeatureList::OverrideState override_state,uint32_t caching_context)239 uint32_t PackFeatureCache(FeatureList::OverrideState override_state,
240                           uint32_t caching_context) {
241   return (static_cast<uint32_t>(override_state) << 24) |
242          (caching_context & 0xFFFF);
243 }
244 
245 }  // namespace
246 
247 #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
248 BASE_FEATURE(kDCheckIsFatalFeature,
249              "DcheckIsFatal",
250              FEATURE_DISABLED_BY_DEFAULT);
251 #endif  // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
252 
253 FeatureList::FeatureList() = default;
254 
255 FeatureList::~FeatureList() = default;
256 
ScopedDisallowOverrides(const char * reason)257 FeatureList::ScopedDisallowOverrides::ScopedDisallowOverrides(
258     const char* reason)
259 #if DCHECK_IS_ON()
260     : previous_reason_(g_reason_overrides_disallowed) {
261   g_reason_overrides_disallowed = reason;
262 }
263 #else
264 {
265 }
266 #endif
267 
~ScopedDisallowOverrides()268 FeatureList::ScopedDisallowOverrides::~ScopedDisallowOverrides() {
269 #if DCHECK_IS_ON()
270   g_reason_overrides_disallowed = previous_reason_;
271 #endif
272 }
273 
InitializeFromCommandLine(const std::string & enable_features,const std::string & disable_features)274 void FeatureList::InitializeFromCommandLine(
275     const std::string& enable_features,
276     const std::string& disable_features) {
277   DCHECK(!initialized_);
278 
279   std::string parsed_enable_features;
280   std::string force_fieldtrials;
281   std::string force_fieldtrial_params;
282   bool parse_enable_features_result =
283       ParseEnableFeatures(enable_features, &parsed_enable_features,
284                           &force_fieldtrials, &force_fieldtrial_params);
285   DCHECK(parse_enable_features_result) << StringPrintf(
286       "The --%s list is unparsable or invalid, please check the format.",
287       ::switches::kEnableFeatures);
288 
289   // Only create field trials when field_trial_list is available. Some tests
290   // don't have field trial list available.
291   if (FieldTrialList::GetInstance()) {
292     bool associate_params_result = AssociateFieldTrialParamsFromString(
293         force_fieldtrial_params, &UnescapeValue);
294     DCHECK(associate_params_result) << StringPrintf(
295         "The field trial parameters part of the --%s list is invalid. Make "
296         "sure "
297         "you %%-encode the following characters in param values: %%:/.,",
298         ::switches::kEnableFeatures);
299 
300     bool create_trials_result =
301         FieldTrialList::CreateTrialsFromString(force_fieldtrials);
302     DCHECK(create_trials_result)
303         << StringPrintf("Invalid field trials are specified in --%s.",
304                         ::switches::kEnableFeatures);
305   }
306 
307   // Process disabled features first, so that disabled ones take precedence over
308   // enabled ones (since RegisterOverride() uses insert()).
309   RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
310   RegisterOverridesFromCommandLine(parsed_enable_features,
311                                    OVERRIDE_ENABLE_FEATURE);
312 
313   initialized_from_command_line_ = true;
314 }
315 
InitializeFromSharedMemory(PersistentMemoryAllocator * allocator)316 void FeatureList::InitializeFromSharedMemory(
317     PersistentMemoryAllocator* allocator) {
318   DCHECK(!initialized_);
319 
320   PersistentMemoryAllocator::Iterator iter(allocator);
321   const FeatureEntry* entry;
322   while ((entry = iter.GetNextOfObject<FeatureEntry>()) != nullptr) {
323     OverrideState override_state =
324         static_cast<OverrideState>(entry->override_state);
325 
326     StringPiece feature_name;
327     StringPiece trial_name;
328     if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name))
329       continue;
330 
331     FieldTrial* trial = FieldTrialList::Find(trial_name);
332     RegisterOverride(feature_name, override_state, trial);
333   }
334 }
335 
IsFeatureOverridden(const std::string & feature_name) const336 bool FeatureList::IsFeatureOverridden(const std::string& feature_name) const {
337   return overrides_.count(feature_name);
338 }
339 
IsFeatureOverriddenFromCommandLine(const std::string & feature_name) const340 bool FeatureList::IsFeatureOverriddenFromCommandLine(
341     const std::string& feature_name) const {
342   auto it = overrides_.find(feature_name);
343   return it != overrides_.end() && !it->second.overridden_by_field_trial;
344 }
345 
IsFeatureOverriddenFromCommandLine(const std::string & feature_name,OverrideState state) const346 bool FeatureList::IsFeatureOverriddenFromCommandLine(
347     const std::string& feature_name,
348     OverrideState state) const {
349   auto it = overrides_.find(feature_name);
350   return it != overrides_.end() && !it->second.overridden_by_field_trial &&
351          it->second.overridden_state == state;
352 }
353 
AssociateReportingFieldTrial(const std::string & feature_name,OverrideState for_overridden_state,FieldTrial * field_trial)354 void FeatureList::AssociateReportingFieldTrial(
355     const std::string& feature_name,
356     OverrideState for_overridden_state,
357     FieldTrial* field_trial) {
358   DCHECK(
359       IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
360 
361   // Only one associated field trial is supported per feature. This is generally
362   // enforced server-side.
363   OverrideEntry* entry = &overrides_.find(feature_name)->second;
364   if (entry->field_trial) {
365     NOTREACHED() << "Feature " << feature_name
366                  << " already has trial: " << entry->field_trial->trial_name()
367                  << ", associating trial: " << field_trial->trial_name();
368     return;
369   }
370 
371   entry->field_trial = field_trial;
372 }
373 
RegisterFieldTrialOverride(const std::string & feature_name,OverrideState override_state,FieldTrial * field_trial)374 void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
375                                              OverrideState override_state,
376                                              FieldTrial* field_trial) {
377   DCHECK(field_trial);
378   DCHECK(!HasAssociatedFieldTrialByFeatureName(feature_name))
379       << "Feature " << feature_name << " is overriden multiple times in these "
380       << "trials: "
381       << overrides_.find(feature_name)->second.field_trial->trial_name()
382       << " and " << field_trial->trial_name() << ". "
383       << "Check the trial (study) in (1) the server config, "
384       << "(2) fieldtrial_testing_config.json, (3) about_flags.cc, and "
385       << "(4) client-side field trials.";
386 
387   RegisterOverride(feature_name, override_state, field_trial);
388 }
389 
RegisterExtraFeatureOverrides(const std::vector<FeatureOverrideInfo> & extra_overrides)390 void FeatureList::RegisterExtraFeatureOverrides(
391     const std::vector<FeatureOverrideInfo>& extra_overrides) {
392   for (const FeatureOverrideInfo& override_info : extra_overrides) {
393     RegisterOverride(override_info.first.get().name, override_info.second,
394                      /* field_trial = */ nullptr);
395   }
396 }
397 
AddFeaturesToAllocator(PersistentMemoryAllocator * allocator)398 void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) {
399   DCHECK(initialized_);
400 
401   for (const auto& override : overrides_) {
402     Pickle pickle;
403     pickle.WriteString(override.first);
404     if (override.second.field_trial)
405       pickle.WriteString(override.second.field_trial->trial_name());
406 
407     size_t total_size = sizeof(FeatureEntry) + pickle.size();
408     FeatureEntry* entry = allocator->New<FeatureEntry>(total_size);
409     if (!entry)
410       return;
411 
412     entry->override_state = override.second.overridden_state;
413     entry->pickle_size = pickle.size();
414 
415     char* dst = reinterpret_cast<char*>(entry) + sizeof(FeatureEntry);
416     memcpy(dst, pickle.data(), pickle.size());
417 
418     allocator->MakeIterable(entry);
419   }
420 }
421 
GetFeatureOverrides(std::string * enable_overrides,std::string * disable_overrides,bool include_group_name) const422 void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
423                                       std::string* disable_overrides,
424                                       bool include_group_name) const {
425   GetFeatureOverridesImpl(enable_overrides, disable_overrides, false,
426                           include_group_name);
427 }
428 
GetCommandLineFeatureOverrides(std::string * enable_overrides,std::string * disable_overrides) const429 void FeatureList::GetCommandLineFeatureOverrides(
430     std::string* enable_overrides,
431     std::string* disable_overrides) const {
432   GetFeatureOverridesImpl(enable_overrides, disable_overrides, true);
433 }
434 
435 // static
IsEnabled(const Feature & feature)436 bool FeatureList::IsEnabled(const Feature& feature) {
437   if (!g_feature_list_instance) {
438     EarlyFeatureAccessTracker::GetInstance()->AccessedFeature(feature);
439     return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
440   }
441   return g_feature_list_instance->IsFeatureEnabled(feature);
442 }
443 
444 // static
IsValidFeatureOrFieldTrialName(StringPiece name)445 bool FeatureList::IsValidFeatureOrFieldTrialName(StringPiece name) {
446   return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
447 }
448 
449 // static
GetStateIfOverridden(const Feature & feature)450 absl::optional<bool> FeatureList::GetStateIfOverridden(const Feature& feature) {
451   if (!g_feature_list_instance) {
452     EarlyFeatureAccessTracker::GetInstance()->AccessedFeature(feature);
453     // If there is no feature list, there can be no overrides.
454     return absl::nullopt;
455   }
456   return g_feature_list_instance->IsFeatureEnabledIfOverridden(feature);
457 }
458 
459 // static
GetFieldTrial(const Feature & feature)460 FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
461   if (!g_feature_list_instance) {
462     EarlyFeatureAccessTracker::GetInstance()->AccessedFeature(feature);
463     return nullptr;
464   }
465   return g_feature_list_instance->GetAssociatedFieldTrial(feature);
466 }
467 
468 // static
SplitFeatureListString(StringPiece input)469 std::vector<StringPiece> FeatureList::SplitFeatureListString(
470     StringPiece input) {
471   return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
472 }
473 
474 // static
ParseEnableFeatureString(StringPiece enable_feature,std::string * feature_name,std::string * study_name,std::string * group_name,std::string * params)475 bool FeatureList::ParseEnableFeatureString(StringPiece enable_feature,
476                                            std::string* feature_name,
477                                            std::string* study_name,
478                                            std::string* group_name,
479                                            std::string* params) {
480   StringPiece first;
481   // First, check whether ":" is present. If true, feature parameters were
482   // set for this feature.
483   std::string feature_params;
484   if (!SplitIntoTwo(enable_feature, ":", &first, &feature_params))
485     return false;
486   // Then, check whether "." is present. If true, a group was specified for
487   // this feature.
488   std::string group;
489   if (!SplitIntoTwo(first, ".", &first, &group))
490     return false;
491   // Finally, check whether "<" is present. If true, a study was specified for
492   // this feature.
493   std::string study;
494   if (!SplitIntoTwo(first, "<", &first, &study))
495     return false;
496 
497   std::string enable_feature_name(first);
498   // If feature params were set but group and study weren't, associate the
499   // feature and its feature params to a synthetic field trial as the
500   // feature params only make sense when it's combined with a field trial.
501   if (!feature_params.empty()) {
502     study = study.empty() ? "Study" + enable_feature_name : study;
503     group = group.empty() ? "Group" + enable_feature_name : group;
504   }
505 
506   feature_name->swap(enable_feature_name);
507   study_name->swap(study);
508   group_name->swap(group);
509   params->swap(feature_params);
510   return true;
511 }
512 
513 // static
InitializeInstance(const std::string & enable_features,const std::string & disable_features)514 bool FeatureList::InitializeInstance(const std::string& enable_features,
515                                      const std::string& disable_features) {
516   return InitializeInstance(enable_features, disable_features,
517                             std::vector<FeatureOverrideInfo>());
518 }
519 
520 // static
InitializeInstance(const std::string & enable_features,const std::string & disable_features,const std::vector<FeatureOverrideInfo> & extra_overrides)521 bool FeatureList::InitializeInstance(
522     const std::string& enable_features,
523     const std::string& disable_features,
524     const std::vector<FeatureOverrideInfo>& extra_overrides) {
525   // We want to initialize a new instance here to support command-line features
526   // in testing better. For example, we initialize a dummy instance in
527   // base/test/test_suite.cc, and override it in content/browser/
528   // browser_main_loop.cc.
529   // On the other hand, we want to avoid re-initialization from command line.
530   // For example, we initialize an instance in chrome/browser/
531   // chrome_browser_main.cc and do not override it in content/browser/
532   // browser_main_loop.cc.
533   // If the singleton was previously initialized from within an accessor, we
534   // want to prevent callers from reinitializing the singleton and masking the
535   // accessor call(s) which likely returned incorrect information.
536   EarlyFeatureAccessTracker::GetInstance()->AssertNoAccess();
537   bool instance_existed_before = false;
538   if (g_feature_list_instance) {
539     if (g_feature_list_instance->initialized_from_command_line_)
540       return false;
541 
542     delete g_feature_list_instance;
543     g_feature_list_instance = nullptr;
544     instance_existed_before = true;
545   }
546 
547   std::unique_ptr<FeatureList> feature_list(new FeatureList);
548   feature_list->InitializeFromCommandLine(enable_features, disable_features);
549   feature_list->RegisterExtraFeatureOverrides(extra_overrides);
550   FeatureList::SetInstance(std::move(feature_list));
551   return !instance_existed_before;
552 }
553 
554 // static
GetInstance()555 FeatureList* FeatureList::GetInstance() {
556   return g_feature_list_instance;
557 }
558 
559 // static
SetInstance(std::unique_ptr<FeatureList> instance)560 void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
561   DCHECK(!g_feature_list_instance);
562   instance->FinalizeInitialization();
563 
564   // Note: Intentional leak of global singleton.
565   g_feature_list_instance = instance.release();
566 
567   EarlyFeatureAccessTracker::GetInstance()->AssertNoAccess();
568 
569 #if !BUILDFLAG(IS_NACL)
570   // Configured first because it takes precedence over the getrandom() trial.
571   internal::ConfigureBoringSSLBackedRandBytesFieldTrial();
572 #endif
573 
574 #if BUILDFLAG(IS_ANDROID)
575   internal::ConfigureRandBytesFieldTrial();
576 #endif
577 
578 #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
579   // Update the behaviour of LOGGING_DCHECK to match the Feature configuration.
580   // DCHECK is also forced to be FATAL if we are running a death-test.
581   // TODO(crbug.com/1057995#c11): --gtest_internal_run_death_test doesn't
582   // currently run through this codepath, mitigated in
583   // base::TestSuite::Initialize() for now.
584   // TODO(asvitkine): If we find other use-cases that need integrating here
585   // then define a proper API/hook for the purpose.
586   if (FeatureList::IsEnabled(kDCheckIsFatalFeature) ||
587       CommandLine::ForCurrentProcess()->HasSwitch(
588           "gtest_internal_run_death_test")) {
589     logging::LOGGING_DCHECK = logging::LOG_FATAL;
590   } else {
591     logging::LOGGING_DCHECK = logging::LOG_INFO;
592   }
593 #endif  // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
594 }
595 
596 // static
ClearInstanceForTesting()597 std::unique_ptr<FeatureList> FeatureList::ClearInstanceForTesting() {
598   FeatureList* old_instance = g_feature_list_instance;
599   g_feature_list_instance = nullptr;
600   EarlyFeatureAccessTracker::GetInstance()->Reset();
601   return WrapUnique(old_instance);
602 }
603 
604 // static
RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance)605 void FeatureList::RestoreInstanceForTesting(
606     std::unique_ptr<FeatureList> instance) {
607   DCHECK(!g_feature_list_instance);
608   // Note: Intentional leak of global singleton.
609   g_feature_list_instance = instance.release();
610 }
611 
612 // static
FailOnFeatureAccessWithoutFeatureList()613 void FeatureList::FailOnFeatureAccessWithoutFeatureList() {
614   EarlyFeatureAccessTracker::GetInstance()
615       ->FailOnFeatureAccessWithoutFeatureList();
616 }
617 
SetCachingContextForTesting(uint16_t caching_context)618 void FeatureList::SetCachingContextForTesting(uint16_t caching_context) {
619   caching_context_ = caching_context;
620 }
621 
FinalizeInitialization()622 void FeatureList::FinalizeInitialization() {
623   DCHECK(!initialized_);
624   // Store the field trial list pointer for DCHECKing.
625   field_trial_list_ = FieldTrialList::GetInstance();
626   initialized_ = true;
627 }
628 
IsFeatureEnabled(const Feature & feature) const629 bool FeatureList::IsFeatureEnabled(const Feature& feature) const {
630   OverrideState overridden_state = GetOverrideState(feature);
631 
632   // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below.
633   if (overridden_state != OVERRIDE_USE_DEFAULT)
634     return overridden_state == OVERRIDE_ENABLE_FEATURE;
635 
636   return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
637 }
638 
IsFeatureEnabledIfOverridden(const Feature & feature) const639 absl::optional<bool> FeatureList::IsFeatureEnabledIfOverridden(
640     const Feature& feature) const {
641   OverrideState overridden_state = GetOverrideState(feature);
642 
643   // If marked as OVERRIDE_USE_DEFAULT, fall through to returning empty.
644   if (overridden_state != OVERRIDE_USE_DEFAULT)
645     return overridden_state == OVERRIDE_ENABLE_FEATURE;
646 
647   return absl::nullopt;
648 }
649 
GetOverrideState(const Feature & feature) const650 FeatureList::OverrideState FeatureList::GetOverrideState(
651     const Feature& feature) const {
652   DCHECK(initialized_);
653   DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
654   DCHECK(CheckFeatureIdentity(feature))
655       << feature.name
656       << " has multiple definitions. Either it is defined more than once in "
657          "code or (for component builds) the code is built into multiple "
658          "components (shared libraries) without a corresponding export "
659          "statement";
660 
661   uint32_t current_cache_value =
662       feature.cached_value.load(std::memory_order_relaxed);
663 
664   auto unpacked = UnpackFeatureCache(current_cache_value);
665 
666   if (unpacked.second == caching_context_)
667     return unpacked.first;
668 
669   OverrideState state = GetOverrideStateByFeatureName(feature.name);
670   uint32_t new_cache_value = PackFeatureCache(state, caching_context_);
671 
672   // Update the cache with the new value.
673   // In non-test code, this value can be in one of 2 states: either it's unset,
674   // or another thread has updated it to the same value we're about to write.
675   // Because of this, a plain `store` yields the correct result in all cases.
676   // In test code, it's possible for a different thread to have installed a new
677   // `ScopedFeatureList` and written a value that's different than the one we're
678   // about to write, although that would be a thread safety violation already
679   // and such tests should be fixed.
680   feature.cached_value.store(new_cache_value, std::memory_order_relaxed);
681 
682   return state;
683 }
684 
GetOverrideStateByFeatureName(StringPiece feature_name) const685 FeatureList::OverrideState FeatureList::GetOverrideStateByFeatureName(
686     StringPiece feature_name) const {
687   DCHECK(initialized_);
688   DCHECK(IsValidFeatureOrFieldTrialName(feature_name)) << feature_name;
689 
690   auto it = overrides_.find(feature_name);
691   if (it != overrides_.end()) {
692     const OverrideEntry& entry = it->second;
693 
694     // Activate the corresponding field trial, if necessary.
695     if (entry.field_trial)
696       entry.field_trial->Activate();
697 
698     // TODO(asvitkine) Expand this section as more support is added.
699 
700     return entry.overridden_state;
701   }
702   // Otherwise, report that we want to use the default state.
703   return OVERRIDE_USE_DEFAULT;
704 }
705 
GetAssociatedFieldTrial(const Feature & feature) const706 FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) const {
707   DCHECK(initialized_);
708   DCHECK(CheckFeatureIdentity(feature)) << feature.name;
709 
710   return GetAssociatedFieldTrialByFeatureName(feature.name);
711 }
712 
713 const base::FeatureList::OverrideEntry*
GetOverrideEntryByFeatureName(StringPiece name) const714 FeatureList::GetOverrideEntryByFeatureName(StringPiece name) const {
715   DCHECK(initialized_);
716   DCHECK(IsValidFeatureOrFieldTrialName(name)) << name;
717 
718   auto it = overrides_.find(name);
719   if (it != overrides_.end()) {
720     const OverrideEntry& entry = it->second;
721     return &entry;
722   }
723   return nullptr;
724 }
725 
GetAssociatedFieldTrialByFeatureName(StringPiece name) const726 FieldTrial* FeatureList::GetAssociatedFieldTrialByFeatureName(
727     StringPiece name) const {
728   DCHECK(initialized_);
729 
730   const base::FeatureList::OverrideEntry* entry =
731       GetOverrideEntryByFeatureName(name);
732   if (entry) {
733     return entry->field_trial;
734   }
735   return nullptr;
736 }
737 
HasAssociatedFieldTrialByFeatureName(StringPiece name) const738 bool FeatureList::HasAssociatedFieldTrialByFeatureName(StringPiece name) const {
739   DCHECK(!initialized_);
740   auto entry = overrides_.find(name);
741   return entry != overrides_.end() && entry->second.field_trial != nullptr;
742 }
743 
GetEnabledFieldTrialByFeatureName(StringPiece name) const744 FieldTrial* FeatureList::GetEnabledFieldTrialByFeatureName(
745     StringPiece name) const {
746   DCHECK(initialized_);
747 
748   const base::FeatureList::OverrideEntry* entry =
749       GetOverrideEntryByFeatureName(name);
750   if (entry &&
751       entry->overridden_state == base::FeatureList::OVERRIDE_ENABLE_FEATURE) {
752     return entry->field_trial;
753   }
754   return nullptr;
755 }
756 
ConstructAccessor()757 std::unique_ptr<FeatureList::Accessor> FeatureList::ConstructAccessor() {
758   if (initialized_) {
759     // This function shouldn't be called after initialization.
760     NOTREACHED();
761     return nullptr;
762   }
763   // Use new and WrapUnique because we want to restrict access to the Accessor's
764   // constructor.
765   return base::WrapUnique(new Accessor(this));
766 }
767 
RegisterOverridesFromCommandLine(const std::string & feature_list,OverrideState overridden_state)768 void FeatureList::RegisterOverridesFromCommandLine(
769     const std::string& feature_list,
770     OverrideState overridden_state) {
771   for (const auto& value : SplitFeatureListString(feature_list)) {
772     StringPiece feature_name = value;
773     FieldTrial* trial = nullptr;
774 
775     // The entry may be of the form FeatureName<FieldTrialName - in which case,
776     // this splits off the field trial name and associates it with the override.
777     std::string::size_type pos = feature_name.find('<');
778     if (pos != std::string::npos) {
779       feature_name = StringPiece(value.data(), pos);
780       trial = FieldTrialList::Find(value.substr(pos + 1));
781 #if !BUILDFLAG(IS_NACL)
782       // If the below DCHECK fires, it means a non-existent trial name was
783       // specified via the "Feature<Trial" command-line syntax.
784       DCHECK(trial) << "trial='" << value.substr(pos + 1) << "' does not exist";
785 #endif  // !BUILDFLAG(IS_NACL)
786     }
787 
788     RegisterOverride(feature_name, overridden_state, trial);
789   }
790 }
791 
RegisterOverride(StringPiece feature_name,OverrideState overridden_state,FieldTrial * field_trial)792 void FeatureList::RegisterOverride(StringPiece feature_name,
793                                    OverrideState overridden_state,
794                                    FieldTrial* field_trial) {
795   DCHECK(!initialized_);
796   DCheckOverridesAllowed();
797   if (field_trial) {
798     DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
799         << field_trial->trial_name();
800   }
801   if (StartsWith(feature_name, "*")) {
802     feature_name = feature_name.substr(1);
803     overridden_state = OVERRIDE_USE_DEFAULT;
804   }
805 
806   // Note: The semantics of emplace() is that it does not overwrite the entry if
807   // one already exists for the key. Thus, only the first override for a given
808   // feature name takes effect.
809   overrides_.emplace(std::string(feature_name),
810                      OverrideEntry(overridden_state, field_trial));
811 }
812 
GetFeatureOverridesImpl(std::string * enable_overrides,std::string * disable_overrides,bool command_line_only,bool include_group_name) const813 void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides,
814                                           std::string* disable_overrides,
815                                           bool command_line_only,
816                                           bool include_group_name) const {
817   DCHECK(initialized_);
818 
819   // Check that the FieldTrialList this is associated with, if any, is the
820   // active one. If not, it likely indicates that this FeatureList has override
821   // entries from a freed FieldTrial, which may be caused by an incorrect test
822   // set up.
823   if (field_trial_list_)
824     DCHECK_EQ(field_trial_list_, FieldTrialList::GetInstance());
825 
826   enable_overrides->clear();
827   disable_overrides->clear();
828 
829   // Note: Since |overrides_| is a std::map, iteration will be in alphabetical
830   // order. This is not guaranteed to users of this function, but is useful for
831   // tests to assume the order.
832   for (const auto& entry : overrides_) {
833     if (command_line_only &&
834         (entry.second.field_trial != nullptr ||
835          entry.second.overridden_state == OVERRIDE_USE_DEFAULT)) {
836       continue;
837     }
838 
839     std::string* target_list = nullptr;
840     switch (entry.second.overridden_state) {
841       case OVERRIDE_USE_DEFAULT:
842       case OVERRIDE_ENABLE_FEATURE:
843         target_list = enable_overrides;
844         break;
845       case OVERRIDE_DISABLE_FEATURE:
846         target_list = disable_overrides;
847         break;
848     }
849 
850     if (!target_list->empty())
851       target_list->push_back(',');
852     if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT)
853       target_list->push_back('*');
854     target_list->append(entry.first);
855     if (entry.second.field_trial) {
856       auto* const field_trial = entry.second.field_trial.get();
857       target_list->push_back('<');
858       target_list->append(field_trial->trial_name());
859       if (include_group_name) {
860         target_list->push_back('.');
861         target_list->append(field_trial->GetGroupNameWithoutActivation());
862       }
863     }
864   }
865 }
866 
CheckFeatureIdentity(const Feature & feature) const867 bool FeatureList::CheckFeatureIdentity(const Feature& feature) const {
868   AutoLock auto_lock(feature_identity_tracker_lock_);
869 
870   auto it = feature_identity_tracker_.find(feature.name);
871   if (it == feature_identity_tracker_.end()) {
872     // If it's not tracked yet, register it.
873     feature_identity_tracker_[feature.name] = &feature;
874     return true;
875   }
876   // Compare address of |feature| to the existing tracked entry.
877   return it->second == &feature;
878 }
879 
OverrideEntry(OverrideState overridden_state,FieldTrial * field_trial)880 FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
881                                           FieldTrial* field_trial)
882     : overridden_state(overridden_state),
883       field_trial(field_trial),
884       overridden_by_field_trial(field_trial != nullptr) {}
885 
Accessor(FeatureList * feature_list)886 FeatureList::Accessor::Accessor(FeatureList* feature_list)
887     : feature_list_(feature_list) {}
888 
GetOverrideStateByFeatureName(StringPiece feature_name)889 FeatureList::OverrideState FeatureList::Accessor::GetOverrideStateByFeatureName(
890     StringPiece feature_name) {
891   return feature_list_->GetOverrideStateByFeatureName(feature_name);
892 }
893 
GetParamsByFeatureName(StringPiece feature_name,std::map<std::string,std::string> * params)894 bool FeatureList::Accessor::GetParamsByFeatureName(
895     StringPiece feature_name,
896     std::map<std::string, std::string>* params) {
897   base::FieldTrial* trial =
898       feature_list_->GetAssociatedFieldTrialByFeatureName(feature_name);
899   return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial,
900                                                                        params);
901 }
902 
903 }  // namespace base
904