blob: 4709640af158d120eadf498f277443df613d789f [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SERVICE_IMPL_H_
#define CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SERVICE_IMPL_H_
// clang-format off
#include "chrome/browser/privacy_sandbox/notice/notice_definitions.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_countries.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
// clang-format on
#include <set>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/privacy_sandbox/canonical_topic.h"
#include "components/privacy_sandbox/privacy_sandbox_settings.h"
#include "components/privacy_sandbox/tracking_protection_settings.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/user_education/common/product_messaging_controller.h"
#include "content/public/browser/interest_group_manager.h"
#include "net/base/schemeful_site.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/privacy_sandbox/privacy_sandbox_queue_manager.h"
#endif // !BUILDFLAG(IS_ANDROID)
class BrowserWindowInterface;
class PrefService;
namespace content {
class BrowsingDataRemover;
}
namespace content_settings {
class CookieSettings;
}
namespace browsing_topics {
class BrowsingTopicsService;
}
namespace views {
class Widget;
}
class PrivacySandboxServiceImpl : public PrivacySandboxService {
public:
PrivacySandboxServiceImpl(
Profile* profile,
privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings,
privacy_sandbox::TrackingProtectionSettings* tracking_protection_settings,
scoped_refptr<content_settings::CookieSettings> cookie_settings,
PrefService* pref_service,
content::InterestGroupManager* interest_group_manager,
profile_metrics::BrowserProfileType profile_type,
content::BrowsingDataRemover* browsing_data_remover,
HostContentSettingsMap* host_content_settings_map,
browsing_topics::BrowsingTopicsService* browsing_topics_service,
first_party_sets::FirstPartySetsPolicyService* first_party_sets_service,
PrivacySandboxCountries* privacy_sandbox_countries);
~PrivacySandboxServiceImpl() override;
// KeyedService:
void Shutdown() override;
// PrivacySandboxService:
PromptType GetRequiredPromptType(SurfaceType surface_type) override;
void PromptActionOccurred(PromptAction action,
SurfaceType surface_type) override;
#if !BUILDFLAG(IS_ANDROID)
void PromptOpenedForBrowser(BrowserWindowInterface* browser,
views::Widget* widget) override;
void PromptClosedForBrowser(BrowserWindowInterface* browser) override;
bool IsPromptOpenForBrowser(BrowserWindowInterface* browser) override;
privacy_sandbox::PrivacySandboxQueueManager&
GetPrivacySandboxNoticeQueueManager() override;
#endif // !BUILDFLAG(IS_ANDROID)
void ForceChromeBuildForTests(bool force_chrome_build) override;
bool IsPrivacySandboxRestricted() override;
bool IsRestrictedNoticeEnabled() override;
void SetRelatedWebsiteSetsDataAccessEnabled(bool enabled) override;
bool IsRelatedWebsiteSetsDataAccessEnabled() const override;
bool IsRelatedWebsiteSetsDataAccessManaged() const override;
std::optional<net::SchemefulSite> GetRelatedWebsiteSetOwner(
const GURL& site_url) const override;
std::optional<std::u16string> GetRelatedWebsiteSetOwnerForDisplay(
const GURL& site_url) const override;
bool IsPartOfManagedRelatedWebsiteSet(
const net::SchemefulSite& site) const override;
void GetFledgeJoiningEtldPlusOneForDisplay(
base::OnceCallback<void(std::vector<std::string>)> callback) override;
std::vector<std::string> GetBlockedFledgeJoiningTopFramesForDisplay()
const override;
void SetFledgeJoiningAllowed(const std::string& top_frame_etld_plus1,
bool allowed) const override;
std::vector<privacy_sandbox::CanonicalTopic> GetCurrentTopTopics()
const override;
std::vector<privacy_sandbox::CanonicalTopic> GetBlockedTopics()
const override;
std::vector<privacy_sandbox::CanonicalTopic> GetFirstLevelTopics()
const override;
std::vector<privacy_sandbox::CanonicalTopic> GetChildTopicsCurrentlyAssigned(
const privacy_sandbox::CanonicalTopic& topic) const override;
void SetTopicAllowed(privacy_sandbox::CanonicalTopic topic,
bool allowed) override;
bool PrivacySandboxPrivacyGuideShouldShowAdTopicsCard() override;
bool ShouldUsePrivacyPolicyChinaDomain() override;
void TopicsToggleChanged(bool new_value) const override;
bool TopicsConsentRequired() override;
bool TopicsHasActiveConsent() const override;
privacy_sandbox::TopicsConsentUpdateSource TopicsConsentLastUpdateSource()
const override;
base::Time TopicsConsentLastUpdateTime() const override;
std::string TopicsConsentLastUpdateText() const override;
void UpdateTopicsApiResult(bool value) override;
void UpdateProtectedAudienceApiResult(bool value) override;
void UpdateMeasurementApiResult(bool value) override;
privacy_sandbox::EligibilityLevel GetTopicsApiEligibility() override;
privacy_sandbox::EligibilityLevel GetProtectedAudienceApiEligibility()
override;
privacy_sandbox::EligibilityLevel GetAdMeasurementApiEligibility() override;
protected:
friend class PrivacySandboxServiceTest;
friend class PrivacySandboxQueueTestNoticeWithSearchEngine;
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
MetricsLoggingOccursCorrectly);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTestNonRegularProfile,
NoMetricsRecorded);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServicePromptTest, RestrictedPrompt);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServicePromptTest, ManagedNoPrompt);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServicePromptTest,
ManuallyControlledNoPrompt);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServicePromptTest, NoParamNoPrompt);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceDeathTest,
GetRequiredPromptType);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxPromptNoticeWaiting);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxPromptConsentWaiting);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxV1OffEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxV1OffDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxConsentEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxConsentDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxNoticeEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxNoticeDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandbox3PCOffEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandbox3PCOffDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxManagedEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxManagedDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxManuallyControlledEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxManuallyControlledDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxNoPromptDisabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
PrivacySandboxNoPromptEnabled);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, PrivacySandboxRestricted);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
RelatedWebsiteSetsNotRelevantMetricAllowedCookies);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
RelatedWebsiteSetsNotRelevantMetricBlockedCookies);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
RelatedWebsiteSetsEnabledMetric);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
RelatedWebsiteSetsDisabledMetric);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Explicitly);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptSuppressed_Implicitly);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_EEA);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed_ROW);
FRIEND_TEST_ALL_PREFIXES(PrivacySandbox4StartupMetricsNonRegularProfilesTest,
APIs);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest,
RecordPrivacySandbox4StartupMetrics_APIs);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxPrivacyGuideShouldShowAdTopicsTest,
ReturnsCorrectStatus);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceM1RestrictedNoticePromptTest,
RecordPrivacySandbox4StartupMetrics_PromptNotSuppressed);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted,
RecordPrivacySandbox4StartupMetrics_GraduationFlow);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyRestricted,
RecordPrivacySandbox4StartupMetrics_GraduationFlow);
FRIEND_TEST_ALL_PREFIXES(
PrivacySandboxServiceM1RestrictedNoticeUserCurrentlyUnrestricted,
RecordPrivacySandbox4StartupMetrics_GraduationFlowWhenNoticeShownToGuardian);
FRIEND_TEST_ALL_PREFIXES(PrivacySandboxQueueTestNoticeWithSearchEngine,
PromptSuppressed);
// Contains all possible privacy sandbox states, recorded on startup.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// Must be kept in sync with the SettingsPrivacySandboxEnabled enum in
// histograms/enums.xml.
enum class SettingsPrivacySandboxEnabled {
kPSEnabledAllowAll = 0,
kPSEnabledBlock3P = 1,
kPSEnabledBlockAll = 2,
kPSDisabledAllowAll = 3,
kPSDisabledBlock3P = 4,
kPSDisabledBlockAll = 5,
kPSDisabledPolicyBlock3P = 6,
kPSDisabledPolicyBlockAll = 7,
// DEPRECATED
kPSEnabledFlocDisabledAllowAll = 8,
// DEPRECATED
kPSEnabledFlocDisabledBlock3P = 9,
// DEPRECATED
kPSEnabledFlocDisabledBlockAll = 10,
// Add values above this line with a corresponding label in
// tools/metrics/histograms/enums.xml
kMaxValue = kPSEnabledFlocDisabledBlockAll,
};
// Contains all possible states of first party sets preference.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// Must be kept in sync with the FirstPartySetsState enum in
// histograms/enums.xml.
enum class FirstPartySetsState {
// The user allows all cookies, or blocks all cookies.
kFpsNotRelevant = 0,
// The user blocks third-party cookies, and has FPS enabled.
kFpsEnabled = 1,
// The user blocks third-party cookies, and has FPS disabled.
kFpsDisabled = 2,
kMaxValue = kFpsDisabled,
};
// Contains the possible states of a users Privacy Sandbox overall settings.
// Must be kept in sync with SettingsPrivacySandboxStartupStates in
// histograms/enums.xml
enum class PSStartupStates {
kPromptWaiting = 0,
kPromptOffV1OffEnabled = 1,
kPromptOffV1OffDisabled = 2,
kConsentShownEnabled = 3,
kConsentShownDisabled = 4,
kNoticeShownEnabled = 5,
kNoticeShownDisabled = 6,
kPromptOff3PCOffEnabled = 7,
kPromptOff3PCOffDisabled = 8,
kPromptOffManagedEnabled = 9,
kPromptOffManagedDisabled = 10,
kPromptOffRestricted = 11,
kPromptOffManuallyControlledEnabled = 12,
kPromptOffManuallyControlledDisabled = 13,
kNoPromptRequiredEnabled = 14,
kNoPromptRequiredDisabled = 15,
// Add values above this line with a corresponding label in
// tools/metrics/histograms/enums.xml
kMaxValue = kNoPromptRequiredDisabled,
};
// Helper function to log first party sets state.
void RecordFirstPartySetsStateHistogram(FirstPartySetsState state);
// Logs the state of the privacy sandbox and cookie settings. Called once per
// profile startup.
void LogPrivacySandboxState();
// Logs the state of privacy sandbox 4 in regards to prompts. Called once per
// profile startup.
void RecordPrivacySandbox4StartupMetrics();
// Converts the provided list of |top_frames| into eTLD+1s for display, and
// provides those to |callback|.
void ConvertInterestGroupDataKeysForDisplay(
base::OnceCallback<void(std::vector<std::string>)> callback,
std::vector<content::InterestGroupManager::InterestGroupDataKey>
data_keys);
// Checks to see if initialization of the user's RWS pref is required, and if
// so, sets the default value based on the user's current cookie settings.
void MaybeInitializeRelatedWebsiteSetsPref();
// Updates the preferences which store the current Topics consent information.
void RecordUpdatedTopicsConsent(
privacy_sandbox::TopicsConsentUpdateSource source,
bool did_consent) const;
#if !BUILDFLAG(IS_ANDROID)
// If appropriate based on feature state, closes all currently open Privacy
// Sandbox prompts.
void MaybeCloseOpenPrompts();
#endif // !BUILDFLAG(IS_ANDROID)
private:
// Determines whether Privacy Sandbox Ads consent is required.
bool IsConsentRequired();
// Determines whether a Privacy Sandbox Ads notice is required.
bool IsNoticeRequired();
// Determines whether the Privacy Sandbox Ads Restricted notice is required.
bool IsRestrictedNoticeRequired();
// Checks if a prompt should be suppressed and updates the suppression
// reason preference if a new reason is determined.
// Returns true if the prompt should be suppressed (due to an existing
// or newly set reason), false otherwise.
bool UpdateAndGetSuppressionReason();
// Returns whether the prompt should be disabled.
bool ShouldDisablePrompt();
// Helper function to set the prompt suppression reason.
void SetPromptSuppressedReason(PromptSuppressedReason reason);
// Internal implementation for `GetRequiredPromptType`.
PromptType GetRequiredPromptTypeInternal(SurfaceType surface_type);
raw_ptr<Profile> profile_;
raw_ptr<privacy_sandbox::PrivacySandboxSettings> privacy_sandbox_settings_;
raw_ptr<privacy_sandbox::TrackingProtectionSettings>
tracking_protection_settings_;
scoped_refptr<content_settings::CookieSettings> cookie_settings_;
raw_ptr<PrefService> pref_service_;
raw_ptr<content::InterestGroupManager> interest_group_manager_;
profile_metrics::BrowserProfileType profile_type_;
raw_ptr<content::BrowsingDataRemover> browsing_data_remover_;
raw_ptr<HostContentSettingsMap> host_content_settings_map_;
raw_ptr<browsing_topics::BrowsingTopicsService> browsing_topics_service_;
raw_ptr<first_party_sets::FirstPartySetsPolicyService>
first_party_sets_policy_service_;
raw_ptr<user_education::ProductMessagingController>
product_messaging_controller_;
raw_ptr<PrivacySandboxCountries> privacy_sandbox_countries_;
PrefChangeRegistrar user_prefs_registrar_;
user_education::RequiredNoticePriorityHandle notice_handle_;
#if !BUILDFLAG(IS_ANDROID)
// A map of Browser windows which have an open Privacy Sandbox prompt,
// to the Widget for that prompt.
std::map<BrowserWindowInterface*, raw_ptr<views::Widget, CtnExperimental>>
browsers_to_open_prompts_;
// Instance of queue manager used to manage queue states.
std::unique_ptr<privacy_sandbox::PrivacySandboxQueueManager> queue_manager_;
#endif
// Fake implementation for current and blocked topics.
// TODO(crbug.com/409048902): Moved initialization to constructor to prevent
// potential initialization order issues.
std::set<privacy_sandbox::CanonicalTopic> fake_current_topics_;
std::set<privacy_sandbox::CanonicalTopic> fake_blocked_topics_;
// Record user action metrics based on the |action|.
void RecordPromptActionMetrics(PrivacySandboxService::PromptAction action);
// Record user startup state metrics based on the |state| on both client and
// profile level.
void RecordPromptStartupStateHistograms(
PrivacySandboxService::PromptStartupState state);
// Called when the Topics preference is changed.
void OnTopicsPrefChanged();
// Called when the Fledge preference is changed.
void OnFledgePrefChanged();
// Called when the Ad measurement preference is changed.
void OnAdMeasurementPrefChanged();
// Returns a PrivacySandboxCountries reference.
PrivacySandboxCountries* GetPrivacySandboxCountries();
// Returns true if _any_ of the k-API prefs are disabled via policy or
// the prompt was suppressed via policy.
static bool IsM1PrivacySandboxEffectivelyManaged(PrefService* pref_service);
// Returns true if the user is in the server trial that allows the prompt to
// be shown even if 3PC are blocked. This will also set the Pref that the
// trial is registered. This is so we know to re-register for the trial on
// subsequent restarts when the Notice is shown, and the profile is therefore
// no longer eligible for a prompt.
// Approach:
// The persistent pref tracks whether the server-side trial has been
// *activated* for a user. The pref is set whenever the server-side trial is
// activated (via base::FeatureList::IsEnabled()), regardless of the resulting
// group (Enabled or Control). On subsequent restarts when the Conditions for
// a normal server activation are no longer met (Happens to the Enabled
// Group), the pref can be reused to reactivate the trial if needed. This is
// to achieve true session consistency even if the conditions for triggering
// the server trial are no longer true.
// Handling Group Changes (Control -> Enabled):
// If a user moves from Control to Enabled due to server-side config changes,
// we'll continue to activate based on the pref, which will remain set.
// Timing:
// Trial activation happens *before* the promo is shown,
// but *after* we confirm the user is a candidate (3P cookies blocked at some
// point in the past).
// Why No Synthetic Trial:
// Checking the pref and re-activating the *server-side* trial directly
// achieves persistent activation and maintains balance, making a synthetic
// trial redundant.
// Rollout Beyond 50%:
// This allows for 100% rollout. The pref-based activation works even when
// A/B comparison is no longer the goal.
bool CheckAndRegisterAllowPromptForBlocked3PCookiesTrial();
bool force_chrome_build_for_tests_ = false;
base::WeakPtrFactory<PrivacySandboxServiceImpl> weak_factory_{this};
};
#endif // CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SERVICE_IMPL_H_