Commit 2bf4aee1 authored by Yao Xiao's avatar Yao Xiao Committed by Chromium LUCI CQ

[floc] Check sync/swaa/nac just for event logging, not for the floc computation.

Why: This is the expected behavior. We should keep calculating and
serving the floc even if sync/swaa/nac is disabled. Those bits should
only affect event loggings.

How: Create the FlocEventLogger class for the sync/swaa/nac permission
checks and the loggings. Removed the checks in the floc_id_provider.
Given that the sync service is often ready a few moments after the
browser start, but the floc may already have been computed before then,
for practical purposes, each logging attempt that fails the initial
sync-history check will be given a second chance 10 seconds later.

For sync_integration_test: Remove the feature list initialization and
a test: With the new change, the 1st FLoC event logging will at least
happen 10 seconds after the profile initialization, so we no longer
have the previous issue that the FLoC event being logged right after
sync setup. The removed test is essentially similar to the floc
browsertests (e.g. FlocIdProviderWithCustomizedServicesBrowserTest.
FlocIdValue_ImmediateComputeOnStartUp), so we don't need to have
another test.


Bug: 1160317
Change-Id: Iec357579fb179b2fdc3a327b2089c5a321d109ff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2597014Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarRamin Halavati <rhalavati@chromium.org>
Reviewed-by: default avatarJosh Karlin <jkarlin@chromium.org>
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842109}
parent 08494035
......@@ -512,6 +512,8 @@ static_library("browser") {
"favicon/large_icon_service_factory.h",
"feature_engagement/tracker_factory.cc",
"feature_engagement/tracker_factory.h",
"federated_learning/floc_event_logger.cc",
"federated_learning/floc_event_logger.h",
"federated_learning/floc_id_provider.h",
"federated_learning/floc_id_provider_factory.cc",
"federated_learning/floc_id_provider_factory.h",
......
// Copyright 2021 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 "chrome/browser/federated_learning/floc_event_logger.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service.h"
#include "components/federated_learning/features/features.h"
#include "components/sync/driver/profile_sync_service.h"
#include "components/sync_user_events/user_event_service.h"
#include "content/public/browser/browser_thread.h"
namespace federated_learning {
namespace {
const base::TimeDelta kSecondAttemptDelay = base::TimeDelta::FromSeconds(10);
} // namespace
FlocEventLogger::FlocEventLogger(
syncer::SyncService* sync_service,
FlocRemotePermissionService* floc_remote_permission_service,
syncer::UserEventService* user_event_service)
: sync_service_(sync_service),
floc_remote_permission_service_(floc_remote_permission_service),
user_event_service_(user_event_service) {}
FlocEventLogger::~FlocEventLogger() = default;
void FlocEventLogger::LogFlocComputedEvent(Event event) {
if (!base::FeatureList::IsEnabled(kFlocIdComputedEventLogging))
return;
auto can_log_event_decided_callback =
base::BindOnce(&FlocEventLogger::OnCanLogEventDecided,
weak_ptr_factory_.GetWeakPtr(), std::move(event));
if (!IsSyncHistoryEnabled()) {
// Give it a second chance 10 seconds later. This is because the first floc
// event logging for a browser session can happen before sync finishes
// setting up, and we want to ensure that the event will eventually be
// logged if sync is supposed to be enabled.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&FlocEventLogger::CheckCanLogEvent,
weak_ptr_factory_.GetWeakPtr(),
std::move(can_log_event_decided_callback)),
kSecondAttemptDelay);
return;
}
CheckCanLogEvent(std::move(can_log_event_decided_callback));
}
void FlocEventLogger::CheckCanLogEvent(CanLogEventCallback callback) {
if (!IsSyncHistoryEnabled()) {
std::move(callback).Run(false);
return;
}
IsSwaaNacAccountEnabled(std::move(callback));
}
void FlocEventLogger::OnCanLogEventDecided(Event event, bool can_log_event) {
if (!can_log_event)
return;
auto specifics = std::make_unique<sync_pb::UserEventSpecifics>();
specifics->set_event_time_usec(
event.time.ToDeltaSinceWindowsEpoch().InMicroseconds());
sync_pb::UserEventSpecifics_FlocIdComputed* const floc_id_computed_event =
specifics->mutable_floc_id_computed_event();
if (event.sim_hash_computed)
floc_id_computed_event->set_floc_id(event.sim_hash);
user_event_service_->RecordUserEvent(std::move(specifics));
}
bool FlocEventLogger::IsSyncHistoryEnabled() const {
return sync_service_->IsSyncFeatureActive() &&
sync_service_->GetActiveDataTypes().Has(
syncer::HISTORY_DELETE_DIRECTIVES);
}
void FlocEventLogger::IsSwaaNacAccountEnabled(CanLogEventCallback callback) {
net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
net::DefinePartialNetworkTrafficAnnotation(
"floc_event_logger", "floc_remote_permission_service",
R"(
semantics {
description:
"Queries Google to find out if user has enabled 'web and app "
"activity' and 'ad personalization', and if the account type is "
"NOT a child account. Those permission bits will be checked before "
"logging the FLoC (Federated Learning of Cohorts) ID - an "
"anonymous similarity hash value of user’s navigation history. "
"This ensures that the logged ID is derived from data that Google "
"already owns and the user has explicitly granted permission on "
"what they will be used for."
trigger:
"This request is sent after each time the FLoC (Federated Learning "
"of Cohorts) ID is computed. A FLoC ID is an anonymous similarity "
"hash value of user’s navigation history. It'll be computed at the "
"start of each browser profile session and will be refreshed "
"regularly."
data:
"Google credentials if user is signed in."
}
policy {
setting:
"This feature can be disabled by disabling sync or third-party "
"cookies."
})");
floc_remote_permission_service_->QueryFlocPermission(
std::move(callback), partial_traffic_annotation);
}
} // namespace federated_learning
// Copyright 2021 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.
#ifndef CHROME_BROWSER_FEDERATED_LEARNING_FLOC_EVENT_LOGGER_H_
#define CHROME_BROWSER_FEDERATED_LEARNING_FLOC_EVENT_LOGGER_H_
#include <stddef.h>
#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "components/sync/driver/sync_service_observer.h"
namespace syncer {
class UserEventService;
class SyncService;
} // namespace syncer
namespace federated_learning {
class FlocRemotePermissionService;
// Provide an interface to log the FlocIdComputed event after each time floc is
// computed. For each logging request, a floc is eligible to be logged if the
// following conditons are met:
// 1) Sync & sync-history are enabled.
// 2) Supplemental Web and App Activity is enabled.
// 3) Supplemental Ad Personalization is enabled.
// 4) The account type is NOT a child account.
//
// Given that the sync service is often ready a few moments after the browser
// start, but the floc may already have been computed before then, for practical
// purposes, each request that fails the initial sync-history check will be
// given a second chance 10 seconds later.
class FlocEventLogger {
public:
struct Event {
bool sim_hash_computed = false;
uint64_t sim_hash = 0;
base::Time time;
};
using CanLogEventCallback = base::OnceCallback<void(bool)>;
FlocEventLogger(syncer::SyncService* sync_service,
FlocRemotePermissionService* floc_remote_permission_service,
syncer::UserEventService* user_event_service);
virtual ~FlocEventLogger();
// Log a user event. It'll first go though a few permission checks to
// determine whether the logging is allowed (see class comments). If
// sync-history is not enabled in particular, it will do a second attempt 10
// seconds later.
virtual void LogFlocComputedEvent(Event event);
private:
friend class FlocEventLoggerUnitTest;
friend class MockFlocEventLogger;
void CheckCanLogEvent(CanLogEventCallback callback);
void OnCanLogEventDecided(Event event, bool can_log_event);
bool IsSyncHistoryEnabled() const;
void IsSwaaNacAccountEnabled(CanLogEventCallback callback);
// The following raw pointer references are guaranteed to outlive this object.
syncer::SyncService* sync_service_;
FlocRemotePermissionService* floc_remote_permission_service_;
syncer::UserEventService* user_event_service_;
base::WeakPtrFactory<FlocEventLogger> weak_ptr_factory_{this};
};
} // namespace federated_learning
#endif // CHROME_BROWSER_FEDERATED_LEARNING_FLOC_EVENT_LOGGER_H_
// 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 "chrome/browser/federated_learning/floc_event_logger.h"
#include "base/strings/strcat.h"
#include "base/test/bind.h"
#include "build/build_config.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/federated_learning/features/features.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/sync_user_events/fake_user_event_service.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace federated_learning {
class FakeFlocRemotePermissionService : public FlocRemotePermissionService {
public:
using FlocRemotePermissionService::FlocRemotePermissionService;
void QueryFlocPermission(QueryFlocPermissionCallback callback,
const net::PartialNetworkTrafficAnnotationTag&
partial_traffic_annotation) override {
++number_of_permission_queries_;
std::move(callback).Run(swaa_nac_account_enabled_);
}
size_t number_of_permission_queries() const {
return number_of_permission_queries_;
}
void set_swaa_nac_account_enabled(bool enabled) {
swaa_nac_account_enabled_ = enabled;
}
private:
size_t number_of_permission_queries_ = 0;
bool swaa_nac_account_enabled_ = true;
};
class FlocEventLoggerUnitTest : public testing::Test {
public:
FlocEventLoggerUnitTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
~FlocEventLoggerUnitTest() override = default;
void SetUp() override {
test_sync_service_ = std::make_unique<syncer::TestSyncService>();
test_sync_service_->SetTransportState(
syncer::SyncService::TransportState::DISABLED);
fake_user_event_service_ = std::make_unique<syncer::FakeUserEventService>();
fake_floc_remote_permission_service_ =
std::make_unique<FakeFlocRemotePermissionService>(
/*url_loader_factory=*/nullptr);
floc_event_logger_ = std::make_unique<FlocEventLogger>(
test_sync_service_.get(), fake_floc_remote_permission_service_.get(),
fake_user_event_service_.get());
}
void DisableSyncHistory() {
test_sync_service_->SetTransportState(
syncer::SyncService::TransportState::DISABLED);
test_sync_service_->FireStateChanged();
}
void EnableSyncHistory() {
test_sync_service_->SetTransportState(
syncer::SyncService::TransportState::ACTIVE);
test_sync_service_->FireStateChanged();
}
void SetRemoteSwaaNacAccountEnabled(bool enabled) {
fake_floc_remote_permission_service_->set_swaa_nac_account_enabled(enabled);
}
size_t GetNumberOfRemotePermissionQueries() {
return fake_floc_remote_permission_service_->number_of_permission_queries();
}
size_t GetLoggedEventSize() const {
return fake_user_event_service_->GetRecordedUserEvents().size();
}
FlocEventLogger::Event GetEventAtIndex(size_t i) {
CHECK_LT(i, fake_user_event_service_->GetRecordedUserEvents().size());
const sync_pb::UserEventSpecifics& specifics =
fake_user_event_service_->GetRecordedUserEvents()[i];
EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
specifics.event_case());
const sync_pb::UserEventSpecifics_FlocIdComputed& e =
specifics.floc_id_computed_event();
return {
e.has_floc_id(), e.has_floc_id() ? e.floc_id() : 0,
base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMicroseconds(specifics.event_time_usec()))};
}
protected:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<syncer::TestSyncService> test_sync_service_;
std::unique_ptr<syncer::FakeUserEventService> fake_user_event_service_;
std::unique_ptr<FakeFlocRemotePermissionService>
fake_floc_remote_permission_service_;
std::unique_ptr<FlocEventLogger> floc_event_logger_;
DISALLOW_COPY_AND_ASSIGN(FlocEventLoggerUnitTest);
};
TEST_F(FlocEventLoggerUnitTest, DefaultSyncDisabled_EventLogging) {
// Expect no loggings as sync is disabled.
floc_event_logger_->LogFlocComputedEvent(
{true, 33, base::Time::FromTimeT(44)});
EXPECT_EQ(0u, GetLoggedEventSize());
// After 10 seconds, still no loggings.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
EXPECT_EQ(0u, GetLoggedEventSize());
}
TEST_F(FlocEventLoggerUnitTest, SyncEnabledWithinTenSeconds) {
// Expect no loggings as sync is disabled.
floc_event_logger_->LogFlocComputedEvent(
{true, 33, base::Time::FromTimeT(44)});
EXPECT_EQ(0u, GetLoggedEventSize());
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(9));
EnableSyncHistory();
EXPECT_EQ(0u, GetLoggedEventSize());
// After 10 seconds, expect a logging as the previous logging is attempted for
// the second time.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1u, GetLoggedEventSize());
EXPECT_EQ(1u, GetNumberOfRemotePermissionQueries());
EXPECT_EQ(true, GetEventAtIndex(0).sim_hash_computed);
EXPECT_EQ(33u, GetEventAtIndex(0).sim_hash);
EXPECT_EQ(base::Time::FromTimeT(44), GetEventAtIndex(0).time);
}
TEST_F(FlocEventLoggerUnitTest, SyncEnabledAfterTenSeconds) {
// Expect no loggings as sync is disabled.
floc_event_logger_->LogFlocComputedEvent(
{true, 33, base::Time::FromTimeT(44)});
EXPECT_EQ(0u, GetLoggedEventSize());
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(11));
// If sync is enabled after 10 seconds after the logging time, the event won't
// be handled.
EnableSyncHistory();
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10000));
EXPECT_EQ(0u, GetLoggedEventSize());
}
TEST_F(FlocEventLoggerUnitTest, MultipleEventsBeforeSyncEnabled) {
floc_event_logger_->LogFlocComputedEvent(
{true, 33, base::Time::FromTimeT(44)});
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(5));
floc_event_logger_->LogFlocComputedEvent(
{false, 999, base::Time::FromTimeT(55)});
EXPECT_EQ(0u, GetLoggedEventSize());
EnableSyncHistory();
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(5));
// At time 10, the first event will be given its second attempt.
EXPECT_EQ(1u, GetLoggedEventSize());
EXPECT_EQ(1u, GetNumberOfRemotePermissionQueries());
EXPECT_EQ(true, GetEventAtIndex(0).sim_hash_computed);
EXPECT_EQ(33u, GetEventAtIndex(0).sim_hash);
EXPECT_EQ(base::Time::FromTimeT(44), GetEventAtIndex(0).time);
// At time 15, the second event will be given its second attempt.
// The sim_hash field of the 2nd event (i.e. 999) was ignored because the
// sim_hash_computed field is false.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(15));
EXPECT_EQ(2u, GetLoggedEventSize());
EXPECT_EQ(2u, GetNumberOfRemotePermissionQueries());
EXPECT_EQ(false, GetEventAtIndex(1).sim_hash_computed);
EXPECT_EQ(0u, GetEventAtIndex(1).sim_hash);
EXPECT_EQ(base::Time::FromTimeT(55), GetEventAtIndex(1).time);
}
// Sync-enabled followed by event logging.
TEST_F(FlocEventLoggerUnitTest, SyncEnabled_EventLogging) {
// When sync gets enabled first, following requests should succeed
// immediately.
EnableSyncHistory();
EXPECT_EQ(0u, GetLoggedEventSize());
// Log an event. Expect it to be logged immediately.
floc_event_logger_->LogFlocComputedEvent(
{true, 33, base::Time::FromTimeT(44)});
EXPECT_EQ(1u, GetLoggedEventSize());
EXPECT_EQ(true, GetEventAtIndex(0).sim_hash_computed);
EXPECT_EQ(33u, GetEventAtIndex(0).sim_hash);
EXPECT_EQ(base::Time::FromTimeT(44), GetEventAtIndex(0).time);
}
// Sync is enabled but remote permission is disabled, the request should also
// fail immediately.
TEST_F(FlocEventLoggerUnitTest,
SyncEnabled_RemotePermissionDisabled_EventLogging) {
EnableSyncHistory();
SetRemoteSwaaNacAccountEnabled(false);
// Log an event. Expect it to fail immediately, as if failed the remote
// permission check.
floc_event_logger_->LogFlocComputedEvent(
{true, 33, base::Time::FromTimeT(44)});
EXPECT_EQ(0u, GetLoggedEventSize());
SetRemoteSwaaNacAccountEnabled(true);
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
EXPECT_EQ(0u, GetLoggedEventSize());
}
} // namespace federated_learning
......@@ -5,6 +5,7 @@
#include "chrome/browser/federated_learning/floc_id_provider_factory.h"
#include "base/memory/singleton.h"
#include "chrome/browser/federated_learning/floc_event_logger.h"
#include "chrome/browser/federated_learning/floc_id_provider_impl.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service_factory.h"
......@@ -75,9 +76,11 @@ KeyedService* FlocIdProviderFactory::BuildServiceInstanceFor(
if (!user_event_service)
return nullptr;
return new FlocIdProviderImpl(
profile->GetPrefs(), sync_service, privacy_sandbox_settings,
floc_remote_permission_service, history_service, user_event_service);
auto floc_event_logger = std::make_unique<FlocEventLogger>(
sync_service, floc_remote_permission_service, user_event_service);
return new FlocIdProviderImpl(profile->GetPrefs(), privacy_sandbox_settings,
history_service, std::move(floc_event_logger));
}
} // namespace federated_learning
......@@ -7,14 +7,11 @@
#include <unordered_set>
#include "chrome/browser/browser_process.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service.h"
#include "chrome/browser/net/profile_network_context_service.h"
#include "chrome/browser/federated_learning/floc_event_logger.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings.h"
#include "components/federated_learning/features/features.h"
#include "components/history/core/browser/history_service.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/profile_sync_service.h"
#include "components/sync_user_events/user_event_service.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
namespace federated_learning {
......@@ -32,8 +29,8 @@ constexpr uint32_t kSortingLshVersionPlaceholder = 0;
bool ShouldKeepUsingPreviousFloc(const FlocId& last_floc,
base::TimeDelta* next_compute_delay) {
// The floc has never been computed. This could happen with a fresh profile,
// or some early trigger conditions were never met (e.g. sync has been
// disabled).
// or some early trigger conditions were never met (e.g. sorting-lsh file has
// never been ready).
if (last_floc.compute_time().is_null())
return false;
......@@ -74,27 +71,21 @@ bool ShouldKeepUsingPreviousFloc(const FlocId& last_floc,
FlocIdProviderImpl::FlocIdProviderImpl(
PrefService* prefs,
syncer::SyncService* sync_service,
PrivacySandboxSettings* privacy_sandbox_settings,
FlocRemotePermissionService* floc_remote_permission_service,
history::HistoryService* history_service,
syncer::UserEventService* user_event_service)
std::unique_ptr<FlocEventLogger> floc_event_logger)
: prefs_(prefs),
sync_service_(sync_service),
privacy_sandbox_settings_(privacy_sandbox_settings),
floc_remote_permission_service_(floc_remote_permission_service),
history_service_(history_service),
user_event_service_(user_event_service),
floc_event_logger_(std::move(floc_event_logger)),
floc_id_(FlocId::ReadFromPrefs(prefs_)) {
history_service->AddObserver(this);
sync_service_->AddObserver(this);
g_browser_process->floc_sorting_lsh_clusters_service()->AddObserver(this);
// If the previous floc has expired, invalidate it. The next computation will
// be "immediate", i.e. will occur after we first observe that sync &
// sync-history is enabled and the SortingLSH file is loaded; otherwise, keep
// using the last floc (which may still have be invalid), and schedule a
// recompute event with the desired delay.
// be "immediate", i.e. will occur after we first observe that the SortingLSH
// file is loaded; otherwise, keep using the last floc (which may still have
// be invalid), and schedule a recompute event with the desired delay.
base::TimeDelta next_compute_delay;
if (ShouldKeepUsingPreviousFloc(floc_id_, &next_compute_delay)) {
ScheduleFlocComputation(next_compute_delay);
......@@ -102,12 +93,12 @@ FlocIdProviderImpl::FlocIdProviderImpl(
floc_id_.InvalidateIdAndSaveToPrefs(prefs_);
}
OnStateChanged(sync_service);
if (g_browser_process->floc_sorting_lsh_clusters_service()
->IsSortingLshClustersFileReady()) {
OnSortingLshClustersFileReady();
}
MaybeTriggerImmediateComputation();
}
FlocIdProviderImpl::~FlocIdProviderImpl() = default;
......@@ -115,10 +106,8 @@ FlocIdProviderImpl::~FlocIdProviderImpl() = default;
std::string FlocIdProviderImpl::GetInterestCohortForJsApi(
const GURL& url,
const base::Optional<url::Origin>& top_frame_origin) const {
// These checks could be / become unnecessary, as we are planning on
// invalidating the |floc_id_| whenever a setting is disabled. Check them
// anyway to be safe.
if (!IsSyncHistoryEnabled() || !IsPrivacySandboxAllowed())
// Check the Privacy Sandbox general settings.
if (!IsPrivacySandboxAllowed())
return std::string();
// Check the Privacy Sandbox context specific settings.
......@@ -152,27 +141,12 @@ void FlocIdProviderImpl::OnComputeFlocCompleted(ComputeFlocResult result) {
}
void FlocIdProviderImpl::LogFlocComputedEvent(const ComputeFlocResult& result) {
if (!base::FeatureList::IsEnabled(kFlocIdComputedEventLogging))
return;
auto specifics = std::make_unique<sync_pb::UserEventSpecifics>();
specifics->set_event_time_usec(
base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
sync_pb::UserEventSpecifics_FlocIdComputed* const floc_id_computed_event =
specifics->mutable_floc_id_computed_event();
if (result.sim_hash_computed)
floc_id_computed_event->set_floc_id(result.sim_hash);
user_event_service_->RecordUserEvent(std::move(specifics));
floc_event_logger_->LogFlocComputedEvent(
FlocEventLogger::Event{result.sim_hash_computed, result.sim_hash,
result.floc_id.compute_time()});
}
void FlocIdProviderImpl::Shutdown() {
if (sync_service_)
sync_service_->RemoveObserver(this);
sync_service_ = nullptr;
if (history_service_)
history_service_->RemoveObserver(this);
history_service_ = nullptr;
......@@ -222,31 +196,17 @@ void FlocIdProviderImpl::OnSortingLshClustersFileReady() {
MaybeTriggerImmediateComputation();
}
void FlocIdProviderImpl::OnStateChanged(syncer::SyncService* sync_service) {
if (first_sync_history_enabled_seen_)
return;
if (!IsSyncHistoryEnabled())
return;
first_sync_history_enabled_seen_ = true;
MaybeTriggerImmediateComputation();
}
void FlocIdProviderImpl::MaybeTriggerImmediateComputation() {
// If the floc computation is neither in progress nor scheduled, it means we
// want to trigger an immediate computation as soon as when the sync &
// sync-history is enabled and sorting-lsh file is loaded.
// want to trigger an immediate computation as soon as the sorting-lsh file is
// loaded.
if (floc_computation_in_progress_ || compute_floc_timer_.IsRunning())
return;
bool sorting_lsh_ready_or_not_required =
!base::FeatureList::IsEnabled(kFlocIdSortingLshBasedComputation) ||
first_sorting_lsh_file_ready_seen_;
if (!first_sync_history_enabled_seen_ || !sorting_lsh_ready_or_not_required)
if (!first_sorting_lsh_file_ready_seen_ &&
base::FeatureList::IsEnabled(kFlocIdSortingLshBasedComputation)) {
return;
}
ComputeFloc();
}
......@@ -267,12 +227,12 @@ void FlocIdProviderImpl::ComputeFloc() {
}
void FlocIdProviderImpl::CheckCanComputeFloc(CanComputeFlocCallback callback) {
if (!IsSyncHistoryEnabled() || !IsPrivacySandboxAllowed()) {
if (!IsPrivacySandboxAllowed()) {
std::move(callback).Run(false);
return;
}
IsSwaaNacAccountEnabled(std::move(callback));
std::move(callback).Run(true);
}
void FlocIdProviderImpl::OnCheckCanComputeFlocCompleted(
......@@ -288,54 +248,10 @@ void FlocIdProviderImpl::OnCheckCanComputeFlocCompleted(
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
bool FlocIdProviderImpl::IsSyncHistoryEnabled() const {
syncer::SyncUserSettings* setting = sync_service_->GetUserSettings();
DCHECK(setting);
return sync_service_->IsSyncFeatureActive() &&
sync_service_->GetActiveDataTypes().Has(
syncer::HISTORY_DELETE_DIRECTIVES);
}
bool FlocIdProviderImpl::IsPrivacySandboxAllowed() const {
return privacy_sandbox_settings_->IsPrivacySandboxAllowed();
}
void FlocIdProviderImpl::IsSwaaNacAccountEnabled(
CanComputeFlocCallback callback) {
net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
net::DefinePartialNetworkTrafficAnnotation(
"floc_id_provider_impl", "floc_remote_permission_service",
R"(
semantics {
description:
"Queries google to find out if user has enabled 'web and app "
"activity' and 'ad personalization', and if the account type is "
"NOT a child account. Those permission bits will be checked before "
"computing the FLoC (Federated Learning of Cohorts) ID - an "
"anonymous similarity hash value of user’s navigation history. "
"This ensures that the FLoC ID is derived from data that Google "
"already owns and the user has explicitly granted permission on "
"what they will be used for."
trigger:
"This request is sent at each time a FLoC (Federated Learning of "
"Cohorts) ID is to be computed. A FLoC ID is an anonymous "
"similarity hash value of user’s navigation history. It'll be "
"computed at the start of each browser profile session and will be "
"refreshed every 24 hours during that session."
data:
"Google credentials if user is signed in."
}
policy {
setting:
"This feature cannot be disabled in settings, but disabling sync "
"or third-party cookies will prevent it."
})");
floc_remote_permission_service_->QueryFlocPermission(
std::move(callback), partial_traffic_annotation);
}
void FlocIdProviderImpl::GetRecentlyVisitedURLs(
GetRecentlyVisitedURLsCallback callback) {
history::QueryOptions options;
......
......@@ -12,28 +12,24 @@
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/sync/driver/sync_service_observer.h"
class PrivacySandboxSettings;
namespace syncer {
class UserEventService;
}
namespace federated_learning {
class FlocRemotePermissionService;
class FlocEventLogger;
// A service that regularly computes the floc id and logs it in a user event. A
// computed floc can be in either a valid or invalid state, based on whether all
// the prerequisites are met:
// 1) Sync & sync-history are enabled.
// 2) 3rd party cookies are NOT blocked.
// 3) Supplemental Web and App Activity is enabled.
// 4) Supplemental Ad Personalization is enabled.
// 5) The account type is NOT a child account.
// A service that regularly computes the floc id and logs it in a user event.
//
// For the first browser session of a profile, we'll start computing the floc
// after the sorting-lsh file is loaded, and another computation will be
// scheduled every X days. When the browser shuts down and starts up again, it
// can remember the last state and can still schedule the computation at X days
// after the last compute time. If we've missed a scheduled update due to the
// browser not being alive, it'll compute after the next session starts, using
// the sorting-lsh-file-loaded as the first compute triggering condition.
//
// When all the prerequisites are met, the floc will be computed by:
// The floc will be computed by:
// Step 1: sim-hashing navigation URL domains in the last 7 days. This step aims
// to group together users with similar browsing habit.
// Step 2: applying the sorting-lsh post processing to the sim-hash value. The
......@@ -42,24 +38,20 @@ class FlocRemotePermissionService;
// server side in chrome-sync, based on logged sim-hash data, and is pushed to
// Chrome on a regular basis through the component updater.
//
// If some prerequisites are not met, an invalid floc will be given.
// A computed floc will be valid if:
// - 3rd party cookies are NOT blocked.
// - There are at least 3 *eligible* history entries in the last 7 days, where
// eligible means the IP was publicly routable.
// - It's not blocked by the sorting-lsh (with encoded blocklist) file.
//
// If some of those conditions are not met, an invalid floc will be given.
//
// For the first browser session of a profile, we'll compute the floc after sync
// & sync-history are enabled and the sorting-lsh file is loaded, and another
// computation will be scheduled every X days. When the browser shuts down and
// starts up again, it can remember the last state and can still schedule the
// computation at X days after the last compute time. If we've missed a
// scheduled update due to browser not being alive, it'll compute after the next
// session starts, using sync-history-enabled & sorting-lsh-file-loaded as the
// first compute triggering condition.
// In the event of history deletion, the floc will be invalidated immediately if
// the time range of the deletion overlaps with the time range used to compute
// the existing floc.
class FlocIdProviderImpl : public FlocIdProvider,
public FlocSortingLshClustersService::Observer,
public history::HistoryServiceObserver,
public syncer::SyncServiceObserver {
public history::HistoryServiceObserver {
public:
struct ComputeFlocResult {
ComputeFlocResult() = default;
......@@ -85,13 +77,10 @@ class FlocIdProviderImpl : public FlocIdProvider,
using GetRecentlyVisitedURLsCallback =
history::HistoryService::QueryHistoryCallback;
FlocIdProviderImpl(
PrefService* prefs,
syncer::SyncService* sync_service,
PrivacySandboxSettings* privacy_sandbox_settings,
FlocRemotePermissionService* floc_remote_permission_service,
history::HistoryService* history_service,
syncer::UserEventService* user_event_service);
FlocIdProviderImpl(PrefService* prefs,
PrivacySandboxSettings* privacy_sandbox_settings,
history::HistoryService* history_service,
std::unique_ptr<FlocEventLogger> floc_event_logger);
~FlocIdProviderImpl() override;
FlocIdProviderImpl(const FlocIdProviderImpl&) = delete;
FlocIdProviderImpl& operator=(const FlocIdProviderImpl&) = delete;
......@@ -122,15 +111,10 @@ class FlocIdProviderImpl : public FlocIdProvider,
// FlocSortingLshClustersService::Observer
void OnSortingLshClustersFileReady() override;
// syncer::SyncServiceObserver:
void OnStateChanged(syncer::SyncService* sync_service) override;
void MaybeComputeOnInitialSetupReady();
// This function will be called whenever the sync setting has changed or the
// sorting-lsh file is loaded. It'll trigger an immediate floc computation if
// the floc was never computed before, or if the floc already expired when the
// browser session starts.
// This function will be called at the start or when the sorting-lsh file is
// loaded. It'll trigger an immediate floc computation if the floc was never
// computed before, or if the floc already expired when the browser session
// starts.
void MaybeTriggerImmediateComputation();
void ComputeFloc();
......@@ -174,11 +158,10 @@ class FlocIdProviderImpl : public FlocIdProvider,
// FlocIdProviderFactory::FlocIdProviderFactory() guarantees that this object
// will be destroyed first among those services.
PrefService* prefs_;
syncer::SyncService* sync_service_;
PrivacySandboxSettings* privacy_sandbox_settings_;
FlocRemotePermissionService* floc_remote_permission_service_;
history::HistoryService* history_service_;
syncer::UserEventService* user_event_service_;
std::unique_ptr<FlocEventLogger> floc_event_logger_;
// The id to be exposed to the JS API. It will always be in sync with the one
// stored in prefs.
......@@ -195,7 +178,6 @@ class FlocIdProviderImpl : public FlocIdProvider,
bool need_recompute_ = false;
bool first_sorting_lsh_file_ready_seen_ = false;
bool first_sync_history_enabled_seen_ = false;
// Used for the async tasks querying the HistoryService.
base::CancelableTaskTracker history_task_tracker_;
......
......@@ -16,8 +16,6 @@
#include "base/test/bind.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service.h"
#include "chrome/browser/federated_learning/floc_remote_permission_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
......@@ -59,15 +57,6 @@ bool HasAuthError(ProfileSyncService* service) {
GoogleServiceAuthError::REQUEST_CANCELED;
}
void FinishOutstandingFlocRemotePermissionQueries(Profile* profile) {
base::RunLoop run_loop;
FlocRemotePermissionServiceFactory::GetForProfile(profile)
->QueryFlocPermission(
base::BindLambdaForTesting([&](bool success) { run_loop.Quit(); }),
PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
run_loop.Run();
}
class EngineInitializeChecker : public SingleClientStatusChangeChecker {
public:
explicit EngineInitializeChecker(ProfileSyncService* service)
......@@ -468,15 +457,6 @@ bool ProfileSyncServiceHarness::AwaitSyncSetupCompletion() {
return false;
}
// Finish any outstanding floc permission network requests. Right after sync
// gets set up, the floc code may make a network call, and at response time
// a floc specific user event could be logged. We need this waiting to ensure
// that the behavior (i.e. either logged or not logged) are determnistic.
//
// TODO(yaoxia): The network call should be mocked out / intercepted and
// handled locally.
FinishOutstandingFlocRemotePermissionQueries(profile_);
return true;
}
......
......@@ -17,7 +17,6 @@
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/sync/test/integration/user_events_helper.h"
#include "chrome/browser/sync/user_event_service_factory.h"
#include "components/federated_learning/features/features.h"
#include "components/sync/protocol/user_event_specifics.pb.h"
#include "components/sync_user_events/user_event_service.h"
#include "content/public/test/browser_test.h"
......@@ -37,14 +36,7 @@ CommitResponse::ResponseType BounceType(
class SingleClientUserEventsSyncTest : public SyncTest {
public:
SingleClientUserEventsSyncTest() : SyncTest(SINGLE_CLIENT) {
// Disable the floc-event-logging for this test suite. This event could be
// logged right after sync gets enabled, and could mess up with the test
// expectations. The scenario when the floc-event-logging is enabled is
// tested separately.
feature_list_.InitAndDisableFeature(
federated_learning::kFlocIdComputedEventLogging);
}
SingleClientUserEventsSyncTest() : SyncTest(SINGLE_CLIENT) {}
~SingleClientUserEventsSyncTest() override = default;
......@@ -239,40 +231,4 @@ IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTest,
EXPECT_TRUE(ExpectUserEvents({}));
}
class SingleClientUserEventsSyncTestFlocEventLoggingEnabled
: public SingleClientUserEventsSyncTest {
public:
SingleClientUserEventsSyncTestFlocEventLoggingEnabled() {
feature_list_.Reset();
feature_list_.InitAndEnableFeature(
federated_learning::kFlocIdComputedEventLogging);
}
};
IN_PROC_BROWSER_TEST_F(SingleClientUserEventsSyncTestFlocEventLoggingEnabled,
FlocEventAfterSyncSetup) {
ASSERT_TRUE(SetupSync());
// When sync gets enabled, the floc calculation should start, and by this
// point it should have failed the remote permission check and logged an user
// event.
EXPECT_TRUE(ServerCountMatchStatusChecker(syncer::USER_EVENTS, 1).Wait());
UserEventSpecifics server_specifics =
GetFakeServer()
->GetSyncEntitiesByModelType(syncer::USER_EVENTS)[0]
.specifics()
.user_event();
EXPECT_EQ(sync_pb::UserEventSpecifics::kFlocIdComputedEvent,
server_specifics.event_case());
const sync_pb::UserEventSpecifics_FlocIdComputed& event =
server_specifics.floc_id_computed_event();
// It shouldn't have the floc_id field, because remote permission check should
// have failed.
EXPECT_FALSE(event.has_floc_id());
}
} // namespace
......@@ -11,7 +11,6 @@
#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
#include "chrome/browser/sync/test/integration/user_events_helper.h"
#include "chrome/browser/sync/user_event_service_factory.h"
#include "components/federated_learning/features/features.h"
#include "components/sync/protocol/user_event_specifics.pb.h"
#include "components/sync_user_events/user_event_service.h"
#include "content/public/test/browser_test.h"
......@@ -26,14 +25,7 @@ const int kDecryptingClientId = 1;
class TwoClientUserEventsSyncTest : public SyncTest {
public:
TwoClientUserEventsSyncTest() : SyncTest(TWO_CLIENT) {
// Disable the floc-event-logging for this test suite. This event could be
// logged right after sync gets enabled, and could mess up with the test
// expectations. The scenario when the floc-event-logging is enabled is
// tested separately.
feature_list_.InitAndDisableFeature(
federated_learning::kFlocIdComputedEventLogging);
}
TwoClientUserEventsSyncTest() : SyncTest(TWO_CLIENT) {}
~TwoClientUserEventsSyncTest() override = default;
......
......@@ -3500,6 +3500,7 @@ test("unit_tests") {
"../browser/enterprise/util/affiliation_unittest.cc",
"../browser/enterprise/util/managed_browser_utils_unittest.cc",
"../browser/external_protocol/external_protocol_handler_unittest.cc",
"../browser/federated_learning/floc_event_logger_unittest.cc",
"../browser/federated_learning/floc_id_provider_unittest.cc",
"../browser/federated_learning/floc_remote_permission_service_unittest.cc",
"../browser/file_select_helper_unittest.cc",
......
......@@ -113,7 +113,8 @@ Refer to README.md for content description and update process.
<item id="favicon_loader" added_in_milestone="63" hash_code="112189210" type="0" content_hash_code="70773116" os_list="linux,windows" file_path="content/renderer/loader/web_url_loader_impl.cc"/>
<item id="feed_image_fetcher" added_in_milestone="68" hash_code="87439531" type="0" deprecated="2019-01-04" content_hash_code="26756208" file_path=""/>
<item id="file_system_connector_to_box" added_in_milestone="89" hash_code="29061438" type="1" second_id="29188932" content_hash_code="69177828" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="-1,3,4" file_path="chrome/browser/enterprise/connectors/file_system/box_api_call_flow.cc"/>
<item id="floc_id_provider_impl" added_in_milestone="85" hash_code="103052331" type="1" second_id="13704791" content_hash_code="41421380" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="3" file_path="chrome/browser/federated_learning/floc_id_provider_impl.cc"/>
<item id="floc_event_logger" added_in_milestone="89" hash_code="86015226" type="1" second_id="13704791" content_hash_code="68024778" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="3" file_path="chrome/browser/federated_learning/floc_event_logger.cc"/>
<item id="floc_id_provider_impl" added_in_milestone="85" hash_code="103052331" type="1" second_id="13704791" deprecated="2021-01-05" content_hash_code="41421380" file_path=""/>
<item id="floc_remote_permission_service" added_in_milestone="85" hash_code="13704791" type="2" content_hash_code="86293622" os_list="linux,windows" semantics_fields="1,5" policy_fields="1,2,4" file_path="chrome/browser/federated_learning/floc_remote_permission_service.cc"/>
<item id="ftl_messaging_client_ack_messages" added_in_milestone="86" hash_code="55663676" type="0" content_hash_code="20913627" os_list="linux,windows" file_path="remoting/signaling/ftl_messaging_client.cc"/>
<item id="ftl_messaging_client_receive_messages" added_in_milestone="86" hash_code="136248372" type="0" content_hash_code="36609143" os_list="linux,windows" file_path="remoting/signaling/ftl_messaging_client.cc"/>
......
......@@ -154,7 +154,7 @@ hidden="true" so that these annotations don't show up in the document.
<traffic_annotation unique_id="services_http_server_error_response"/>
<traffic_annotation unique_id="webrtc_peer_connection"/>
<traffic_annotation unique_id="direct_sockets"/>
<traffic_annotation unique_id="floc_id_provider_impl"/>
<traffic_annotation unique_id="floc_event_logger"/>
<traffic_annotation unique_id="gstatic_change_password_override_urls"/>
<traffic_annotation unique_id="interest_feedv2_image_send"/>
<traffic_annotation unique_id="sanitized_image_source"/>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment