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