field_trials.h (4272B)
1 /* 2 * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef API_FIELD_TRIALS_H_ 12 #define API_FIELD_TRIALS_H_ 13 14 #include <atomic> 15 #include <memory> 16 #include <string> 17 #include <utility> 18 19 #include "absl/base/nullability.h" 20 #include "absl/strings/string_view.h" 21 #include "api/field_trials_registry.h" 22 #include "api/field_trials_view.h" 23 #include "rtc_base/checks.h" 24 #include "rtc_base/containers/flat_map.h" 25 26 namespace webrtc { 27 28 // The FieldTrials class is used to inject field trials into webrtc. 29 // 30 // Field trials allow webrtc clients (such as Chromium) to turn on feature code 31 // in binaries out in the field and gather information with that. 32 // 33 // They are designed to be easy to use with Chromium field trials and to speed 34 // up developers by reducing the need to wire up APIs to control whether a 35 // feature is on/off. 36 // 37 // The field trials are injected into objects that use them at creation time. 38 class FieldTrials : public FieldTrialsRegistry { 39 public: 40 // Creates field trials from a valid field trial string. 41 // Returns nullptr if the string is invalid. 42 // E.g., valid string: 43 // "WebRTC-ExperimentFoo/Enabled/WebRTC-ExperimentBar/Enabled100kbps/" 44 // Assigns to group "Enabled" on WebRTC-ExperimentFoo trial 45 // and to group "Enabled100kbps" on WebRTC-ExperimentBar. 46 // 47 // E.g., invalid string: 48 // "WebRTC-experiment1/Enabled" (note missing / separator at the end). 49 static absl_nullable std::unique_ptr<FieldTrials> Create(absl::string_view s); 50 51 // Creates field trials from a string. 52 // It is an error to call the constructor with an invalid field trial string. 53 explicit FieldTrials(absl::string_view s); 54 55 FieldTrials(const FieldTrials&); 56 FieldTrials(FieldTrials&&); 57 FieldTrials& operator=(const FieldTrials&); 58 FieldTrials& operator=(FieldTrials&&); 59 60 ~FieldTrials() override = default; 61 62 template <typename Sink> 63 friend void AbslStringify(Sink& sink, const FieldTrials& self); 64 65 // Merges field trials from the `other` into this. 66 // 67 // If a key (trial) exists twice with conflicting values (groups), the value 68 // in `other` takes precedence. 69 void Merge(const FieldTrials& other); 70 71 // Sets value (`group`) for an indvidual `trial`. 72 // It is an error to call this function with an invalid `trial` or `group`. 73 // Setting empty `group` is valid and removes the `trial`. 74 void Set(absl::string_view trial, absl::string_view group); 75 76 // Create a copy of this view. 77 std::unique_ptr<FieldTrialsView> CreateCopy() const override { 78 // We don't need to reset get_value_called_ on the returned copy 79 // since it is a FieldTrialsView that has no mutable methods. 80 return std::make_unique<FieldTrials>(*this); 81 } 82 83 void AssertGetValueNotCalled() const { 84 #if RTC_DCHECK_IS_ON 85 RTC_DCHECK(!get_value_called_) 86 << "FieldTrials are immutable once first Lookup has been performed"; 87 #endif 88 } 89 90 private: 91 explicit FieldTrials(flat_map<std::string, std::string> key_value_map) 92 : key_value_map_(std::move(key_value_map)) {} 93 94 std::string GetValue(absl::string_view key) const override; 95 96 #if RTC_DCHECK_IS_ON 97 // Keep track of if GetValue() has been called. 98 // This is used to enforce immutability by DCHECK:ing 99 // that modification are performed once get_value_called_ 100 // is true. 101 mutable std::atomic<bool> get_value_called_ = false; 102 #endif 103 104 flat_map<std::string, std::string> key_value_map_; 105 }; 106 107 template <typename Sink> 108 void AbslStringify(Sink& sink, const FieldTrials& self) { 109 for (const auto& [trial, group] : self.key_value_map_) { 110 sink.Append(trial); 111 sink.Append("/"); 112 sink.Append(group); 113 // Intentionally output a string that is not a valid field trial string. 114 // Stringification is intended only for human readable logs, and is not 115 // intended for reusing as `FieldTrials` construction parameter. 116 sink.Append("//"); 117 } 118 } 119 120 } // namespace webrtc 121 122 #endif // API_FIELD_TRIALS_H_