1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/cronet/android/cronet_base_feature.h"
6
7 #include "base/debug/leak_annotations.h"
8 #include "base/feature_list.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/field_trial_params.h"
11
12 namespace cronet {
13
14 using ::org::chromium::net::httpflags::BaseFeatureOverrides;
15
ApplyBaseFeatureOverrides(const BaseFeatureOverrides & overrides)16 void ApplyBaseFeatureOverrides(const BaseFeatureOverrides& overrides) {
17 if (base::FeatureList::GetInstance() != nullptr) {
18 LOG(WARNING) << "Not setting Cronet base::Feature overrides as "
19 "base::Feature is already initialized";
20 return;
21 }
22
23 // We need to ensure base::FieldTrialList is initialized, otherwise the call
24 // to base::FieldTrialList::CreateFieldTrial() below will crash.
25 {
26 // Intentional leak (singleton). Note that we can't use a static
27 // base::NoDestructor here because that would lead to the FieldTrialList
28 // singleton not getting properly reset between unit tests.
29 auto* const field_trial_list = new base::FieldTrialList();
30 ANNOTATE_LEAKING_OBJECT_PTR(field_trial_list);
31 (void)field_trial_list;
32 }
33
34 auto feature_list = std::make_unique<base::FeatureList>();
35 for (const auto& [feature_name, feature_state] : overrides.feature_states()) {
36 // Cronet uses its own bespoke metrics logging system, and never reports
37 // base::FieldTrial data back to Finch. We still need to provide a
38 // FieldTrial to be able to register the base::Feature override and to
39 // associate params, so let's create a fake one with bogus names. This is
40 // similar in principle to how Chrome base::Features can be overridden from
41 // the command line, and in fact the naming scheme below is inspired by how
42 // base::FeatureList::InitializeFromCommandLine() generates fake field trial
43 // and group names, with an additional "Cronet" prefix.
44 const std::string field_trial_name = "CronetStudy" + feature_name;
45 const std::string field_trial_group = "CronetGroup" + feature_name;
46 auto* const field_trial = base::FieldTrialList::CreateFieldTrial(
47 field_trial_name, field_trial_group);
48 CHECK(field_trial != nullptr)
49 << "Unable to create field trial for feature: " << feature_name;
50 feature_list->RegisterFieldTrialOverride(
51 feature_name,
52 feature_state.has_enabled()
53 ? (feature_state.enabled()
54 ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
55 : base::FeatureList::OVERRIDE_DISABLE_FEATURE)
56 : base::FeatureList::OVERRIDE_USE_DEFAULT,
57 field_trial);
58 if (!feature_state.params().empty()) {
59 base::AssociateFieldTrialParams(
60 field_trial_name, field_trial_group,
61 {feature_state.params().begin(), feature_state.params().end()});
62 }
63 }
64 base::FeatureList::SetInstance(std::move(feature_list));
65 }
66
67 } // namespace cronet
68