// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
option java_package = "org.chromium.components.variations";
package variations;
// A Layer divides Variations clients into disjoint LayerMembers based on client
// entropy values, allowing potentially conflicting studies to be performed on
// separate client subsets.
// Each layer consists of N slots, and each Chrome client instance will randomly
// select a specific slot to be "active" within that layer based on the layer's
// salt and the client's entropy source value. That slot will be part of a range
// within a specific LayerMember. Each study that participates in a layer points
// to a particular LayerMember within that layer. Only the studies pointing to
// the active LayerMember will be active for a given client.
// Example:
// LayerFoo:
// num_slots=10: |0, 1, 2, 3, 4, 5, 6, 7, 8, 9|
// LayerMembers: <0 - 3>, <4 - 9>
// ^Member1^ ^Member2^.
//
// In this example, the Member1 LayerMember has four slots and
// Member2 has six out of ten total. This means studies pointing to
// Member1 will receive ~40% of the population and Member2 ~60%.
// Next tag: 6
message Layer {
message LayerMember {
message SlotRange {
// First slot in the range (inclusive). This range has to be
// in the [0..`num_slots`) range of the layer.
optional uint32 start = 1;
// Last slot in the range (inclusive).
optional uint32 end = 2;
}
// An id (unique within the Layer) that studies will use to refer to this
// particular member.
optional uint32 id = 1;
// Ranges of slots that belong to this member. These slot ranges must not
// overlap with the slot ranges of other members within the layer, so
// that at most one member within the layer will be active. The ranges must
// be listed in increasing order.
repeated SlotRange slots = 2;
}
// ID for the layer, must be unique across all layers. Studies will specify
// a <layer_id, layer_member_id> pair to become part of a layer.
optional uint32 id = 1;
// Total number of slots within the layer. There are constraints on the number
// of slots when a low entropy source is used (100, initially) to alleviate
// skew in the bucket populations.
optional uint32 num_slots = 2;
// Layer members, which occupy disjoint subsets of the [0, `num_slots`) range.
// Not all slots have to be used, and normally won't in order to reserve space
// within the layer. Each study that participates in a layer is associated
// with a single layer member.
repeated LayerMember members = 3;
// A salt which is used as an input to a hash function together with the
// output of the chosen entropy source, to choose an active slot within the
// layer. If salt is unset or 0, the layer id will be used instead.
optional uint32 salt = 4;
enum EntropyMode {
// Use the default entropy source when selecting slots. This will use the
// high entropy source for the clients that have it, and falls back to the
// low entropy source for other clients.
DEFAULT = 0;
// Use the low entropy source.
LOW = 1;
// Use the limited entropy source.
LIMITED = 2;
}
// Which of the above entropy modes should be used to select a slot.
optional EntropyMode entropy_mode = 5;
}
// A Study can optionally specify a LayerMemberReference which will constrain it
// to one or more layer members of the specified layer.
message LayerMemberReference {
// Reference to the layer with this specific ID.
optional uint32 layer_id = 1;
// References to members within the above layer.
//
// New code should use `layer_member_ids` instead. Older clients only support
// `layer_member_id`, and values in `layer_member_ids` are ignored. Newer
// clients support both fields for backward compatibility. A study that uses
// `layer_member_ids` needs to have a `min_version` that is greater than
// the minimum version that supports `layer_member_ids`.
// TODO(crbug.com/345611804): Amend this comment with the minimum version when
// it is known.
//
// Specifying more than one `layer_member_id` can be used to adjust the active
// percentage of a study:
// - Adding a `layer_member_id` will result in clients randomized to that
// layer member to be part of this study (and be randomized into its
// groups).
// - Removing a `layer_member_id` will take out clients randomized to that
// layer member from the study.
//
optional uint32 layer_member_id = 2;
repeated uint32 layer_member_ids = 3 [packed = true];
}