123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/variations/variations_layers.h"
- #include "base/metrics/field_trial.h"
- namespace variations {
- namespace {
- // Returns a double in the [0, 1] range to be used to select a slot within
- // a layer with the given randomization seed value.
- double GetEntropyForLayer(
- const base::FieldTrial::EntropyProvider* entropy_provider,
- uint32_t randomization_seed) {
- // GetEntropyForTrial will ignore the trial_name parameter in favor of the
- // randomization_seed.
- return entropy_provider->GetEntropyForTrial(/*trial_name=*/"",
- randomization_seed);
- }
- // Iterates through the members of the given layer proto definition, and
- // returns the ID of the member which contains that slot (if any).
- absl::optional<uint32_t> FindActiveMemberBySlot(uint32_t chosen_slot,
- const Layer& layer_proto) {
- for (const Layer::LayerMember& member : layer_proto.members()) {
- if (!member.id())
- continue;
- for (const Layer::LayerMember::SlotRange& slot : member.slots()) {
- if (slot.start() <= chosen_slot && chosen_slot <= slot.end())
- return member.id();
- }
- }
- return absl::nullopt;
- }
- } // namespace
- VariationsLayers::LayerInfo::LayerInfo(
- absl::optional<uint32_t> active_member_id,
- Layer::EntropyMode entropy_mode)
- : active_member_id(active_member_id), entropy_mode(entropy_mode) {}
- VariationsLayers::LayerInfo::~LayerInfo() = default;
- VariationsLayers::LayerInfo::LayerInfo(const LayerInfo& other) {
- active_member_id = other.active_member_id;
- entropy_mode = other.entropy_mode;
- }
- VariationsLayers::VariationsLayers(
- const VariationsSeed& seed,
- const base::FieldTrial::EntropyProvider* low_entropy_provider) {
- if (!low_entropy_provider) {
- // Android WebView does not support low-entropy field trials.
- return;
- }
- // TODO(crbug.com/1154033): Support a way to expire old/unused layers so they
- // no longer get processed by the clients.
- for (const Layer& layer_proto : seed.layers())
- ConstructLayer(*low_entropy_provider, layer_proto);
- }
- VariationsLayers::VariationsLayers() = default;
- VariationsLayers::~VariationsLayers() = default;
- void VariationsLayers::ConstructLayer(
- const base::FieldTrial::EntropyProvider& low_entropy_provider,
- const Layer& layer_proto) {
- if (layer_proto.id() == 0 || layer_proto.num_slots() == 0 ||
- layer_proto.members_size() == 0) {
- return;
- }
- double entropy_value;
- if (layer_proto.entropy_mode() == Layer::LOW) {
- entropy_value =
- GetEntropyForLayer(&low_entropy_provider, layer_proto.salt());
- } else {
- const base::FieldTrial::EntropyProvider* default_entropy_provider =
- base::FieldTrialList::GetEntropyProviderForOneTimeRandomization();
- CHECK(default_entropy_provider);
- entropy_value =
- GetEntropyForLayer(default_entropy_provider, layer_proto.salt());
- }
- const double kEpsilon = 1e-8;
- // Add a tiny epsilon to get consistent values when converting the double
- // to the integer slots; see comment in
- // base::FieldTrialList::GetGroupBoundaryValue() for more details.
- uint32_t chosen_slot = std::min(
- static_cast<uint32_t>(layer_proto.num_slots() * entropy_value + kEpsilon),
- layer_proto.num_slots() - 1);
- active_member_for_layer_.emplace(
- layer_proto.id(),
- LayerInfo{FindActiveMemberBySlot(chosen_slot, layer_proto),
- layer_proto.entropy_mode()});
- }
- bool VariationsLayers::IsLayerMemberActive(uint32_t layer_id,
- uint32_t member_id) const {
- auto layer_iter = active_member_for_layer_.find(layer_id);
- if (layer_iter == active_member_for_layer_.end())
- return false;
- return layer_iter->second.active_member_id &&
- (member_id == layer_iter->second.active_member_id.value());
- }
- bool VariationsLayers::IsLayerUsingDefaultEntropy(uint32_t layer_id) const {
- auto layer_iter = active_member_for_layer_.find(layer_id);
- if (layer_iter == active_member_for_layer_.end())
- return false;
- return layer_iter->second.entropy_mode == Layer::DEFAULT;
- }
- } // namespace variations
|