File: variations_field_trial_creator_base.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (365 lines) | stat: -rw-r--r-- 15,896 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_VARIATIONS_SERVICE_VARIATIONS_FIELD_TRIAL_CREATOR_BASE_H_
#define COMPONENTS_VARIATIONS_SERVICE_VARIATIONS_FIELD_TRIAL_CREATOR_BASE_H_

// This file contains a base class for VariationsFieldTrialCreator. Its primary
// goal is to minimize generated code size, even at the expense of
// functionality, and to be usable in ChromeOS early boot as part of a
// standalone executable.
// In particular, it will *not*:
// 1) determine locale (this requires linking in libicu, which is several
//    hundred KiB). Instead, it will accept locale as a parameter to the
//    constructor.
// 2) modify cached UI strings (we remove the ui::ResourceBundle dep entirely)
//
// All such functionality must be implemented by subclasses (e.g.
// VariationsFieldTrialCreator)

#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/field_trial.h"
#include "base/time/time.h"
#include "base/version_info/channel.h"
#include "build/build_config.h"
#include "components/variations/client_filterable_state.h"
#include "components/variations/metrics.h"
#include "components/variations/proto/study.pb.h"
#include "components/variations/seed_response.h"
#include "components/variations/service/buildflags.h"
#include "components/variations/service/limited_entropy_synthetic_trial.h"
#include "components/variations/service/safe_seed_manager.h"
#include "components/variations/service/variations_service_client.h"
#include "components/variations/variations_seed_store.h"
#include "components/version_info/channel.h"

namespace metrics {
class MetricsStateManager;
}

namespace variations {

class SyntheticTrialRegistry;
class EntropyProviders;

// Just maps one set of enum values to another. Nothing to see here.
Study::Channel ConvertProductChannelToStudyChannel(
    version_info::Channel product_channel);

// Denotes whether Chrome used a variations seed. Also captures (a) the kind of
// seed and (b) the conditions under which the seed was used or failed to be
// used. Exposed for testing.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class SeedUsage {
  kRegularSeedUsed = 0,
  kExpiredRegularSeedNotUsed = 1,
  kUnloadableRegularSeedNotUsed = 2,
  kSafeSeedUsed = 3,
  kExpiredSafeSeedNotUsed = 4,
  // The below three enumerators were deprecated in M100.
  // kCorruptedSafeSeedNotUsed = 5,
  // kRegularSeedUsedAfterEmptySafeSeedLoaded = 6,
  // kExpiredRegularSeedNotUsedAfterEmptySafeSeedLoaded = 7,
  // kCorruptedRegularSeedNotUsedAfterEmptySafeSeedLoaded = 8,
  kRegularSeedForFutureMilestoneNotUsed = 9,
  kSafeSeedForFutureMilestoneNotUsed = 10,
  kUnloadableSafeSeedNotUsed = 11,
  kNullSeedUsed = 12,
  kMaxValue = kNullSeedUsed,
};

// Denotes a variations seed's expiry state. Exposed for testing.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class VariationsSeedExpiry {
  kNotExpired = 0,
  kFetchTimeMissing = 1,
  kExpired = 2,
  kMaxValue = kExpired,
};

enum LoadPermanentConsistencyCountryResult {
  LOAD_COUNTRY_NO_PREF_NO_SEED = 0,
  LOAD_COUNTRY_NO_PREF_HAS_SEED,
  LOAD_COUNTRY_INVALID_PREF_NO_SEED,
  LOAD_COUNTRY_INVALID_PREF_HAS_SEED,
  LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_EQ,
  LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_NEQ,
  LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_EQ,
  LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_NEQ,
  LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_EQ,
  LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_NEQ,
  LOAD_COUNTRY_HAS_PERMANENT_OVERRIDDEN_COUNTRY,
  LOAD_COUNTRY_MAX,
};

class PlatformFieldTrials;
class SafeSeedManagerBase;
class VariationsServiceClient;

// Used to set up field trials based on stored variations seed data.
class VariationsFieldTrialCreatorBase {
 public:
  // Caller is responsible for ensuring that the VariationsServiceClient and
  // LimitedEntropySyntheticTrial passed to the
  // constructor stay valid for the lifetime of this object.
  //
  // |client| provides some platform-specific operations for variations.
  // |seed_store| manages seed data.
  // |locale_cb| computes the locale, given a PrefService for local_state.
  // |limited_entropy_synthetic_trial|, if not null, allows eligible clients to
  // participate in the synthetic trial.
  VariationsFieldTrialCreatorBase(
      VariationsServiceClient* client,
      std::unique_ptr<VariationsSeedStore> seed_store,
      base::OnceCallback<std::string(PrefService*)> locale_cb,
      LimitedEntropySyntheticTrial* limited_entropy_synthetic_trial);

  VariationsFieldTrialCreatorBase(const VariationsFieldTrialCreatorBase&) =
      delete;
  VariationsFieldTrialCreatorBase& operator=(
      const VariationsFieldTrialCreatorBase&) = delete;

  virtual ~VariationsFieldTrialCreatorBase();

  // Returns what variations will consider to be the latest country. Returns
  // empty if it is not available.
  std::string GetLatestCountry() const;

  VariationsSeedStore* seed_store() { return seed_store_.get(); }

  // Sets up field trials based on stored variations seed data. Returns whether
  // setup completed successfully.
  //
  // |variation_ids| allows for forcing ids selected in chrome://flags.
  // |command_line_variation_ids| allows for forcing ids through the
  // "--force-variation-ids" command line flag. It should be a comma-separated
  // list of variation ids. Ids prefixed with the character "t" will be treated
  // as Trigger Variation Ids.
  // |extra_overrides| gives a list of feature overrides that should be applied
  // after the features explicitly disabled/enabled from the command line via
  // --disable-features and --enable-features, but before field trials.
  // |feature_list| contains the list of all active features for this client.
  // Must not be null.
  // |metrics_state_manager| facilitates signaling that Chrome has not yet
  // exited cleanly. Must not be null.
  // |synthetic_trial_registry| provides an interface to register synthetic
  // trials. Must not be null.
  // |platform_field_trials| provides the
  // platform-specific field trial setup for Chrome. Must not be null.
  // |safe_seed_manager| should be notified of the combined server and client
  // state that was activated to create the field trials (only when the return
  // value is true). Must not be null.
  // |add_entropy_source_to_variations_ids| controls if variations ID for the
  // low entropy source should be added to FIRST_PARTY variation headers.
  // |entropy_providers| Used to provide entropy to field trials.
  // TODO(b/263797385): eliminate this argument if we can always add the ID.
  //
  // NOTE: The ordering of the FeatureList method calls is such that the
  // explicit --disable-features and --enable-features from the command line
  // take precedence over |extra_overrides|, which takes precedence over the
  // field trials.
  bool SetUpFieldTrials(
      const std::vector<std::string>& variation_ids,
      const std::string& command_line_variation_ids,
      const std::vector<base::FeatureList::FeatureOverrideInfo>&
          extra_overrides,
      std::unique_ptr<base::FeatureList> feature_list,
      metrics::MetricsStateManager* metrics_state_manager,
      SyntheticTrialRegistry* synthetic_trial_registry,
      PlatformFieldTrials* platform_field_trials,
      SafeSeedManagerBase* safe_seed_manager,
      bool add_entropy_source_to_variations_ids,
      const EntropyProviders& entropy_providers);

  // Returns all of the client state used for filtering studies.
  // As a side-effect, may update the stored permanent consistency country.
  std::unique_ptr<ClientFilterableState> GetClientFilterableStateForVersion(
      const base::Version& version);

  // Loads the country code to use for filtering permanent consistency studies,
  // updating the stored country code if the stored value was for a different
  // Chrome version. The country used for permanent consistency studies is kept
  // consistent between Chrome upgrades in order to avoid annoying the user due
  // to experiment churn while traveling.
  std::string LoadPermanentConsistencyCountry(
      const base::Version& version,
      const std::string& latest_country);

  // Returns the country code used for filtering permanent consistency studies.
  // This can only be called after field trials have been initialized or if
  // prefs::kVariationsPermanentOverriddenCountry has been overridden through
  // StoreVariationsOverriddenCountry() in this session.
  std::string GetPermanentConsistencyCountry() const;

  // Sets the stored permanent country pref for this client.
  void StorePermanentCountry(const base::Version& version,
                             const std::string& country);

  // Sets the stored permanent variations overridden country pref for this
  // client.
  void StoreVariationsOverriddenCountry(const std::string& country);

  // Allow the platform that is used to filter the set of active trials to be
  // overridden.
  void OverrideVariationsPlatform(Study::Platform platform_override);

  // Calculates the Seed Freshness
  base::Time CalculateSeedFreshness();

  // Returns the locale that was used for evaluating trials.
  const std::string& application_locale() const { return application_locale_; }

  SeedType seed_type() const { return seed_type_; }

  // Overrides cached UI strings on the resource bundle once it is initialized.
  // To be implemented by subclasses, if they have need for UI strings.
  virtual void OverrideCachedUIStrings() = 0;

  // Returns whether the map of the cached UI strings to override is empty.
  // To be implemented by subclasses, if they have need for UI strings.
  virtual bool IsOverrideResourceMapEmpty() = 0;

  // Whether the limited entropy randomization source is enabled on this client.
  // The `trial` param controls the output, which will be false if `trial` is
  // null or the trial is not enabled. `trial` can be a nullptr when the client
  // is not eligible for limited entropy randomization (e.g. Android WebView).
  static bool IsLimitedEntropyRandomizationSourceEnabled(
      version_info::Channel channel,
      LimitedEntropySyntheticTrial* trial);

 protected:
  // Get the platform we're running on, respecting OverrideVariationsPlatform().
  // Protected for testing.
  Study::Platform GetPlatform();

