blob: 506dffedb18daaa786f94df5f15d332573386b28 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Provides functions for associating FieldTrials with Google VariationIDs and
// time windows.
//
// Example usage:
//
// AssociateGoogleVariationID(
// GOOGLE_WEB_PROPERTIES_FIRST_PARTY, "MyStudy", "TreatmentGroup", 1234);
//
// VariationID id = GetGoogleVariationID(
// GOOGLE_WEB_PROPERTIES_FIRST_PARTY, "MyStudy", "TreatmentGroup");
#ifndef COMPONENTS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_
#define COMPONENTS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_
#include <map>
#include <memory>
#include <optional>
#include <string_view>
#include "base/metrics/field_trial.h"
#include "base/time/time.h"
#include "components/variations/active_field_trials.h"
namespace variations {
typedef int VariationID;
// A time window is used to timebox a VariationID. Each VariationID will be
// transmitted via the X-Client-Data header only when the current time is
// between the (inclusive) start and end timestamps of the TimeWindow for that
// VariationID. These times are network times. The client should makes its best
// effort to use a network synchronized time source when comparing the
// `current_time` to the start and end timestamps of a TimeWindow.
class COMPONENT_EXPORT(VARIATIONS) TimeWindow {
public:
TimeWindow() = default;
// Creates a TimeWindow with the given `start` and `end` times. The `start`
// time must be strictly less than the `end` time, otherwise the TimeWindow
// is empty/invalid (i.e. has zero duration).
TimeWindow(base::Time start, base::Time end)
: start_(start), end_(end) {}
// Copyable and moveable.
TimeWindow(const TimeWindow& other) = default;
TimeWindow(TimeWindow&& other) = default;
TimeWindow& operator=(const TimeWindow& other) = default;
TimeWindow& operator=(TimeWindow&& other) = default;
// Returns the start and end times of the TimeWindow. These times are
// best-effort network times.
base::Time start() const { return start_; }
base::Time end() const { return end_; }
// Returns true if the TimeWindow is valid (i.e. the start time is less than
// the end time).
bool IsValid() const { return start_ < end_; }
// Returns true if the `time` is within the TimeWindow and the TimeWindow is
// valid (non-empty).
bool Contains(base::Time time) const {
return (start_ <= time) && (time <= end_) && (start_ < end_);
}
private:
base::Time start_ = base::Time::Min();
base::Time end_ = base::Time::Max();
};
const VariationID EMPTY_ID = 0;
// A key into the Associate/Get methods for VariationIDs. This is used to create
// separate ID associations for separate parties interested in VariationIDs.
enum IDCollectionKey {
// The IDs in this collection are used by Google web properties and are
// transmitted via the X-Client-Data header. These IDs are transmitted in
// first- and third-party contexts.
GOOGLE_WEB_PROPERTIES_ANY_CONTEXT,
// The IDs in this collection are used by Google web properties and are
// transmitted via the X-Client-Data header. Transmitted in only first-party
// contexts.
GOOGLE_WEB_PROPERTIES_FIRST_PARTY,
// This collection is used by Google web properties for signed in users only,
// transmitted through the X-Client-Data header.
GOOGLE_WEB_PROPERTIES_SIGNED_IN,
// The IDs in this collection are used by Google web properties to trigger
// server-side experimental behavior and are transmitted via the X-Client-Data
// header. These IDs are transmitted in first- and third-party contexts.
GOOGLE_WEB_PROPERTIES_TRIGGER_ANY_CONTEXT,
// The IDs in this collection are used by Google web properties to trigger
// server-side experimental behavior and are transmitted via the X-Client-Data
// header. Transmitted in only first-party contexts.
GOOGLE_WEB_PROPERTIES_TRIGGER_FIRST_PARTY,
// This collection is used by the Google App and is passed at the time
// the cross-app communication is triggered.
GOOGLE_APP,
// The total count of collections.
ID_COLLECTION_COUNT,
};
// Associate a variations::VariationID value with a FieldTrial group for
// collection |key|. If an id was previously set for |trial_name| and
// |group_name|, it is overwritten. The group is denoted by |trial_name| and
// |group_name|. This must be called whenever a FieldTrial is prepared (create
// the trial and append groups) and needs to have a variations::VariationID
// associated with it so Google servers can recognize the FieldTrial. The
// transmission of the VariationID will be limited to the |time_window|.
// Thread safe.
COMPONENT_EXPORT(VARIATIONS)
void AssociateGoogleVariationID(IDCollectionKey key,
std::string_view trial_name,
std::string_view group_name,
VariationID variation_id,
TimeWindow time_window = TimeWindow());
// As above, but takes an ActiveGroupId hash pair, rather than the string names.
COMPONENT_EXPORT(VARIATIONS)
void AssociateGoogleVariationID(
IDCollectionKey key,
ActiveGroupId active_group_id,
VariationID variation_id,
TimeWindow time_window = TimeWindow());
// Retrieve the variations::VariationID associated with a FieldTrial group for
// collection |key|. The group is denoted by |trial_name| and |group_name|.
// This will return variations::EMPTY_ID if there is currently no associated ID
// for the named group. This API can be nicely combined with
// FieldTrial::GetActiveFieldTrialGroups() to enumerate the variation IDs for
// all active FieldTrial groups. If a |current_time| is provided, the
// VariationID will be returned only if the current time is between the
// (inclusive) start and end timestamps of the TimeWindow for that VariationID.
// Thread safe.
COMPONENT_EXPORT(VARIATIONS)
VariationID GetGoogleVariationID(
IDCollectionKey key,
std::string_view trial_name,
std::string_view group_name,
std::optional<base::Time> current_time = std::nullopt);
// Same as GetGoogleVariationID(), but takes in a hashed |active_group_id|
// rather than the string trial and group name.
COMPONENT_EXPORT(VARIATIONS)
VariationID GetGoogleVariationID(
IDCollectionKey key,
ActiveGroupId active_group_id,
std::optional<base::Time> current_time = std::nullopt);
// Returns the next time after the given time that a time window will start or
// end for a VariationID.
COMPONENT_EXPORT(VARIATIONS)
base::Time GetNextTimeWindowEvent(base::Time time);
// Expose some functions for testing.
namespace testing {
// Clears all of the mapped associations. Deprecated, use ScopedFeatureList
// instead as it does a lot of work for you automatically.
COMPONENT_EXPORT(VARIATIONS) void ClearAllVariationIDs();
// Clears all of the associated params. Deprecated, use ScopedFeatureList
// instead as it does a lot of work for you automatically.
COMPONENT_EXPORT(VARIATIONS) void ClearAllVariationParams();
} // namespace testing
} // namespace variations
#endif // COMPONENTS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_