Commit 0e2f7cb7 authored by Yao Xiao's avatar Yao Xiao Committed by Commit Bot

Update the floc computation scheduling pattern

Before: Schedule the computation events using a RepeatingTimer and use a
session number to address potential race conditions.

After: Use a flag |floc_computation_in_progress_| to guard the process
from ComputeFloc to OnComputeFlocCompleted. Incoming computation will be
ignored if there’s one ongoing. After each OnComputeFlocCompleted, a
ComputeFloc event will be scheduled 24 hours later / override the
existing scheduled event.

Why: The new pattern would be more suitable for a future plan where more
computation triggers are introduced (e.g. kHistoryDelete). In that case,
the caller can simply call
ComputeFloc(ComputeFlocTrigger::kHistoryDelete) without needing to reset
the timer.


Bug: 1062736
Change-Id: Ic128262272c71be3bc8998bb192ff7c7b615faa8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2359394
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Reviewed-by: default avatarJosh Karlin <jkarlin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799547}
parent d8d68438
...@@ -278,7 +278,7 @@ IN_PROC_BROWSER_TEST_F(FlocIdProviderWithCustomizedServicesBrowserTest, ...@@ -278,7 +278,7 @@ IN_PROC_BROWSER_TEST_F(FlocIdProviderWithCustomizedServicesBrowserTest,
EXPECT_EQ(GetFlocId().ToDebugHeaderValue(), FlocId().ToDebugHeaderValue()); EXPECT_EQ(GetFlocId().ToDebugHeaderValue(), FlocId().ToDebugHeaderValue());
// Turn on sync-history to trigger the start of the 1st floc session. // Turn on sync-history to trigger the 1st floc computation.
sync_service()->SetActiveDataTypes(syncer::ModelTypeSet::All()); sync_service()->SetActiveDataTypes(syncer::ModelTypeSet::All());
sync_service()->FireStateChanged(); sync_service()->FireStateChanged();
...@@ -313,7 +313,7 @@ IN_PROC_BROWSER_TEST_F(FlocIdProviderWithCustomizedServicesBrowserTest, ...@@ -313,7 +313,7 @@ IN_PROC_BROWSER_TEST_F(FlocIdProviderWithCustomizedServicesBrowserTest,
EXPECT_EQ(GetFlocId().ToDebugHeaderValue(), FlocId().ToDebugHeaderValue()); EXPECT_EQ(GetFlocId().ToDebugHeaderValue(), FlocId().ToDebugHeaderValue());
// Turn on sync-history to trigger the start of the 1st floc session. // Turn on sync-history to trigger the 1st floc computation.
sync_service()->SetActiveDataTypes(syncer::ModelTypeSet::All()); sync_service()->SetActiveDataTypes(syncer::ModelTypeSet::All());
sync_service()->FireStateChanged(); sync_service()->FireStateChanged();
......
...@@ -25,7 +25,7 @@ namespace federated_learning { ...@@ -25,7 +25,7 @@ namespace federated_learning {
namespace { namespace {
constexpr size_t kMinHistoryDomainSizeToReportFlocId = 1; constexpr size_t kMinHistoryDomainSizeToReportFlocId = 1;
constexpr base::TimeDelta kFlocSessionRenewInterval = constexpr base::TimeDelta kFlocScheduledUpdateInterval =
base::TimeDelta::FromDays(1); base::TimeDelta::FromDays(1);
constexpr int kQueryHistoryWindowInDays = 7; constexpr int kQueryHistoryWindowInDays = 7;
...@@ -48,9 +48,7 @@ FlocIdProviderImpl::FlocIdProviderImpl( ...@@ -48,9 +48,7 @@ FlocIdProviderImpl::FlocIdProviderImpl(
FlocIdProviderImpl::~FlocIdProviderImpl() = default; FlocIdProviderImpl::~FlocIdProviderImpl() = default;
void FlocIdProviderImpl::NotifyFlocIdUpdated() { void FlocIdProviderImpl::NotifyFlocUpdated(ComputeFlocTrigger trigger) {
DCHECK(floc_session_count_ > 0);
if (!base::FeatureList::IsEnabled(features::kFlocIdComputedEventLogging)) if (!base::FeatureList::IsEnabled(features::kFlocIdComputedEventLogging))
return; return;
...@@ -60,9 +58,9 @@ void FlocIdProviderImpl::NotifyFlocIdUpdated() { ...@@ -60,9 +58,9 @@ void FlocIdProviderImpl::NotifyFlocIdUpdated() {
specifics->mutable_floc_id_computed_event(); specifics->mutable_floc_id_computed_event();
sync_pb::UserEventSpecifics_FlocIdComputed_EventTrigger event_trigger = sync_pb::UserEventSpecifics_FlocIdComputed_EventTrigger event_trigger =
(floc_session_count_ == 1u) (trigger == ComputeFlocTrigger::kBrowserStart)
? sync_pb::UserEventSpecifics::FlocIdComputed::NEW ? sync_pb::UserEventSpecifics_FlocIdComputed_EventTrigger_NEW
: sync_pb::UserEventSpecifics::FlocIdComputed::REFRESHED; : sync_pb::UserEventSpecifics_FlocIdComputed_EventTrigger_REFRESHED;
floc_id_computed_event->set_event_trigger(event_trigger); floc_id_computed_event->set_event_trigger(event_trigger);
...@@ -86,7 +84,7 @@ bool FlocIdProviderImpl::AreThirdPartyCookiesAllowed() { ...@@ -86,7 +84,7 @@ bool FlocIdProviderImpl::AreThirdPartyCookiesAllowed() {
} }
void FlocIdProviderImpl::IsSwaaNacAccountEnabled( void FlocIdProviderImpl::IsSwaaNacAccountEnabled(
CanComputeFlocIdCallback callback) { CanComputeFlocCallback callback) {
net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation = net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
net::DefinePartialNetworkTrafficAnnotation( net::DefinePartialNetworkTrafficAnnotation(
"floc_id_provider_impl", "floc_remote_permission_service", "floc_id_provider_impl", "floc_remote_permission_service",
...@@ -127,29 +125,59 @@ void FlocIdProviderImpl::Shutdown() { ...@@ -127,29 +125,59 @@ void FlocIdProviderImpl::Shutdown() {
} }
void FlocIdProviderImpl::OnStateChanged(syncer::SyncService* sync_service) { void FlocIdProviderImpl::OnStateChanged(syncer::SyncService* sync_service) {
if (floc_session_count_ > 0) if (first_floc_computation_triggered_)
return; return;
if (!IsSyncHistoryEnabled()) if (!IsSyncHistoryEnabled())
return; return;
CalculateFloc(); ComputeFloc(ComputeFlocTrigger::kBrowserStart);
}
void FlocIdProviderImpl::ComputeFloc(ComputeFlocTrigger trigger) {
DCHECK_NE(trigger == ComputeFlocTrigger::kBrowserStart,
first_floc_computation_triggered_);
floc_session_start_timer_.Start( DCHECK(trigger != ComputeFlocTrigger::kBrowserStart ||
FROM_HERE, kFlocSessionRenewInterval, !floc_computation_in_progress_);
base::BindRepeating(&FlocIdProviderImpl::CalculateFloc,
weak_ptr_factory_.GetWeakPtr())); // Skip computing as long as there's one still in progress.
if (floc_computation_in_progress_)
return;
floc_computation_in_progress_ = true;
first_floc_computation_triggered_ = true;
auto compute_floc_completed_callback =
base::BindOnce(&FlocIdProviderImpl::OnComputeFlocCompleted,
weak_ptr_factory_.GetWeakPtr(), trigger);
CheckCanComputeFloc(
base::BindOnce(&FlocIdProviderImpl::OnCheckCanComputeFlocCompleted,
weak_ptr_factory_.GetWeakPtr(),
std::move(compute_floc_completed_callback)));
} }
void FlocIdProviderImpl::CalculateFloc() { void FlocIdProviderImpl::OnComputeFlocCompleted(ComputeFlocTrigger trigger,
floc_session_count_ += 1; FlocId floc_id) {
CheckCanComputeFlocId( DCHECK(floc_computation_in_progress_);
base::BindOnce(&FlocIdProviderImpl::OnCheckCanComputeFlocIdCompleted, floc_computation_in_progress_ = false;
weak_ptr_factory_.GetWeakPtr()));
if (floc_id_ != floc_id) {
floc_id_ = floc_id;
NotifyFlocUpdated(trigger);
}
// Abandon the scheduled task if any, and schedule a new compute-floc task
// that is |kFlocScheduledUpdateInterval| from now.
compute_floc_timer_.Start(
FROM_HERE, kFlocScheduledUpdateInterval,
base::BindOnce(&FlocIdProviderImpl::ComputeFloc,
weak_ptr_factory_.GetWeakPtr(),
ComputeFlocTrigger::kScheduledUpdate));
} }
void FlocIdProviderImpl::CheckCanComputeFlocId( void FlocIdProviderImpl::CheckCanComputeFloc(CanComputeFlocCallback callback) {
CanComputeFlocIdCallback callback) {
if (!IsSyncHistoryEnabled() || !AreThirdPartyCookiesAllowed()) { if (!IsSyncHistoryEnabled() || !AreThirdPartyCookiesAllowed()) {
std::move(callback).Run(false); std::move(callback).Run(false);
return; return;
...@@ -158,19 +186,17 @@ void FlocIdProviderImpl::CheckCanComputeFlocId( ...@@ -158,19 +186,17 @@ void FlocIdProviderImpl::CheckCanComputeFlocId(
IsSwaaNacAccountEnabled(std::move(callback)); IsSwaaNacAccountEnabled(std::move(callback));
} }
void FlocIdProviderImpl::OnCheckCanComputeFlocIdCompleted( void FlocIdProviderImpl::OnCheckCanComputeFlocCompleted(
ComputeFlocCompletedCallback callback,
bool can_compute_floc) { bool can_compute_floc) {
if (!can_compute_floc) { if (!can_compute_floc) {
if (floc_id_.IsValid()) { std::move(callback).Run(FlocId());
floc_id_ = FlocId();
NotifyFlocIdUpdated();
}
return; return;
} }
GetRecentlyVisitedURLs( GetRecentlyVisitedURLs(
base::BindOnce(&FlocIdProviderImpl::OnGetRecentlyVisitedURLsCompleted, base::BindOnce(&FlocIdProviderImpl::OnGetRecentlyVisitedURLsCompleted,
weak_ptr_factory_.GetWeakPtr(), floc_session_count_)); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
void FlocIdProviderImpl::GetRecentlyVisitedURLs( void FlocIdProviderImpl::GetRecentlyVisitedURLs(
...@@ -184,12 +210,8 @@ void FlocIdProviderImpl::GetRecentlyVisitedURLs( ...@@ -184,12 +210,8 @@ void FlocIdProviderImpl::GetRecentlyVisitedURLs(
} }
void FlocIdProviderImpl::OnGetRecentlyVisitedURLsCompleted( void FlocIdProviderImpl::OnGetRecentlyVisitedURLsCompleted(
size_t floc_session_count, ComputeFlocCompletedCallback callback,
history::QueryResults results) { history::QueryResults results) {
DCHECK_LE(floc_session_count, floc_session_count_);
if (floc_session_count < floc_session_count_)
return;
std::unordered_set<std::string> domains; std::unordered_set<std::string> domains;
for (const history::URLResult& url_result : results) { for (const history::URLResult& url_result : results) {
if (!url_result.publicly_routable()) if (!url_result.publicly_routable())
...@@ -204,10 +226,7 @@ void FlocIdProviderImpl::OnGetRecentlyVisitedURLsCompleted( ...@@ -204,10 +226,7 @@ void FlocIdProviderImpl::OnGetRecentlyVisitedURLsCompleted(
? FlocId::CreateFromHistory(domains) ? FlocId::CreateFromHistory(domains)
: FlocId(); : FlocId();
if (floc_id_ != floc_id) { std::move(callback).Run(floc_id);
floc_id_ = floc_id;
NotifyFlocIdUpdated();
}
} }
} // namespace federated_learning } // namespace federated_learning
...@@ -25,19 +25,31 @@ namespace federated_learning { ...@@ -25,19 +25,31 @@ namespace federated_learning {
class FlocRemotePermissionService; class FlocRemotePermissionService;
// A service that regularly computes the floc id and logs it in a user event. // 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 floc session starts when sync & sync-history is first enabled. We validate // When all the prerequisites are met, the floc will be computed by sim-hashing
// the following conditions in sequence before computing the floc id: user // navigation URL domains in the last 7 days; otherwise, an invalid floc will be
// doesn’t block 3rd party cookies; all 3 of swaa & nac & account_type are // given.
// enabled; the user has visited at least 1 domain with publicly routable ip in //
// the past 7 days. Every 24 hours, it'll go over the conditions above again // The floc will be first computed after sync & sync-history are enabled. After
// (including the sync & sync-history check), and reset or recompute the id // each computation, another computation will be scheduled 24 hours later.
// accordingly.
class FlocIdProviderImpl : public FlocIdProvider, class FlocIdProviderImpl : public FlocIdProvider,
public syncer::SyncServiceObserver { public syncer::SyncServiceObserver {
public: public:
using CanComputeFlocIdCallback = base::OnceCallback<void(bool)>; enum class ComputeFlocTrigger {
kBrowserStart,
kScheduledUpdate,
};
using CanComputeFlocCallback = base::OnceCallback<void(bool)>;
using ComputeFlocCompletedCallback = base::OnceCallback<void(FlocId)>;
using GetRecentlyVisitedURLsCallback = using GetRecentlyVisitedURLsCallback =
history::HistoryService::QueryHistoryCallback; history::HistoryService::QueryHistoryCallback;
...@@ -53,10 +65,10 @@ class FlocIdProviderImpl : public FlocIdProvider, ...@@ -53,10 +65,10 @@ class FlocIdProviderImpl : public FlocIdProvider,
protected: protected:
// protected virtual for testing. // protected virtual for testing.
virtual void NotifyFlocIdUpdated(); virtual void NotifyFlocUpdated(ComputeFlocTrigger trigger);
virtual bool IsSyncHistoryEnabled(); virtual bool IsSyncHistoryEnabled();
virtual bool AreThirdPartyCookiesAllowed(); virtual bool AreThirdPartyCookiesAllowed();
virtual void IsSwaaNacAccountEnabled(CanComputeFlocIdCallback callback); virtual void IsSwaaNacAccountEnabled(CanComputeFlocCallback callback);
private: private:
friend class FlocIdProviderUnitTest; friend class FlocIdProviderUnitTest;
...@@ -68,17 +80,20 @@ class FlocIdProviderImpl : public FlocIdProvider, ...@@ -68,17 +80,20 @@ class FlocIdProviderImpl : public FlocIdProvider,
// syncer::SyncServiceObserver: // syncer::SyncServiceObserver:
void OnStateChanged(syncer::SyncService* sync_service) override; void OnStateChanged(syncer::SyncService* sync_service) override;
void CalculateFloc(); void ComputeFloc(ComputeFlocTrigger trigger);
void OnComputeFlocCompleted(ComputeFlocTrigger trigger, FlocId floc_id);
void CheckCanComputeFlocId(CanComputeFlocIdCallback callback); void CheckCanComputeFloc(CanComputeFlocCallback callback);
void OnCheckCanComputeFlocIdCompleted(bool can_compute_floc); void OnCheckCanComputeFlocCompleted(ComputeFlocCompletedCallback callback,
bool can_compute_floc);
void GetRecentlyVisitedURLs(GetRecentlyVisitedURLsCallback callback); void GetRecentlyVisitedURLs(GetRecentlyVisitedURLsCallback callback);
void OnGetRecentlyVisitedURLsCompleted(size_t floc_session_count, void OnGetRecentlyVisitedURLsCompleted(ComputeFlocCompletedCallback callback,
history::QueryResults results); history::QueryResults results);
FlocId floc_id_; FlocId floc_id_;
size_t floc_session_count_ = 0; bool floc_computation_in_progress_ = false;
bool first_floc_computation_triggered_ = false;
syncer::SyncService* sync_service_; syncer::SyncService* sync_service_;
scoped_refptr<content_settings::CookieSettings> cookie_settings_; scoped_refptr<content_settings::CookieSettings> cookie_settings_;
...@@ -89,8 +104,8 @@ class FlocIdProviderImpl : public FlocIdProvider, ...@@ -89,8 +104,8 @@ class FlocIdProviderImpl : public FlocIdProvider,
// Used for the async tasks querying the HistoryService. // Used for the async tasks querying the HistoryService.
base::CancelableTaskTracker history_task_tracker_; base::CancelableTaskTracker history_task_tracker_;
// The timer used to start the floc session at regular intervals. // The timer used to schedule a floc computation.
base::RepeatingTimer floc_session_start_timer_; base::OneShotTimer compute_floc_timer_;
base::WeakPtrFactory<FlocIdProviderImpl> weak_ptr_factory_{this}; base::WeakPtrFactory<FlocIdProviderImpl> weak_ptr_factory_{this};
}; };
......
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