145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// Copyright 2015 The Chromium Authors. All rights reserved.
245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// found in the LICENSE file.
445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include "base/feature_list.h"
645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include <stddef.h>
845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include <utility>
1045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include <vector>
1145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
1245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include "base/logging.h"
1336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe#include "base/memory/ptr_util.h"
1445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include "base/metrics/field_trial.h"
1536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe#include "base/pickle.h"
1645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include "base/strings/string_split.h"
1745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko#include "base/strings/string_util.h"
1845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
1945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkonamespace base {
2045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
2145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkonamespace {
2245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
2345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// Pointer to the FeatureList instance singleton that was set via
2445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
2545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// have more control over initialization timing. Leaky.
2645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoFeatureList* g_instance = nullptr;
2745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
280c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez// Tracks whether the FeatureList instance was initialized via an accessor.
290c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavezbool g_initialized_from_accessor = false;
300c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez
3136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe// An allocator entry for a feature in shared memory. The FeatureEntry is
3236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe// followed by a base::Pickle object that contains the feature and trial name.
3336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abestruct FeatureEntry {
3436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // SHA1(FeatureEntry): Increment this if structure changes!
3536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  static constexpr uint32_t kPersistentTypeId = 0x06567CA6 + 1;
3636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
3736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // Expected size for 32/64-bit check.
3836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  static constexpr size_t kExpectedInstanceSize = 8;
3936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
4036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // Specifies whether a feature override enables or disables the feature. Same
4136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // values as the OverrideState enum in feature_list.h
4236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  uint32_t override_state;
4336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
4436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // Size of the pickled structure, NOT the total size of this entry.
4536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  uint32_t pickle_size;
4636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
4736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // Reads the feature and trial name from the pickle. Calling this is only
4836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // valid on an initialized entry that's in shared memory.
4936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  bool GetFeatureAndTrialName(StringPiece* feature_name,
5036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe                              StringPiece* trial_name) const {
5136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    const char* src =
5236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe        reinterpret_cast<const char*>(this) + sizeof(FeatureEntry);
5336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
5436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    Pickle pickle(src, pickle_size);
5536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    PickleIterator pickle_iter(pickle);
5636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
5736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    if (!pickle_iter.ReadStringPiece(feature_name))
5836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe      return false;
5936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
6036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    // Return true because we are not guaranteed to have a trial name anyways.
6136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    auto sink = pickle_iter.ReadStringPiece(trial_name);
6236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    ALLOW_UNUSED_LOCAL(sink);
6336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    return true;
6436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  }
6536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe};
6636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
6745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// Some characters are not allowed to appear in feature names or the associated
6845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// field trial names, as they are used as special characters for command-line
6945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// serialization. This function checks that the strings are ASCII (since they
7045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// are used in command-line API functions that require ASCII) and whether there
7145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// are any reserved characters present, returning true if the string is valid.
7245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// Only called in DCHECKs.
7345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkobool IsValidFeatureOrFieldTrialName(const std::string& name) {
7494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
7545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
7645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
7745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}  // namespace
7845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
790c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector ChavezFeatureList::FeatureList() {}
8045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
8145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoFeatureList::~FeatureList() {}
8245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
8345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::InitializeFromCommandLine(
8445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const std::string& enable_features,
8545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const std::string& disable_features) {
8645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(!initialized_);
8745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
8845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // Process disabled features first, so that disabled ones take precedence over
8945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // enabled ones (since RegisterOverride() uses insert()).
9045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
9145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  RegisterOverridesFromCommandLine(enable_features, OVERRIDE_ENABLE_FEATURE);
9294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
9394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  initialized_from_command_line_ = true;
9445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
9545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
9636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abevoid FeatureList::InitializeFromSharedMemory(
9736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    PersistentMemoryAllocator* allocator) {
9836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  DCHECK(!initialized_);
9936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
10036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  PersistentMemoryAllocator::Iterator iter(allocator);
10136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  const FeatureEntry* entry;
10236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  while ((entry = iter.GetNextOfObject<FeatureEntry>()) != nullptr) {
10336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    OverrideState override_state =
10436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe        static_cast<OverrideState>(entry->override_state);
10536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
10636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    StringPiece feature_name;
10736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    StringPiece trial_name;
10836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name))
10936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe      continue;
11036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
11136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    FieldTrial* trial = FieldTrialList::Find(trial_name.as_string());
11236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    RegisterOverride(feature_name, override_state, trial);
11336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  }
11436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe}
11536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
11645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkobool FeatureList::IsFeatureOverriddenFromCommandLine(
11745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const std::string& feature_name,
11845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    OverrideState state) const {
11945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  auto it = overrides_.find(feature_name);
12045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return it != overrides_.end() && it->second.overridden_state == state &&
12145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko         !it->second.overridden_by_field_trial;
12245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
12345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
12445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::AssociateReportingFieldTrial(
12545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const std::string& feature_name,
12645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    OverrideState for_overridden_state,
12745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    FieldTrial* field_trial) {
12845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(
12945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
13045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
13145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // Only one associated field trial is supported per feature. This is generally
13245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // enforced server-side.
13345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  OverrideEntry* entry = &overrides_.find(feature_name)->second;
13445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (entry->field_trial) {
13545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    NOTREACHED() << "Feature " << feature_name
13645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                 << " already has trial: " << entry->field_trial->trial_name()
13745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                 << ", associating trial: " << field_trial->trial_name();
13845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return;
13945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
14045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
14145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  entry->field_trial = field_trial;
14245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
14345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
14445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
14545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                             OverrideState override_state,
14645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                             FieldTrial* field_trial) {
14745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(field_trial);
14845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(!ContainsKey(overrides_, feature_name) ||
14945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko         !overrides_.find(feature_name)->second.field_trial)
15045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      << "Feature " << feature_name
15145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      << " has conflicting field trial overrides: "
15245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      << overrides_.find(feature_name)->second.field_trial->trial_name()
15345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      << " / " << field_trial->trial_name();
15445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
15545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  RegisterOverride(feature_name, override_state, field_trial);
15645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
15745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
15836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abevoid FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) {
15936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  DCHECK(initialized_);
16036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
16136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  for (const auto& override : overrides_) {
16236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    Pickle pickle;
16336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    pickle.WriteString(override.first);
16436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    if (override.second.field_trial)
16536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe      pickle.WriteString(override.second.field_trial->trial_name());
16636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
16736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    size_t total_size = sizeof(FeatureEntry) + pickle.size();
16836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    FeatureEntry* entry = allocator->New<FeatureEntry>(total_size);
16936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    if (!entry)
17036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe      return;
17136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
17236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    entry->override_state = override.second.overridden_state;
17336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    entry->pickle_size = pickle.size();
17436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
17536040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    char* dst = reinterpret_cast<char*>(entry) + sizeof(FeatureEntry);
17636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    memcpy(dst, pickle.data(), pickle.size());
17736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
17836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    allocator->MakeIterable(entry);
17936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  }
18036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe}
18136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
18245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::GetFeatureOverrides(std::string* enable_overrides,
18345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                      std::string* disable_overrides) {
18445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(initialized_);
18545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
18645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  enable_overrides->clear();
18745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  disable_overrides->clear();
18845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
18994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Note: Since |overrides_| is a std::map, iteration will be in alphabetical
19094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // order. This not guaranteed to users of this function, but is useful for
19194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // tests to assume the order.
19245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  for (const auto& entry : overrides_) {
19345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    std::string* target_list = nullptr;
19445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    switch (entry.second.overridden_state) {
19594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      case OVERRIDE_USE_DEFAULT:
19645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      case OVERRIDE_ENABLE_FEATURE:
19745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko        target_list = enable_overrides;
19845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko        break;
19945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      case OVERRIDE_DISABLE_FEATURE:
20045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko        target_list = disable_overrides;
20145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko        break;
20245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    }
20345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
20445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (!target_list->empty())
20545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      target_list->push_back(',');
20694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT)
20794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      target_list->push_back('*');
20845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    target_list->append(entry.first);
20945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (entry.second.field_trial) {
21045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      target_list->push_back('<');
21145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      target_list->append(entry.second.field_trial->trial_name());
21245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    }
21345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
21445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
21545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
21645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
21745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkobool FeatureList::IsEnabled(const Feature& feature) {
2180c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  if (!g_instance) {
2190c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez    g_initialized_from_accessor = true;
2200c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez    return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
2210c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  }
2220c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  return g_instance->IsFeatureEnabled(feature);
22345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
22445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
22545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
22694ffa55491333f3dcc701befd0d2652922916d99Luis Hector ChavezFieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
22794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  return GetInstance()->GetAssociatedFieldTrial(feature);
22894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez}
22994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
23094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez// static
231319afc59a539d6261307aadbdab4d4ee93eaf1ffJakub Pawlowskistd::vector<base::StringPiece> FeatureList::SplitFeatureListString(
232319afc59a539d6261307aadbdab4d4ee93eaf1ffJakub Pawlowski    base::StringPiece input) {
233319afc59a539d6261307aadbdab4d4ee93eaf1ffJakub Pawlowski  return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
23445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
23545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
23645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
23794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezbool FeatureList::InitializeInstance(const std::string& enable_features,
23894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez                                     const std::string& disable_features) {
23994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // We want to initialize a new instance here to support command-line features
24094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // in testing better. For example, we initialize a dummy instance in
24194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // base/test/test_suite.cc, and override it in content/browser/
24294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // browser_main_loop.cc.
24394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // On the other hand, we want to avoid re-initialization from command line.
24494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // For example, we initialize an instance in chrome/browser/
24594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // chrome_browser_main.cc and do not override it in content/browser/
24694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // browser_main_loop.cc.
2470c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  // If the singleton was previously initialized from within an accessor, we
2480c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  // want to prevent callers from reinitializing the singleton and masking the
2490c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  // accessor call(s) which likely returned incorrect information.
2500c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  CHECK(!g_initialized_from_accessor);
25194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  bool instance_existed_before = false;
25294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (g_instance) {
25394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    if (g_instance->initialized_from_command_line_)
25494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      return false;
25594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
25694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    delete g_instance;
25794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    g_instance = nullptr;
25894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    instance_existed_before = true;
25994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
26094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
26194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
26294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  feature_list->InitializeFromCommandLine(enable_features, disable_features);
26394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  base::FeatureList::SetInstance(std::move(feature_list));
26494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  return !instance_existed_before;
26545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
26645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
26745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
26845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoFeatureList* FeatureList::GetInstance() {
26945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return g_instance;
27045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
27145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
27245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
27394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
27445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(!g_instance);
27545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  instance->FinalizeInitialization();
27645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
27745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // Note: Intentional leak of global singleton.
27845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  g_instance = instance.release();
27945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
28045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
28145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
28236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abestd::unique_ptr<FeatureList> FeatureList::ClearInstanceForTesting() {
28336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  FeatureList* old_instance = g_instance;
28445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  g_instance = nullptr;
2850c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  g_initialized_from_accessor = false;
28636040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  return base::WrapUnique(old_instance);
28736040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe}
28836040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe
28936040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe// static
29036040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abevoid FeatureList::RestoreInstanceForTesting(
29136040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe    std::unique_ptr<FeatureList> instance) {
29236040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  DCHECK(!g_instance);
29336040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  // Note: Intentional leak of global singleton.
29436040ed30c39d2106a2cd5ec033e98b71302a744Hidehiko Abe  g_instance = instance.release();
29545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
29645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
29745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::FinalizeInitialization() {
29845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(!initialized_);
29945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  initialized_ = true;
30045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
30145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
30245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkobool FeatureList::IsFeatureEnabled(const Feature& feature) {
30345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(initialized_);
30445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
30545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(CheckFeatureIdentity(feature)) << feature.name;
30645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
30745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  auto it = overrides_.find(feature.name);
30845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (it != overrides_.end()) {
30945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const OverrideEntry& entry = it->second;
31045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
31145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    // Activate the corresponding field trial, if necessary.
31245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (entry.field_trial)
31345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      entry.field_trial->group();
31445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
31545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    // TODO(asvitkine) Expand this section as more support is added.
31694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
31794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below.
31894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    if (entry.overridden_state != OVERRIDE_USE_DEFAULT)
31994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      return entry.overridden_state == OVERRIDE_ENABLE_FEATURE;
32045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
32145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // Otherwise, return the default state.
32245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
32345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
32445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
32594ffa55491333f3dcc701befd0d2652922916d99Luis Hector ChavezFieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) {
32694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  DCHECK(initialized_);
32794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
32894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  DCHECK(CheckFeatureIdentity(feature)) << feature.name;
32994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
33094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  auto it = overrides_.find(feature.name);
33194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (it != overrides_.end()) {
33294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    const OverrideEntry& entry = it->second;
33394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    return entry.field_trial;
33494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
33594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
33694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  return nullptr;
33794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez}
33894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
33945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::RegisterOverridesFromCommandLine(
34045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const std::string& feature_list,
34145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    OverrideState overridden_state) {
34245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  for (const auto& value : SplitFeatureListString(feature_list)) {
343319afc59a539d6261307aadbdab4d4ee93eaf1ffJakub Pawlowski    StringPiece feature_name = value;
34445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    base::FieldTrial* trial = nullptr;
34545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
34645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    // The entry may be of the form FeatureName<FieldTrialName - in which case,
34745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    // this splits off the field trial name and associates it with the override.
34845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    std::string::size_type pos = feature_name.find('<');
34945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (pos != std::string::npos) {
35045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      feature_name.set(value.data(), pos);
351319afc59a539d6261307aadbdab4d4ee93eaf1ffJakub Pawlowski      trial = base::FieldTrialList::Find(value.substr(pos + 1).as_string());
35245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    }
35345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
35445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    RegisterOverride(feature_name, overridden_state, trial);
35545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
35645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
35745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
35845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid FeatureList::RegisterOverride(StringPiece feature_name,
35945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                   OverrideState overridden_state,
36045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                   FieldTrial* field_trial) {
36145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(!initialized_);
36245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (field_trial) {
36345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
36445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko        << field_trial->trial_name();
36545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
36694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (feature_name.starts_with("*")) {
36794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    feature_name = feature_name.substr(1);
36894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    overridden_state = OVERRIDE_USE_DEFAULT;
36994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
37045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
37145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // Note: The semantics of insert() is that it does not overwrite the entry if
37245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // one already exists for the key. Thus, only the first override for a given
37345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // feature name takes effect.
37445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  overrides_.insert(std::make_pair(
37545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      feature_name.as_string(), OverrideEntry(overridden_state, field_trial)));
37645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
37745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
37845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkobool FeatureList::CheckFeatureIdentity(const Feature& feature) {
37945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  AutoLock auto_lock(feature_identity_tracker_lock_);
38045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
38145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  auto it = feature_identity_tracker_.find(feature.name);
38245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (it == feature_identity_tracker_.end()) {
38345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    // If it's not tracked yet, register it.
38445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    feature_identity_tracker_[feature.name] = &feature;
38545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return true;
38645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
38745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // Compare address of |feature| to the existing tracked entry.
38845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return it->second == &feature;
38945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
39045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
39145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoFeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
39245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                          FieldTrial* field_trial)
39345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    : overridden_state(overridden_state),
39445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      field_trial(field_trial),
39545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      overridden_by_field_trial(field_trial != nullptr) {}
39645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
39745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}  // namespace base
398