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