feature_list.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/feature_list.h"
  5. #include <string>
  6. #include <tuple>
  7. #include <stddef.h>
  8. #include "base/base_paths.h"
  9. #include "base/base_switches.h"
  10. #include "base/containers/contains.h"
  11. #include "base/debug/alias.h"
  12. #include "base/debug/stack_trace.h"
  13. #include "base/logging.h"
  14. #include "base/memory/ptr_util.h"
  15. #include "base/metrics/field_trial.h"
  16. #include "base/metrics/field_trial_param_associator.h"
  17. #include "base/metrics/field_trial_params.h"
  18. #include "base/metrics/persistent_memory_allocator.h"
  19. #include "base/notreached.h"
  20. #include "base/path_service.h"
  21. #include "base/pickle.h"
  22. #include "base/rand_util.h"
  23. #include "base/strings/string_piece.h"
  24. #include "base/strings/string_split.h"
  25. #include "base/strings/string_util.h"
  26. #include "base/strings/stringprintf.h"
  27. #include "base/task/sequence_manager/work_queue.h"
  28. #include "build/build_config.h"
  29. namespace base {
  30. namespace {
  31. // Pointer to the FeatureList instance singleton that was set via
  32. // FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
  33. // have more control over initialization timing. Leaky.
  34. FeatureList* g_feature_list_instance = nullptr;
  35. // Tracks whether the FeatureList instance was initialized via an accessor, and
  36. // which Feature that accessor was for, if so.
  37. const Feature* g_initialized_from_accessor = nullptr;
  38. #if DCHECK_IS_ON()
  39. // Tracks whether the use of base::Feature is allowed for this module.
  40. // See ForbidUseForCurrentModule().
  41. bool g_use_allowed = true;
  42. const char* g_reason_overrides_disallowed = nullptr;
  43. void DCheckOverridesAllowed() {
  44. const bool feature_overrides_allowed = !g_reason_overrides_disallowed;
  45. DCHECK(feature_overrides_allowed) << g_reason_overrides_disallowed;
  46. }
  47. #else
  48. void DCheckOverridesAllowed() {}
  49. #endif
  50. // An allocator entry for a feature in shared memory. The FeatureEntry is
  51. // followed by a base::Pickle object that contains the feature and trial name.
  52. struct FeatureEntry {
  53. // SHA1(FeatureEntry): Increment this if structure changes!
  54. static constexpr uint32_t kPersistentTypeId = 0x06567CA6 + 2;
  55. // Expected size for 32/64-bit check.
  56. static constexpr size_t kExpectedInstanceSize = 16;
  57. // Specifies whether a feature override enables or disables the feature. Same
  58. // values as the OverrideState enum in feature_list.h
  59. uint32_t override_state;
  60. // On e.g. x86, alignof(uint64_t) is 4. Ensure consistent size and alignment
  61. // of `pickle_size` across platforms.
  62. uint32_t padding;
  63. // Size of the pickled structure, NOT the total size of this entry.
  64. uint64_t pickle_size;
  65. // Reads the feature and trial name from the pickle. Calling this is only
  66. // valid on an initialized entry that's in shared memory.
  67. bool GetFeatureAndTrialName(StringPiece* feature_name,
  68. StringPiece* trial_name) const {
  69. const char* src =
  70. reinterpret_cast<const char*>(this) + sizeof(FeatureEntry);
  71. Pickle pickle(src, checked_cast<size_t>(pickle_size));
  72. PickleIterator pickle_iter(pickle);
  73. if (!pickle_iter.ReadStringPiece(feature_name))
  74. return false;
  75. // Return true because we are not guaranteed to have a trial name anyways.
  76. std::ignore = pickle_iter.ReadStringPiece(trial_name);
  77. return true;
  78. }
  79. };
  80. // Some characters are not allowed to appear in feature names or the associated
  81. // field trial names, as they are used as special characters for command-line
  82. // serialization. This function checks that the strings are ASCII (since they
  83. // are used in command-line API functions that require ASCII) and whether there
  84. // are any reserved characters present, returning true if the string is valid.
  85. // Only called in DCHECKs.
  86. bool IsValidFeatureOrFieldTrialName(StringPiece name) {
  87. return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
  88. }
  89. // Splits |text| into two parts by the |separator| where the first part will be
  90. // returned updated in |first| and the second part will be returned as |second|.
  91. // This function returns false if there is more than one |separator| in |first|.
  92. // If there is no |separator| presented in |first|, this function will not
  93. // modify |first| and |second|. It's used for splitting the |enable_features|
  94. // flag into feature name, field trial name and feature parameters.
  95. bool SplitIntoTwo(StringPiece text,
  96. StringPiece separator,
  97. StringPiece* first,
  98. std::string* second) {
  99. std::vector<StringPiece> parts =
  100. SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL);
  101. if (parts.size() == 2) {
  102. *second = std::string(parts[1]);
  103. } else if (parts.size() > 2) {
  104. DLOG(ERROR) << "Only one '" << separator
  105. << "' is allowed but got: " << *first;
  106. return false;
  107. }
  108. *first = parts[0];
  109. return true;
  110. }
  111. // Checks and parses the |enable_features| flag and sets
  112. // |parsed_enable_features| to be a comma-separated list of features,
  113. // |force_fieldtrials| to be a comma-separated list of field trials that each
  114. // feature want to associate with and |force_fieldtrial_params| to be the field
  115. // trial parameters for each field trial.
  116. // Returns true if |enable_features| is parsable, otherwise false.
  117. bool ParseEnableFeatures(const std::string& enable_features,
  118. std::string* parsed_enable_features,
  119. std::string* force_fieldtrials,
  120. std::string* force_fieldtrial_params) {
  121. std::vector<std::string> enable_features_list;
  122. std::vector<std::string> force_fieldtrials_list;
  123. std::vector<std::string> force_fieldtrial_params_list;
  124. for (const auto& enable_feature :
  125. FeatureList::SplitFeatureListString(enable_features)) {
  126. std::string feature_name;
  127. std::string study;
  128. std::string group;
  129. std::string feature_params;
  130. if (!FeatureList::ParseEnableFeatureString(
  131. enable_feature, &feature_name, &study, &group, &feature_params)) {
  132. return false;
  133. }
  134. // If feature params were set but group and study weren't, associate the
  135. // feature and its feature params to a synthetic field trial as the
  136. // feature params only make sense when it's combined with a field trial.
  137. if (!feature_params.empty()) {
  138. force_fieldtrials_list.push_back(study + "/" + group);
  139. force_fieldtrial_params_list.push_back(study + "." + group + ":" +
  140. feature_params);
  141. }
  142. enable_features_list.push_back(
  143. study.empty() ? feature_name : (feature_name + "<" + study));
  144. }
  145. *parsed_enable_features = JoinString(enable_features_list, ",");
  146. // Field trial separator is currently a slash. See
  147. // |kPersistentStringSeparator| in base/metrics/field_trial.cc.
  148. *force_fieldtrials = JoinString(force_fieldtrials_list, "/");
  149. *force_fieldtrial_params = JoinString(force_fieldtrial_params_list, ",");
  150. return true;
  151. }
  152. } // namespace
  153. #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
  154. const Feature kDCheckIsFatalFeature{"DcheckIsFatal",
  155. FEATURE_DISABLED_BY_DEFAULT};
  156. #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
  157. FeatureList::FeatureList() = default;
  158. FeatureList::~FeatureList() = default;
  159. FeatureList::ScopedDisallowOverrides::ScopedDisallowOverrides(
  160. const char* reason)
  161. #if DCHECK_IS_ON()
  162. : previous_reason_(g_reason_overrides_disallowed) {
  163. g_reason_overrides_disallowed = reason;
  164. }
  165. #else
  166. {
  167. }
  168. #endif
  169. FeatureList::ScopedDisallowOverrides::~ScopedDisallowOverrides() {
  170. #if DCHECK_IS_ON()
  171. g_reason_overrides_disallowed = previous_reason_;
  172. #endif
  173. }
  174. void FeatureList::InitializeFromCommandLine(
  175. const std::string& enable_features,
  176. const std::string& disable_features) {
  177. DCHECK(!initialized_);
  178. std::string parsed_enable_features;
  179. std::string force_fieldtrials;
  180. std::string force_fieldtrial_params;
  181. bool parse_enable_features_result =
  182. ParseEnableFeatures(enable_features, &parsed_enable_features,
  183. &force_fieldtrials, &force_fieldtrial_params);
  184. DCHECK(parse_enable_features_result) << StringPrintf(
  185. "The --%s list is unparsable or invalid, please check the format.",
  186. ::switches::kEnableFeatures);
  187. // Only create field trials when field_trial_list is available. Some tests
  188. // don't have field trial list available.
  189. if (FieldTrialList::GetInstance()) {
  190. bool associate_params_result = AssociateFieldTrialParamsFromString(
  191. force_fieldtrial_params, &UnescapeValue);
  192. DCHECK(associate_params_result) << StringPrintf(
  193. "The field trial parameters part of the --%s list is invalid. Make "
  194. "sure "
  195. "you %%-encode the following characters in param values: %%:/.,",
  196. ::switches::kEnableFeatures);
  197. bool create_trials_result =
  198. FieldTrialList::CreateTrialsFromString(force_fieldtrials);
  199. DCHECK(create_trials_result)
  200. << StringPrintf("Invalid field trials are specified in --%s.",
  201. ::switches::kEnableFeatures);
  202. }
  203. // Process disabled features first, so that disabled ones take precedence over
  204. // enabled ones (since RegisterOverride() uses insert()).
  205. RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
  206. RegisterOverridesFromCommandLine(parsed_enable_features,
  207. OVERRIDE_ENABLE_FEATURE);
  208. initialized_from_command_line_ = true;
  209. }
  210. void FeatureList::InitializeFromSharedMemory(
  211. PersistentMemoryAllocator* allocator) {
  212. DCHECK(!initialized_);
  213. PersistentMemoryAllocator::Iterator iter(allocator);
  214. const FeatureEntry* entry;
  215. while ((entry = iter.GetNextOfObject<FeatureEntry>()) != nullptr) {
  216. OverrideState override_state =
  217. static_cast<OverrideState>(entry->override_state);
  218. StringPiece feature_name;
  219. StringPiece trial_name;
  220. if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name))
  221. continue;
  222. FieldTrial* trial = FieldTrialList::Find(trial_name);
  223. RegisterOverride(feature_name, override_state, trial);
  224. }
  225. }
  226. bool FeatureList::IsFeatureOverridden(const std::string& feature_name) const {
  227. return overrides_.count(feature_name);
  228. }
  229. bool FeatureList::IsFeatureOverriddenFromCommandLine(
  230. const std::string& feature_name) const {
  231. auto it = overrides_.find(feature_name);
  232. return it != overrides_.end() && !it->second.overridden_by_field_trial;
  233. }
  234. bool FeatureList::IsFeatureOverriddenFromCommandLine(
  235. const std::string& feature_name,
  236. OverrideState state) const {
  237. auto it = overrides_.find(feature_name);
  238. return it != overrides_.end() && !it->second.overridden_by_field_trial &&
  239. it->second.overridden_state == state;
  240. }
  241. void FeatureList::AssociateReportingFieldTrial(
  242. const std::string& feature_name,
  243. OverrideState for_overridden_state,
  244. FieldTrial* field_trial) {
  245. DCHECK(
  246. IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
  247. // Only one associated field trial is supported per feature. This is generally
  248. // enforced server-side.
  249. OverrideEntry* entry = &overrides_.find(feature_name)->second;
  250. if (entry->field_trial) {
  251. NOTREACHED() << "Feature " << feature_name
  252. << " already has trial: " << entry->field_trial->trial_name()
  253. << ", associating trial: " << field_trial->trial_name();
  254. return;
  255. }
  256. entry->field_trial = field_trial;
  257. }
  258. void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
  259. OverrideState override_state,
  260. FieldTrial* field_trial) {
  261. DCHECK(field_trial);
  262. DCHECK(!Contains(overrides_, feature_name) ||
  263. !overrides_.find(feature_name)->second.field_trial)
  264. << "Feature " << feature_name << " is overriden multiple times in these "
  265. << "trials: "
  266. << overrides_.find(feature_name)->second.field_trial->trial_name()
  267. << " and " << field_trial->trial_name() << ". "
  268. << "Check the trial (study) in (1) the server config, "
  269. << "(2) fieldtrial_testing_config.json, (3) about_flags.cc, and "
  270. << "(4) client-side field trials.";
  271. RegisterOverride(feature_name, override_state, field_trial);
  272. }
  273. void FeatureList::RegisterExtraFeatureOverrides(
  274. const std::vector<FeatureOverrideInfo>& extra_overrides) {
  275. for (const FeatureOverrideInfo& override_info : extra_overrides) {
  276. RegisterOverride(override_info.first.get().name, override_info.second,
  277. /* field_trial = */ nullptr);
  278. }
  279. }
  280. void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) {
  281. DCHECK(initialized_);
  282. for (const auto& override : overrides_) {
  283. Pickle pickle;
  284. pickle.WriteString(override.first);
  285. if (override.second.field_trial)
  286. pickle.WriteString(override.second.field_trial->trial_name());
  287. size_t total_size = sizeof(FeatureEntry) + pickle.size();
  288. FeatureEntry* entry = allocator->New<FeatureEntry>(total_size);
  289. if (!entry)
  290. return;
  291. entry->override_state = override.second.overridden_state;
  292. entry->pickle_size = pickle.size();
  293. char* dst = reinterpret_cast<char*>(entry) + sizeof(FeatureEntry);
  294. memcpy(dst, pickle.data(), pickle.size());
  295. allocator->MakeIterable(entry);
  296. }
  297. }
  298. void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
  299. std::string* disable_overrides,
  300. bool include_group_name) const {
  301. GetFeatureOverridesImpl(enable_overrides, disable_overrides, false,
  302. include_group_name);
  303. }
  304. void FeatureList::GetCommandLineFeatureOverrides(
  305. std::string* enable_overrides,
  306. std::string* disable_overrides) const {
  307. GetFeatureOverridesImpl(enable_overrides, disable_overrides, true);
  308. }
  309. // static
  310. bool FeatureList::IsEnabled(const Feature& feature) {
  311. #if DCHECK_IS_ON()
  312. CHECK(g_use_allowed) << "base::Feature not permitted for this module.";
  313. #endif
  314. if (!g_feature_list_instance) {
  315. g_initialized_from_accessor = &feature;
  316. return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
  317. }
  318. return g_feature_list_instance->IsFeatureEnabled(feature);
  319. }
  320. // static
  321. absl::optional<bool> FeatureList::GetStateIfOverridden(const Feature& feature) {
  322. #if DCHECK_IS_ON()
  323. CHECK(g_use_allowed) << "base::Feature not permitted for this module.";
  324. #endif
  325. if (!g_feature_list_instance) {
  326. g_initialized_from_accessor = &feature;
  327. // If there is no feature list, there can be no overrides.
  328. return absl::nullopt;
  329. }
  330. return g_feature_list_instance->IsFeatureEnabledIfOverridden(feature);
  331. }
  332. // static
  333. FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
  334. #if DCHECK_IS_ON()
  335. // See documentation for ForbidUseForCurrentModule.
  336. CHECK(g_use_allowed) << "base::Feature not permitted for this module.";
  337. #endif
  338. if (!g_feature_list_instance) {
  339. g_initialized_from_accessor = &feature;
  340. return nullptr;
  341. }
  342. return g_feature_list_instance->GetAssociatedFieldTrial(feature);
  343. }
  344. // static
  345. std::vector<StringPiece> FeatureList::SplitFeatureListString(
  346. StringPiece input) {
  347. return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
  348. }
  349. // static
  350. bool FeatureList::ParseEnableFeatureString(StringPiece enable_feature,
  351. std::string* feature_name,
  352. std::string* study_name,
  353. std::string* group_name,
  354. std::string* params) {
  355. StringPiece first;
  356. // First, check whether ":" is present. If true, feature parameters were
  357. // set for this feature.
  358. std::string feature_params;
  359. if (!SplitIntoTwo(enable_feature, ":", &first, &feature_params))
  360. return false;
  361. // Then, check whether "." is present. If true, a group was specified for
  362. // this feature.
  363. std::string group;
  364. if (!SplitIntoTwo(first, ".", &first, &group))
  365. return false;
  366. // Finally, check whether "<" is present. If true, a study was specified for
  367. // this feature.
  368. std::string study;
  369. if (!SplitIntoTwo(first, "<", &first, &study))
  370. return false;
  371. std::string enable_feature_name(first);
  372. // If feature params were set but group and study weren't, associate the
  373. // feature and its feature params to a synthetic field trial as the
  374. // feature params only make sense when it's combined with a field trial.
  375. if (!feature_params.empty()) {
  376. study = study.empty() ? "Study" + enable_feature_name : study;
  377. group = group.empty() ? "Group" + enable_feature_name : group;
  378. }
  379. feature_name->swap(enable_feature_name);
  380. study_name->swap(study);
  381. group_name->swap(group);
  382. params->swap(feature_params);
  383. return true;
  384. }
  385. // static
  386. bool FeatureList::InitializeInstance(const std::string& enable_features,
  387. const std::string& disable_features) {
  388. return InitializeInstance(enable_features, disable_features,
  389. std::vector<FeatureOverrideInfo>());
  390. }
  391. // static
  392. bool FeatureList::InitializeInstance(
  393. const std::string& enable_features,
  394. const std::string& disable_features,
  395. const std::vector<FeatureOverrideInfo>& extra_overrides) {
  396. // We want to initialize a new instance here to support command-line features
  397. // in testing better. For example, we initialize a dummy instance in
  398. // base/test/test_suite.cc, and override it in content/browser/
  399. // browser_main_loop.cc.
  400. // On the other hand, we want to avoid re-initialization from command line.
  401. // For example, we initialize an instance in chrome/browser/
  402. // chrome_browser_main.cc and do not override it in content/browser/
  403. // browser_main_loop.cc.
  404. // If the singleton was previously initialized from within an accessor, we
  405. // want to prevent callers from reinitializing the singleton and masking the
  406. // accessor call(s) which likely returned incorrect information.
  407. if (g_initialized_from_accessor) {
  408. DEBUG_ALIAS_FOR_CSTR(accessor_name, g_initialized_from_accessor->name, 128);
  409. CHECK(!g_initialized_from_accessor);
  410. }
  411. bool instance_existed_before = false;
  412. if (g_feature_list_instance) {
  413. if (g_feature_list_instance->initialized_from_command_line_)
  414. return false;
  415. delete g_feature_list_instance;
  416. g_feature_list_instance = nullptr;
  417. instance_existed_before = true;
  418. }
  419. std::unique_ptr<FeatureList> feature_list(new FeatureList);
  420. feature_list->InitializeFromCommandLine(enable_features, disable_features);
  421. feature_list->RegisterExtraFeatureOverrides(extra_overrides);
  422. FeatureList::SetInstance(std::move(feature_list));
  423. return !instance_existed_before;
  424. }
  425. // static
  426. FeatureList* FeatureList::GetInstance() {
  427. return g_feature_list_instance;
  428. }
  429. // static
  430. void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
  431. DCHECK(!g_feature_list_instance);
  432. instance->FinalizeInitialization();
  433. // Note: Intentional leak of global singleton.
  434. g_feature_list_instance = instance.release();
  435. #if BUILDFLAG(IS_ANDROID)
  436. ConfigureRandBytesFieldTrial();
  437. #endif
  438. base::sequence_manager::internal::WorkQueue::ConfigureCapacityFieldTrial();
  439. #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
  440. // Update the behaviour of LOGGING_DCHECK to match the Feature configuration.
  441. // DCHECK is also forced to be FATAL if we are running a death-test.
  442. // TODO(crbug.com/1057995#c11): --gtest_internal_run_death_test doesn't
  443. // currently run through this codepath, mitigated in
  444. // base::TestSuite::Initialize() for now.
  445. // TODO(asvitkine): If we find other use-cases that need integrating here
  446. // then define a proper API/hook for the purpose.
  447. if (FeatureList::IsEnabled(kDCheckIsFatalFeature) ||
  448. CommandLine::ForCurrentProcess()->HasSwitch(
  449. "gtest_internal_run_death_test")) {
  450. logging::LOGGING_DCHECK = logging::LOG_FATAL;
  451. } else {
  452. logging::LOGGING_DCHECK = logging::LOG_INFO;
  453. }
  454. #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
  455. }
  456. // static
  457. std::unique_ptr<FeatureList> FeatureList::ClearInstanceForTesting() {
  458. FeatureList* old_instance = g_feature_list_instance;
  459. g_feature_list_instance = nullptr;
  460. g_initialized_from_accessor = nullptr;
  461. return WrapUnique(old_instance);
  462. }
  463. // static
  464. void FeatureList::RestoreInstanceForTesting(
  465. std::unique_ptr<FeatureList> instance) {
  466. DCHECK(!g_feature_list_instance);
  467. // Note: Intentional leak of global singleton.
  468. g_feature_list_instance = instance.release();
  469. }
  470. // static
  471. void FeatureList::ForbidUseForCurrentModule() {
  472. #if DCHECK_IS_ON()
  473. // Verify there hasn't been any use prior to being called.
  474. DCHECK(!g_initialized_from_accessor);
  475. g_use_allowed = false;
  476. #endif // DCHECK_IS_ON()
  477. }
  478. void FeatureList::FinalizeInitialization() {
  479. DCHECK(!initialized_);
  480. // Store the field trial list pointer for DCHECKing.
  481. field_trial_list_ = FieldTrialList::GetInstance();
  482. initialized_ = true;
  483. }
  484. bool FeatureList::IsFeatureEnabled(const Feature& feature) const {
  485. OverrideState overridden_state = GetOverrideState(feature);
  486. // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below.
  487. if (overridden_state != OVERRIDE_USE_DEFAULT)
  488. return overridden_state == OVERRIDE_ENABLE_FEATURE;
  489. return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
  490. }
  491. absl::optional<bool> FeatureList::IsFeatureEnabledIfOverridden(
  492. const Feature& feature) const {
  493. OverrideState overridden_state = GetOverrideState(feature);
  494. // If marked as OVERRIDE_USE_DEFAULT, fall through to returning empty.
  495. if (overridden_state != OVERRIDE_USE_DEFAULT)
  496. return overridden_state == OVERRIDE_ENABLE_FEATURE;
  497. return absl::nullopt;
  498. }
  499. FeatureList::OverrideState FeatureList::GetOverrideState(
  500. const Feature& feature) const {
  501. DCHECK(initialized_);
  502. DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
  503. DCHECK(CheckFeatureIdentity(feature)) << feature.name;
  504. return GetOverrideStateByFeatureName(feature.name);
  505. }
  506. FeatureList::OverrideState FeatureList::GetOverrideStateByFeatureName(
  507. StringPiece feature_name) const {
  508. DCHECK(initialized_);
  509. DCHECK(IsValidFeatureOrFieldTrialName(feature_name)) << feature_name;
  510. auto it = overrides_.find(feature_name);
  511. if (it != overrides_.end()) {
  512. const OverrideEntry& entry = it->second;
  513. // Activate the corresponding field trial, if necessary.
  514. if (entry.field_trial)
  515. entry.field_trial->group();
  516. // TODO(asvitkine) Expand this section as more support is added.
  517. return entry.overridden_state;
  518. }
  519. // Otherwise, report that we want to use the default state.
  520. return OVERRIDE_USE_DEFAULT;
  521. }
  522. FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) const {
  523. DCHECK(initialized_);
  524. DCHECK(CheckFeatureIdentity(feature)) << feature.name;
  525. return GetAssociatedFieldTrialByFeatureName(feature.name);
  526. }
  527. const base::FeatureList::OverrideEntry*
  528. FeatureList::GetOverrideEntryByFeatureName(StringPiece name) const {
  529. DCHECK(initialized_);
  530. DCHECK(IsValidFeatureOrFieldTrialName(name)) << name;
  531. auto it = overrides_.find(name);
  532. if (it != overrides_.end()) {
  533. const OverrideEntry& entry = it->second;
  534. return &entry;
  535. }
  536. return nullptr;
  537. }
  538. FieldTrial* FeatureList::GetAssociatedFieldTrialByFeatureName(
  539. StringPiece name) const {
  540. DCHECK(initialized_);
  541. const base::FeatureList::OverrideEntry* entry =
  542. GetOverrideEntryByFeatureName(name);
  543. if (entry) {
  544. return entry->field_trial;
  545. }
  546. return nullptr;
  547. }
  548. FieldTrial* FeatureList::GetEnabledFieldTrialByFeatureName(
  549. StringPiece name) const {
  550. DCHECK(initialized_);
  551. const base::FeatureList::OverrideEntry* entry =
  552. GetOverrideEntryByFeatureName(name);
  553. if (entry &&
  554. entry->overridden_state == base::FeatureList::OVERRIDE_ENABLE_FEATURE) {
  555. return entry->field_trial;
  556. }
  557. return nullptr;
  558. }
  559. std::unique_ptr<FeatureList::Accessor> FeatureList::ConstructAccessor() {
  560. if (initialized_) {
  561. // This function shouldn't be called after initialization.
  562. NOTREACHED();
  563. return nullptr;
  564. }
  565. // Use new and WrapUnique because we want to restrict access to the Accessor's
  566. // constructor.
  567. return base::WrapUnique(new Accessor(this));
  568. }
  569. void FeatureList::RegisterOverridesFromCommandLine(
  570. const std::string& feature_list,
  571. OverrideState overridden_state) {
  572. for (const auto& value : SplitFeatureListString(feature_list)) {
  573. StringPiece feature_name = value;
  574. FieldTrial* trial = nullptr;
  575. // The entry may be of the form FeatureName<FieldTrialName - in which case,
  576. // this splits off the field trial name and associates it with the override.
  577. std::string::size_type pos = feature_name.find('<');
  578. if (pos != std::string::npos) {
  579. feature_name = StringPiece(value.data(), pos);
  580. trial = FieldTrialList::Find(value.substr(pos + 1));
  581. #if !BUILDFLAG(IS_NACL)
  582. // If the below DCHECK fires, it means a non-existent trial name was
  583. // specified via the "Feature<Trial" command-line syntax.
  584. DCHECK(trial) << "trial='" << value.substr(pos + 1) << "' does not exist";
  585. #endif // !BUILDFLAG(IS_NACL)
  586. }
  587. RegisterOverride(feature_name, overridden_state, trial);
  588. }
  589. }
  590. void FeatureList::RegisterOverride(StringPiece feature_name,
  591. OverrideState overridden_state,
  592. FieldTrial* field_trial) {
  593. DCHECK(!initialized_);
  594. DCheckOverridesAllowed();
  595. if (field_trial) {
  596. DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
  597. << field_trial->trial_name();
  598. }
  599. if (StartsWith(feature_name, "*")) {
  600. feature_name = feature_name.substr(1);
  601. overridden_state = OVERRIDE_USE_DEFAULT;
  602. }
  603. // Note: The semantics of emplace() is that it does not overwrite the entry if
  604. // one already exists for the key. Thus, only the first override for a given
  605. // feature name takes effect.
  606. overrides_.emplace(std::string(feature_name),
  607. OverrideEntry(overridden_state, field_trial));
  608. }
  609. void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides,
  610. std::string* disable_overrides,
  611. bool command_line_only,
  612. bool include_group_name) const {
  613. DCHECK(initialized_);
  614. // Check that the FieldTrialList this is associated with, if any, is the
  615. // active one. If not, it likely indicates that this FeatureList has override
  616. // entries from a freed FieldTrial, which may be caused by an incorrect test
  617. // set up.
  618. if (field_trial_list_)
  619. DCHECK_EQ(field_trial_list_, FieldTrialList::GetInstance());
  620. enable_overrides->clear();
  621. disable_overrides->clear();
  622. // Note: Since |overrides_| is a std::map, iteration will be in alphabetical
  623. // order. This is not guaranteed to users of this function, but is useful for
  624. // tests to assume the order.
  625. for (const auto& entry : overrides_) {
  626. if (command_line_only &&
  627. (entry.second.field_trial != nullptr ||
  628. entry.second.overridden_state == OVERRIDE_USE_DEFAULT)) {
  629. continue;
  630. }
  631. std::string* target_list = nullptr;
  632. switch (entry.second.overridden_state) {
  633. case OVERRIDE_USE_DEFAULT:
  634. case OVERRIDE_ENABLE_FEATURE:
  635. target_list = enable_overrides;
  636. break;
  637. case OVERRIDE_DISABLE_FEATURE:
  638. target_list = disable_overrides;
  639. break;
  640. }
  641. if (!target_list->empty())
  642. target_list->push_back(',');
  643. if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT)
  644. target_list->push_back('*');
  645. target_list->append(entry.first);
  646. if (entry.second.field_trial) {
  647. auto* const field_trial = entry.second.field_trial;
  648. target_list->push_back('<');
  649. target_list->append(field_trial->trial_name());
  650. if (include_group_name) {
  651. target_list->push_back('.');
  652. target_list->append(field_trial->GetGroupNameWithoutActivation());
  653. }
  654. }
  655. }
  656. }
  657. bool FeatureList::CheckFeatureIdentity(const Feature& feature) const {
  658. AutoLock auto_lock(feature_identity_tracker_lock_);
  659. auto it = feature_identity_tracker_.find(feature.name);
  660. if (it == feature_identity_tracker_.end()) {
  661. // If it's not tracked yet, register it.
  662. feature_identity_tracker_[feature.name] = &feature;
  663. return true;
  664. }
  665. // Compare address of |feature| to the existing tracked entry.
  666. return it->second == &feature;
  667. }
  668. FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
  669. FieldTrial* field_trial)
  670. : overridden_state(overridden_state),
  671. field_trial(field_trial),
  672. overridden_by_field_trial(field_trial != nullptr) {}
  673. FeatureList::Accessor::Accessor(FeatureList* feature_list)
  674. : feature_list_(feature_list) {}
  675. FeatureList::OverrideState FeatureList::Accessor::GetOverrideStateByFeatureName(
  676. StringPiece feature_name) {
  677. return feature_list_->GetOverrideStateByFeatureName(feature_name);
  678. }
  679. bool FeatureList::Accessor::GetParamsByFeatureName(
  680. StringPiece feature_name,
  681. std::map<std::string, std::string>* params) {
  682. base::FieldTrial* trial =
  683. feature_list_->GetAssociatedFieldTrialByFeatureName(feature_name);
  684. return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial,
  685. params);
  686. }
  687. } // namespace base