  // Get the client's current form factor. Protected for testing.
  Study::FormFactor GetCurrentFormFactor();

#if BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
  // Applies the field trial testing config defined in
  // testing/variations/fieldtrial_testing_config.json to the current session.
  // Protected and virtual for testing.
  virtual void ApplyFieldTrialTestingConfig(base::FeatureList* feature_list);
#endif  // BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)

  // Read the google group memberships from local-state prefs.
  // Protected for testing.
  base::flat_set<uint64_t> GetGoogleGroupsFromPrefs();

  // Overrides the string resource specified by |hash| with |str| in the
  // resource bundle. Protected for testing.
  // To be implemented by subclasses if they need UI string overrides.
  virtual void OverrideUIString(uint32_t hash, const std::u16string& str) = 0;

 private:
  // Returns true if the loaded VariationsSeed has expired. An expired seed is
  // one that (a) was fetched over |kMaxSeedAgeDays| ago and (b) is older than
  // the binary build time.
  //
  // Also, records a couple VariationsSeed-related metrics.
  bool HasSeedExpired();

  // Returns true if the loaded VariationsSeed is for a future milestone (e.g.
  // if the client is on M92 and the seed was fetched with M93). A seed for a
  // future milestone is invalid as it may be missing studies filtered out by
  // the server.
  bool IsSeedForFutureMilestone(bool is_safe_seed);

  // Creates field trials based on the variations seed loaded from local state.
  // If there is a problem loading the seed data, all trials specified by the
  // seed may not be created. Some field trials are configured to override or
  // associate with (for reporting) specific features. These associations are
  // registered with |feature_list|. Returns true if trials were created
  // successfully; and if so, stores the loaded variations state into the
  // |safe_seed_manager|.
  bool CreateTrialsFromSeed(const EntropyProviders& entropy_providers,
                            base::FeatureList* feature_list,
                            SafeSeedManagerBase* safe_seed_manager,
                            SyntheticTrialRegistry* synthetic_trial_registry,
                            std::unique_ptr<ClientFilterableState> state);

  // Reads a seed's data and signature from the file at |json_seed_path| and
  // writes them to Local State. Exits Chrome if (A) the file's contents can't
  // be loaded or (B) if the contents do not contain |kVariationsCompressedSeed|
  // or |kVariationsSeedSignature|. Also forces Chrome to not run in variations
  // safe mode. Used for variations seed testing.
  void LoadSeedFromJsonFile(const base::FilePath& json_seed_path);

  // Returns whether the conditions to activate the limited entropy synthetic
  // trial are met.
  bool ShouldActivateLimitedEntropySyntheticTrial(const VariationsSeed& seed);

  // Registers the group assignment of the limited entropy synthetic trial if
  // the activation condition are met (as given by
  // ShouldActivateLimitedEntropySyntheticTrial()).
  void RegisterLimitedEntropySyntheticTrialIfNeeded(
      const VariationsSeed& seed,
      SyntheticTrialRegistry* synthetic_trial_registry);

  // Returns the seed store. Virtual for testing.
  virtual VariationsSeedStore* GetSeedStore();

  PrefService* local_state() { return seed_store_->local_state(); }
  const PrefService* local_state() const { return seed_store_->local_state(); }

  raw_ptr<VariationsServiceClient> client_;

  std::unique_ptr<VariationsSeedStore> seed_store_;

  // Seed type used for variations.
  SeedType seed_type_ = SeedType::kNullSeed;

  // Tracks whether |CreateTrialsFromSeed| has been called, to ensure that it is
  // called at most once.
  bool create_trials_from_seed_called_;

  // The application locale won't change after the startup, so we cache the
  // value the first time when GetApplicationLocale() is called in the
  // constructor.
  std::string application_locale_;

  // Indicate if OverrideVariationsPlatform has been used to set
  // |platform_override_|.
  bool has_platform_override_;

  // Platform to be used for variations filtering, overriding the current
  // platform.
  Study::Platform platform_override_;

  // Caches the UI strings which need to be overridden in the resource bundle.
  // These strings are cached before the resource bundle is initialized.
  std::unordered_map<int, std::u16string> overridden_strings_map_;

  // Configurations related to the limited entropy synthetic trial.
  raw_ptr<LimitedEntropySyntheticTrial> limited_entropy_synthetic_trial_;

  // Holds the country code to use for filtering permanent consistency studies
  std::string permanent_consistency_country_;

  // Tracks whether |permanent_consistency_country_| has been initialized to
  // ensure it contains a relevant value.
  bool permanent_consistency_country_initialized_ = false;

  SEQUENCE_CHECKER(sequence_checker_);
};

// A testing feature that forces a crash during field trial creation
// on developer and test builds.
BASE_DECLARE_FEATURE(kForceFieldTrialSetupCrashForTesting);

}  // namespace variations

#endif  // COMPONENTS_VARIATIONS_SERVICE_VARIATIONS_FIELD_TRIAL_CREATOR_BASE_H_