#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include <initializer_list>
#include <optional>
#include <random>
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/no_destructor.h"
#include "base/synchronization/atomic_flag.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings_provider.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
namespace blink {
namespace {
bool IdentifiabilityTracingEnabled() {
bool tracing_enabled;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("identifiability"), &tracing_enabled);
return tracing_enabled;
}
class ThreadsafeSettingsWrapper {
public:
ThreadsafeSettingsWrapper() = default;
const IdentifiabilityStudySettings* GetSettings() {
if (!initialized_.IsSet())
return &default_settings_;
return &initialized_settings_.value();
}
void SetProvider(
std::unique_ptr<IdentifiabilityStudySettingsProvider> provider) {
DCHECK(!initialized_.IsSet());
initialized_settings_.emplace(std::move(provider));
initialized_.Set();
}
void ResetStateForTesting() {
initialized_settings_.reset();
initialized_.UnsafeResetForTesting();
}
static ThreadsafeSettingsWrapper* GetWrapper() {
static base::NoDestructor<ThreadsafeSettingsWrapper> wrapper;
return wrapper.get();
}
private:
std::optional<IdentifiabilityStudySettings> initialized_settings_;
const IdentifiabilityStudySettings default_settings_;
base::AtomicFlag initialized_;
};
}
IdentifiabilityStudySettingsProvider::~IdentifiabilityStudySettingsProvider() =
default;
IdentifiabilityStudySettings::IdentifiabilityStudySettings() = default;
IdentifiabilityStudySettings::IdentifiabilityStudySettings(
std::unique_ptr<IdentifiabilityStudySettingsProvider> provider)
: provider_(std::move(provider)),
is_enabled_(provider_->IsActive()),
is_any_surface_or_type_blocked_(provider_->IsAnyTypeOrSurfaceBlocked()),
is_meta_experiment_active_(provider_->IsMetaExperimentActive()) {}
IdentifiabilityStudySettings::~IdentifiabilityStudySettings() = default;
const IdentifiabilityStudySettings* IdentifiabilityStudySettings::Get() {
return ThreadsafeSettingsWrapper::GetWrapper()->GetSettings();
}
void IdentifiabilityStudySettings::SetGlobalProvider(
std::unique_ptr<IdentifiabilityStudySettingsProvider> provider) {
ThreadsafeSettingsWrapper::GetWrapper()->SetProvider(std::move(provider));
}
void IdentifiabilityStudySettings::ResetStateForTesting() {
ThreadsafeSettingsWrapper::GetWrapper()->ResetStateForTesting();
}
bool IdentifiabilityStudySettings::IsActive() const {
return is_enabled_ || is_meta_experiment_active_;
}
bool IdentifiabilityStudySettings::ShouldSampleWebFeature(
mojom::WebFeature feature) const {
return ShouldSampleSurface(IdentifiableSurface::FromTypeAndToken(
IdentifiableSurface::Type::kWebFeature, feature));
}
bool IdentifiabilityStudySettings::ShouldSampleSurface(
IdentifiableSurface surface) const {
if (!ShouldSampleAnything()) [[likely]] {
return false;
}
if (!is_any_surface_or_type_blocked_) [[likely]] {
return true;
}
if (is_meta_experiment_active_) {
return true;
}
return provider_->IsSurfaceAllowed(surface);
}
bool IdentifiabilityStudySettings::ShouldSampleType(
IdentifiableSurface::Type type) const {
if (!ShouldSampleAnything()) [[likely]] {
return false;
}
if (!is_any_surface_or_type_blocked_) [[likely]] {
return true;
}
if (is_meta_experiment_active_) {
return true;
}
return provider_->IsTypeAllowed(type);
}
bool IdentifiabilityStudySettings::ShouldSampleAnything() const {
return IsActive() || IdentifiabilityTracingEnabled();
}
}