blob: b07eca5d880b62a1acafbf166f3c0eeca26a7fdc [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_BROWSING_TOPICS_BROWSING_TOPICS_SERVICE_IMPL_H_
#define COMPONENTS_BROWSING_TOPICS_BROWSING_TOPICS_SERVICE_IMPL_H_
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/timer/timer.h"
#include "components/browsing_topics/browsing_topics_calculator.h"
#include "components/browsing_topics/browsing_topics_service.h"
#include "components/browsing_topics/browsing_topics_state.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/privacy_sandbox/privacy_sandbox_settings.h"
namespace content {
class BrowsingTopicsSiteDataManager;
} // namespace content
namespace optimization_guide {
class PageContentAnnotationsService;
} // namespace optimization_guide
namespace browsing_topics {
// A profile keyed service for scheduling browsing topics calculation,
// calculating the topics to give to a requesting context or to other internal
// components (e.g. UX), and handling relevant data deletion. Browsing topics
// calculation will happen periodically every time period of
// `kBrowsingTopicsTimePeriodPerEpoch`. See the `BrowsingTopicsCalculator` class
// for the calculation details.
class BrowsingTopicsServiceImpl
: public BrowsingTopicsService,
public privacy_sandbox::PrivacySandboxSettings::Observer,
public history::HistoryServiceObserver {
public:
BrowsingTopicsServiceImpl(const BrowsingTopicsServiceImpl&) = delete;
BrowsingTopicsServiceImpl& operator=(const BrowsingTopicsServiceImpl&) =
delete;
BrowsingTopicsServiceImpl(BrowsingTopicsServiceImpl&&) = delete;
BrowsingTopicsServiceImpl& operator=(BrowsingTopicsServiceImpl&&) = delete;
~BrowsingTopicsServiceImpl() override;
bool HandleTopicsWebApi(
const url::Origin& context_origin,
content::RenderFrameHost* main_frame,
ApiCallerSource caller_source,
bool get_topics,
bool observe,
std::vector<blink::mojom::EpochTopicPtr>& topics) override;
void GetBrowsingTopicsStateForWebUi(
bool calculate_now,
mojom::PageHandler::GetBrowsingTopicsStateCallback callback) override;
std::vector<privacy_sandbox::CanonicalTopic> GetTopTopicsForDisplay()
const override;
void ClearTopic(
const privacy_sandbox::CanonicalTopic& canonical_topic) override;
void ClearTopicsDataForOrigin(const url::Origin& origin) override;
void ClearAllTopicsData() override;
protected:
// The following methods are marked protected so that they may be overridden
// by tests.
virtual std::unique_ptr<BrowsingTopicsCalculator> CreateCalculator(
privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings,
history::HistoryService* history_service,
content::BrowsingTopicsSiteDataManager* site_data_manager,
optimization_guide::PageContentAnnotationsService* annotations_service,
const base::circular_deque<EpochTopics>& epochs,
BrowsingTopicsCalculator::CalculateCompletedCallback callback);
// Allow tests to access `browsing_topics_state_`.
virtual const BrowsingTopicsState& browsing_topics_state();
// privacy_sandbox::PrivacySandboxSettings::Observer:
//
// When the floc-accessible-since time is updated (due to e.g. cookies
// deletion), we'll invalidate the underlying browsing topics.
void OnTopicsDataAccessibleSinceUpdated() override;
// history::HistoryServiceObserver:
//
// On history deletion, the top topics of history epochs will be invalidated
// if the deletion time range overlaps with the time range of the underlying
// data used to derive the topics.
void OnURLsDeleted(history::HistoryService* history_service,
const history::DeletionInfo& deletion_info) override;
// Called when the outstanding calculation completes. It's going to reset
// `topics_calculator_`, add the new `epoch_topics` to `browsing_topics_`, and
// schedule the next calculation.
virtual void OnCalculateBrowsingTopicsCompleted(EpochTopics epoch_topics);
private:
friend class BrowsingTopicsServiceFactory;
friend class BrowsingTopicsBrowserTest;
friend class TesterBrowsingTopicsService;
using TopicAccessedCallback =
base::RepeatingCallback<void(content::RenderFrameHost* rfh,
const url::Origin& api_origin,
bool blocked_by_policy,
privacy_sandbox::CanonicalTopic topic)>;
BrowsingTopicsServiceImpl(
const base::FilePath& profile_path,
privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings,
history::HistoryService* history_service,
content::BrowsingTopicsSiteDataManager* site_data_manager,
optimization_guide::PageContentAnnotationsService* annotations_service,
TopicAccessedCallback topic_accessed_callback);
void ScheduleBrowsingTopicsCalculation(base::TimeDelta delay);
// Initialize `topics_calculator_` to start calculating this epoch's top
// topics and context observed topics.
void CalculateBrowsingTopics();
// Set `browsing_topics_state_loaded_` to true. Start scheduling the topics
// calculation.
void OnBrowsingTopicsStateLoaded();
// KeyedService:
void Shutdown() override;
mojom::WebUIGetBrowsingTopicsStateResultPtr
GetBrowsingTopicsStateForWebUiHelper();
// These pointers are safe to hold and use throughout the lifetime of
// `this`:
// - For `privacy_sandbox_settings_`, `history_service_` and
// `annotations_service_`: the dependency declared in
// `BrowsingTopicsServiceFactory`'s constructor guarantees that
// `BrowsingTopicsService` will be destroyed first before those depend-on
// services.
// - For `site_data_manager_`: it lives in the StoragePartition which lives
// in the BrowserContext, and thus outlives all BrowserContext's KeyedService.
raw_ptr<privacy_sandbox::PrivacySandboxSettings> privacy_sandbox_settings_;
raw_ptr<history::HistoryService> history_service_;
raw_ptr<content::BrowsingTopicsSiteDataManager> site_data_manager_;
raw_ptr<optimization_guide::PageContentAnnotationsService>
annotations_service_;
BrowsingTopicsState browsing_topics_state_;
// Whether the `browsing_topics_state_` has finished loading. Before the
// loading finishes, accessor methods will use a default handling (i.e. return
// an empty value; skip usage tracking; ignore data deletions). This is fine
// in practice, as the loading should be reasonably fast, and normally the API
// usage or data deletion won't happen at the browser start.
bool browsing_topics_state_loaded_ = false;
// This is non-null if a calculation is in progress. A calculation can be
// triggered periodically, or due to the "Calculate Now" request from the
// WebUI.
std::unique_ptr<BrowsingTopicsCalculator> topics_calculator_;
// This is populated when a request for the topics state arrives during an
// ongoing topics calculation, or for a request that requires "Calculate Now"
// in the first place. Callbacks will be invoked to return the latest topics
// state as soon as the ongoing calculation finishes, and
// `get_state_for_webui_callbacks_` will be cleared afterwards.
std::vector<mojom::PageHandler::GetBrowsingTopicsStateCallback>
get_state_for_webui_callbacks_;
base::OneShotTimer schedule_calculate_timer_;
TopicAccessedCallback topic_accessed_callback_;
base::ScopedObservation<privacy_sandbox::PrivacySandboxSettings,
privacy_sandbox::PrivacySandboxSettings::Observer>
privacy_sandbox_settings_observation_{this};
base::ScopedObservation<history::HistoryService,
history::HistoryServiceObserver>
history_service_observation_{this};
base::WeakPtrFactory<BrowsingTopicsServiceImpl> weak_ptr_factory_{this};
};
} // namespace browsing_topics
#endif // COMPONENTS_BROWSING_TOPICS_BROWSING_TOPICS_SERVICE_IMPL_H_