variations_layers.cc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright 2020 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 "components/variations/variations_layers.h"
  5. #include "base/metrics/field_trial.h"
  6. namespace variations {
  7. namespace {
  8. // Returns a double in the [0, 1] range to be used to select a slot within
  9. // a layer with the given randomization seed value.
  10. double GetEntropyForLayer(
  11. const base::FieldTrial::EntropyProvider* entropy_provider,
  12. uint32_t randomization_seed) {
  13. // GetEntropyForTrial will ignore the trial_name parameter in favor of the
  14. // randomization_seed.
  15. return entropy_provider->GetEntropyForTrial(/*trial_name=*/"",
  16. randomization_seed);
  17. }
  18. // Iterates through the members of the given layer proto definition, and
  19. // returns the ID of the member which contains that slot (if any).
  20. absl::optional<uint32_t> FindActiveMemberBySlot(uint32_t chosen_slot,
  21. const Layer& layer_proto) {
  22. for (const Layer::LayerMember& member : layer_proto.members()) {
  23. if (!member.id())
  24. continue;
  25. for (const Layer::LayerMember::SlotRange& slot : member.slots()) {
  26. if (slot.start() <= chosen_slot && chosen_slot <= slot.end())
  27. return member.id();
  28. }
  29. }
  30. return absl::nullopt;
  31. }
  32. } // namespace
  33. VariationsLayers::LayerInfo::LayerInfo(
  34. absl::optional<uint32_t> active_member_id,
  35. Layer::EntropyMode entropy_mode)
  36. : active_member_id(active_member_id), entropy_mode(entropy_mode) {}
  37. VariationsLayers::LayerInfo::~LayerInfo() = default;
  38. VariationsLayers::LayerInfo::LayerInfo(const LayerInfo& other) {
  39. active_member_id = other.active_member_id;
  40. entropy_mode = other.entropy_mode;
  41. }
  42. VariationsLayers::VariationsLayers(
  43. const VariationsSeed& seed,
  44. const base::FieldTrial::EntropyProvider* low_entropy_provider) {
  45. if (!low_entropy_provider) {
  46. // Android WebView does not support low-entropy field trials.
  47. return;
  48. }
  49. // TODO(crbug.com/1154033): Support a way to expire old/unused layers so they
  50. // no longer get processed by the clients.
  51. for (const Layer& layer_proto : seed.layers())
  52. ConstructLayer(*low_entropy_provider, layer_proto);
  53. }
  54. VariationsLayers::VariationsLayers() = default;
  55. VariationsLayers::~VariationsLayers() = default;
  56. void VariationsLayers::ConstructLayer(
  57. const base::FieldTrial::EntropyProvider& low_entropy_provider,
  58. const Layer& layer_proto) {
  59. if (layer_proto.id() == 0 || layer_proto.num_slots() == 0 ||
  60. layer_proto.members_size() == 0) {
  61. return;
  62. }
  63. double entropy_value;
  64. if (layer_proto.entropy_mode() == Layer::LOW) {
  65. entropy_value =
  66. GetEntropyForLayer(&low_entropy_provider, layer_proto.salt());
  67. } else {
  68. const base::FieldTrial::EntropyProvider* default_entropy_provider =
  69. base::FieldTrialList::GetEntropyProviderForOneTimeRandomization();
  70. CHECK(default_entropy_provider);
  71. entropy_value =
  72. GetEntropyForLayer(default_entropy_provider, layer_proto.salt());
  73. }
  74. const double kEpsilon = 1e-8;
  75. // Add a tiny epsilon to get consistent values when converting the double
  76. // to the integer slots; see comment in
  77. // base::FieldTrialList::GetGroupBoundaryValue() for more details.
  78. uint32_t chosen_slot = std::min(
  79. static_cast<uint32_t>(layer_proto.num_slots() * entropy_value + kEpsilon),
  80. layer_proto.num_slots() - 1);
  81. active_member_for_layer_.emplace(
  82. layer_proto.id(),
  83. LayerInfo{FindActiveMemberBySlot(chosen_slot, layer_proto),
  84. layer_proto.entropy_mode()});
  85. }
  86. bool VariationsLayers::IsLayerMemberActive(uint32_t layer_id,
  87. uint32_t member_id) const {
  88. auto layer_iter = active_member_for_layer_.find(layer_id);
  89. if (layer_iter == active_member_for_layer_.end())
  90. return false;
  91. return layer_iter->second.active_member_id &&
  92. (member_id == layer_iter->second.active_member_id.value());
  93. }
  94. bool VariationsLayers::IsLayerUsingDefaultEntropy(uint32_t layer_id) const {
  95. auto layer_iter = active_member_for_layer_.find(layer_id);
  96. if (layer_iter == active_member_for_layer_.end())
  97. return false;
  98. return layer_iter->second.entropy_mode == Layer::DEFAULT;
  99. }
  100. } // namespace variations