variations_ids_provider.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // Copyright 2014 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. #ifndef COMPONENTS_VARIATIONS_VARIATIONS_IDS_PROVIDER_H_
  5. #define COMPONENTS_VARIATIONS_VARIATIONS_IDS_PROVIDER_H_
  6. #include <map>
  7. #include <set>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11. #include "base/component_export.h"
  12. #include "base/gtest_prod_util.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/metrics/field_trial.h"
  15. #include "base/observer_list.h"
  16. #include "base/synchronization/lock.h"
  17. #include "components/variations/proto/study.pb.h"
  18. #include "components/variations/synthetic_trials.h"
  19. #include "components/variations/variations.mojom.h"
  20. #include "components/variations/variations_associated_data.h"
  21. namespace variations {
  22. class VariationsClient;
  23. // The key for a VariationsIdsProvider's |variations_headers_map_|. A
  24. // VariationsHeaderKey provides more details about the VariationsIDs included in
  25. // a particular header. For example, the header associated with a key with true
  26. // for |is_signed_in| and Study_GoogleWebVisibility_ANY for |web_visibility| has
  27. // (i) VariationsIDs associated with external experiments, which can be sent
  28. // only for signed-in users and (ii) VariationsIDs that can be sent in first-
  29. // and third-party contexts.
  30. struct COMPONENT_EXPORT(VARIATIONS) VariationsHeaderKey {
  31. bool is_signed_in;
  32. Study_GoogleWebVisibility web_visibility;
  33. // This allows the struct to be used as a key in a map.
  34. bool operator<(const VariationsHeaderKey& other) const;
  35. };
  36. // A helper class for maintaining client experiments and metrics state
  37. // transmitted in custom HTTP request headers.
  38. // This class is a thread-safe singleton.
  39. class COMPONENT_EXPORT(VARIATIONS) VariationsIdsProvider
  40. : public base::FieldTrialList::Observer,
  41. public SyntheticTrialObserver {
  42. public:
  43. class COMPONENT_EXPORT(VARIATIONS) Observer {
  44. public:
  45. // Called when variation ids headers are updated.
  46. virtual void VariationIdsHeaderUpdated() = 0;
  47. protected:
  48. virtual ~Observer() {}
  49. };
  50. enum class Mode {
  51. // Indicates the signed-in parameter supplied to GetClientDataHeaders() is
  52. // honored.
  53. kUseSignedInState,
  54. // Indicates the signed-in parameter supplied to GetClientDataHeaders() is
  55. // treated as true, regardless of what is supplied. This is intended for
  56. // embedders (such as WebLayer) that do not have the notion of signed-in.
  57. kIgnoreSignedInState,
  58. // Indicates the signed-in parameter supplied to GetClientDataHeaders() is
  59. // treated as false, regardless of what is supplied.
  60. kDontSendSignedInVariations,
  61. };
  62. // Creates the VariationsIdsProvider instance. This must be called before
  63. // GetInstance(). Only one instance of VariationsIdsProvider may be created.
  64. static VariationsIdsProvider* Create(Mode mode);
  65. static VariationsIdsProvider* GetInstance();
  66. VariationsIdsProvider(const VariationsIdsProvider&) = delete;
  67. VariationsIdsProvider& operator=(const VariationsIdsProvider&) = delete;
  68. Mode mode() const { return mode_; }
  69. // Returns the X-Client-Data headers corresponding to |is_signed_in|: a header
  70. // that may be sent in first-party requests and a header that may be sent in
  71. // third-party requests. For more details, see IsFirstPartyContext() in
  72. // variations_http_headers.cc.
  73. //
  74. // If |is_signed_in| is false, VariationIDs that should be sent for only
  75. // signed in users (i.e. GOOGLE_WEB_PROPERTIES_SIGNED_IN entries) are not
  76. // included. Also, computes and caches the header if necessary. |is_signed_in|
  77. // is impacted by the Mode supplied when VariationsIdsProvider is created.
  78. // See Mode for details.
  79. variations::mojom::VariationsHeadersPtr GetClientDataHeaders(
  80. bool is_signed_in);
  81. // Returns a space-separated string containing the list of current active
  82. // variations (as would be reported in the |variation_id| repeated field of
  83. // the ClientVariations proto). Does not include variation ids that should be
  84. // sent for signed-in users only and does not include Google app variations.
  85. // The returned string is guaranteed to have a leading and trailing space,
  86. // e.g. " 123 234 345 ".
  87. std::string GetVariationsString();
  88. // Same as GetVariationString(), but returns Google App variation ids rather
  89. // than Google Web variations.
  90. // IMPORTANT: This string is only approved for integrations with the Android
  91. // Google App and must receive a privacy review before extending to other
  92. // apps.
  93. std::string GetGoogleAppVariationsString();
  94. // Returns the collection of VariationIDs associated with |keys|. Each entry
  95. // in the returned vector is unique.
  96. std::vector<VariationID> GetVariationsVector(
  97. const std::set<IDCollectionKey>& keys);
  98. // Returns the collection of variations ids for all Google Web Properties
  99. // related keys.
  100. std::vector<VariationID> GetVariationsVectorForWebPropertiesKeys();
  101. // Sets low entropy source value that was used for client-side randomization
  102. // of variations.
  103. void SetLowEntropySourceValue(absl::optional<int> low_entropy_source_value);
  104. // Result of ForceVariationIds() call.
  105. enum class ForceIdsResult {
  106. SUCCESS,
  107. INVALID_VECTOR_ENTRY, // Invalid entry in |variation_ids|.
  108. INVALID_SWITCH_ENTRY, // Invalid entry in |command_line_variation_ids|.
  109. };
  110. // Sets *additional* variation ids and trigger variation ids to be encoded in
  111. // the X-Client-Data request header. This is intended for development use to
  112. // force a server side experiment id. |variation_ids| should be a list of
  113. // strings of numeric experiment ids. Ids explicitly passed in |variation_ids|
  114. // and those in the comma-separated |command_line_variation_ids| are added.
  115. ForceIdsResult ForceVariationIds(
  116. const std::vector<std::string>& variation_ids,
  117. const std::string& command_line_variation_ids);
  118. // Ensures that the given variation ids and trigger variation ids are not
  119. // encoded in the X-Client-Data request header. This is intended for
  120. // development use to force that a server side experiment id is not set.
  121. // |command_line_variation_ids| are comma-separted experiment ids.
  122. // Returns true on success.
  123. bool ForceDisableVariationIds(const std::string& command_line_variation_ids);
  124. // Methods to register or remove observers of variation ids header update.
  125. void AddObserver(Observer* observer);
  126. void RemoveObserver(Observer* observer);
  127. // Resets any cached state for tests.
  128. void ResetForTesting();
  129. private:
  130. typedef std::pair<VariationID, IDCollectionKey> VariationIDEntry;
  131. friend class ScopedVariationsIdsProvider;
  132. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, ForceVariationIds_Valid);
  133. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
  134. ForceVariationIds_ValidCommandLine);
  135. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
  136. ForceVariationIds_Invalid);
  137. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
  138. ForceDisableVariationIds_ValidCommandLine);
  139. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
  140. ForceDisableVariationIds_Invalid);
  141. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTestWithRestrictedVisibility,
  142. OnFieldTrialGroupFinalized);
  143. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTestWithRestrictedVisibility,
  144. LowEntropySourceValue_Valid);
  145. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTestWithRestrictedVisibility,
  146. LowEntropySourceValue_Null);
  147. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
  148. GetGoogleAppVariationsString);
  149. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, GetVariationsString);
  150. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, GetVariationsVector);
  151. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
  152. GetVariationsVectorForWebPropertiesKeys);
  153. FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, GetVariationsVectorImpl);
  154. explicit VariationsIdsProvider(Mode mode);
  155. ~VariationsIdsProvider() override;
  156. static void CreateInstanceForTesting(Mode mode);
  157. static void DestroyInstanceForTesting();
  158. // Returns a space-separated string containing the list of current active
  159. // variations (as would be reported in the |variation_id| repeated field of
  160. // the ClientVariations proto) for a given ID collection.
  161. std::string GetVariationsString(const std::set<IDCollectionKey>& keys);
  162. // base::FieldTrialList::Observer:
  163. // This will add the variation ID associated with |trial_name| and
  164. // |group_name| to the variation ID cache.
  165. void OnFieldTrialGroupFinalized(const std::string& trial_name,
  166. const std::string& group_name) override;
  167. // metrics::SyntheticTrialObserver:
  168. void OnSyntheticTrialsChanged(
  169. const std::vector<SyntheticTrialGroup>& groups) override;
  170. // Prepares the variation IDs cache with initial values if not already done.
  171. // This method also registers the caller with the FieldTrialList to receive
  172. // new variation IDs.
  173. void InitVariationIDsCacheIfNeeded();
  174. // Looks up the VariationID associated with |trial_name| and |group_name|, and
  175. // if found, adds an entry for it to |variation_ids_set_|.
  176. void CacheVariationsId(const std::string& trial_name,
  177. const std::string& group_name);
  178. // Takes whatever is currently in |variation_ids_set_| and recreates
  179. // |variation_ids_header_| with it. Assumes the the |lock_| is currently
  180. // held.
  181. void UpdateVariationIDsHeaderValue();
  182. // Generates a base64-encoded ClientVariations proto to be used as a header
  183. // value for the given |is_signed_in| and |is_first_party_context| states.
  184. std::string GenerateBase64EncodedProto(bool is_signed_in,
  185. bool is_first_party_context);
  186. // Adds variation ids and trigger variation ids to |target_set|. If
  187. // |should_dedupe| is true, the ids in |variation_ids| that have already been
  188. // added as non-Google-app ids are not added to |target_set|. Returns false if
  189. // any variation ids are malformed or duplicated. Returns true otherwise.
  190. bool AddVariationIdsToSet(const std::vector<std::string>& variation_ids,
  191. bool should_dedupe,
  192. std::set<VariationIDEntry>* target_set);
  193. // Parses a comma-separated string of variation ids and trigger variation ids
  194. // and adds them to |target_set|. If |should_dedupe| is true, ids that have
  195. // already been added as non-Google-app ids are not added to |target_set|.
  196. // Returns false if any variation ids are malformed or duplicated. Returns
  197. // true otherwise.
  198. bool ParseVariationIdsParameter(const std::string& command_line_variation_ids,
  199. bool should_dedupe,
  200. std::set<VariationIDEntry>* target_set);
  201. // Returns the value of the X-Client-Data header corresponding to
  202. // |is_signed_in| and |web_visibility|. Considering |web_visibility| may allow
  203. // fewer VariationIDs to be sent in third-party contexts.
  204. std::string GetClientDataHeaderWhileLocked(
  205. bool is_signed_in,
  206. Study_GoogleWebVisibility web_visibility);
  207. // Returns the currently active set of variation ids, which includes ids from
  208. // field trials, synthetic trials, and forced ids.
  209. std::set<VariationIDEntry> GetAllVariationIds();
  210. // Returns the collection of variation ids matching any of the given
  211. // |keys|. Each entry in the returned vector will be unique.
  212. std::vector<VariationID> GetVariationsVectorImpl(
  213. const std::set<IDCollectionKey>& key);
  214. // Returns whether |id| has already been added to the active set of variation
  215. // ids. This includes ids from field trials, synthetic trials, and forced ids.
  216. // Note that Google app ids are treated differently. They may be reused as a
  217. // Google Web id.
  218. bool IsDuplicateId(VariationID id);
  219. const Mode mode_;
  220. // Guards access to variables below.
  221. base::Lock lock_;
  222. // Low entropy source value from client that was used for client-side
  223. // randomization of variations.
  224. absl::optional<int> low_entropy_source_value_;
  225. // Whether or not we've initialized the caches.
  226. bool variation_ids_cache_initialized_;
  227. // Keep a cache of variation IDs that are transmitted in headers to Google.
  228. // This consists of a list of valid IDs, and the actual transmitted header.
  229. std::set<VariationIDEntry> variation_ids_set_;
  230. // Provides the google experiment ids that are force-enabled through
  231. // ForceVariationIds().
  232. std::set<VariationIDEntry> force_enabled_ids_set_;
  233. // Variations ids from synthetic field trials.
  234. std::set<VariationIDEntry> synthetic_variation_ids_set_;
  235. // Provides the google experiment ids that are force-disabled by command line.
  236. std::set<VariationIDEntry> force_disabled_ids_set_;
  237. // A collection of variations headers. Each header is a base64-encoded
  238. // ClientVariations proto containing VariationIDs that may be sent to Google
  239. // web properties. For more details about when this may be sent, see
  240. // AppendHeaderIfNeeded() in variations_http_headers.cc.
  241. //
  242. // The key for each header describes the VariationIDs included in its
  243. // associated header. See VariationsHeaderKey's comments for more information.
  244. std::map<VariationsHeaderKey, std::string> variations_headers_map_
  245. GUARDED_BY(lock_);
  246. // List of observers to notify on variation ids header update.
  247. // NOTE this should really check observers are unregistered but due to
  248. // https://crbug.com/1051937 this isn't currently possible.
  249. base::ObserverList<Observer>::Unchecked observer_list_;
  250. raw_ptr<const VariationsClient> variations_client_ = nullptr;
  251. };
  252. } // namespace variations
  253. #endif // COMPONENTS_VARIATIONS_VARIATIONS_IDS_PROVIDER_H_