blob: fe279a32a230f3c94524281021b3f43b310049a6 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_MANAGER_IMPL_H_
#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_MANAGER_IMPL_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/sequence_bound.h"
#include "content/browser/aggregation_service/aggregation_service.h"
#include "content/browser/aggregation_service/report_scheduler_timer.h"
#include "content/browser/attribution_reporting/attribution_manager.h"
#include "content/browser/attribution_reporting/attribution_report.h"
#include "content/browser/attribution_reporting/attribution_report_sender.h"
#include "content/browser/attribution_reporting/attribution_reporting.mojom-forward.h"
#include "content/browser/attribution_reporting/destination_throttler.h"
#include "content/common/content_export.h"
#include "content/public/browser/storage_partition.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
namespace attribution_reporting {
class SuitableOrigin;
} // namespace attribution_reporting
namespace base {
class FilePath;
class TimeDelta;
class UpdateableSequencedTaskRunner;
} // namespace base
namespace storage {
class SpecialStoragePolicy;
} // namespace storage
namespace content {
class AggregatableReport;
class AggregatableReportRequest;
class AttributionCookieChecker;
class AttributionDataHostManager;
class AttributionDebugReport;
class AttributionOsLevelManager;
class AttributionStorage;
class AttributionStorageDelegate;
class CreateReportResult;
class StoragePartitionImpl;
struct GlobalRenderFrameHostId;
struct OsRegistration;
struct SendResult;
struct StoreSourceResult;
// UI thread class that manages the lifetime of the underlying attribution
// storage and coordinates sending attribution reports. Owned by the storage
// partition.
class CONTENT_EXPORT AttributionManagerImpl : public AttributionManager {
public:
// Configures underlying storage to be setup in memory, rather than on
// disk. This speeds up initialization to avoid timeouts in test environments.
class CONTENT_EXPORT ScopedUseInMemoryStorageForTesting {
public:
ScopedUseInMemoryStorageForTesting();
~ScopedUseInMemoryStorageForTesting();
ScopedUseInMemoryStorageForTesting(
const ScopedUseInMemoryStorageForTesting&) = delete;
ScopedUseInMemoryStorageForTesting& operator=(
const ScopedUseInMemoryStorageForTesting&) = delete;
ScopedUseInMemoryStorageForTesting(ScopedUseInMemoryStorageForTesting&&) =
delete;
ScopedUseInMemoryStorageForTesting& operator=(
ScopedUseInMemoryStorageForTesting&&) = delete;
private:
const bool previous_;
};
static std::unique_ptr<AttributionManagerImpl> CreateForTesting(
const base::FilePath& user_data_directory,
size_t max_pending_events,
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
std::unique_ptr<AttributionStorageDelegate> storage_delegate,
std::unique_ptr<AttributionCookieChecker> cookie_checker,
std::unique_ptr<AttributionReportSender> report_sender,
std::unique_ptr<AttributionOsLevelManager> os_level_manager,
StoragePartitionImpl* storage_partition,
scoped_refptr<base::UpdateableSequencedTaskRunner> storage_task_runner);
AttributionManagerImpl(
StoragePartitionImpl* storage_partition,
const base::FilePath& user_data_directory,
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy);
AttributionManagerImpl(const AttributionManagerImpl&) = delete;
AttributionManagerImpl& operator=(const AttributionManagerImpl&) = delete;
AttributionManagerImpl(AttributionManagerImpl&&) = delete;
AttributionManagerImpl& operator=(AttributionManagerImpl&&) = delete;
~AttributionManagerImpl() override;
// AttributionManager:
void AddObserver(AttributionObserver* observer) override;
void RemoveObserver(AttributionObserver* observer) override;
AttributionDataHostManager* GetDataHostManager() override;
void HandleSource(StorableSource source,
GlobalRenderFrameHostId render_frame_id) override;
void HandleTrigger(AttributionTrigger trigger,
GlobalRenderFrameHostId render_frame_id) override;
void GetActiveSourcesForWebUI(
base::OnceCallback<void(std::vector<StoredSource>)> callback) override;
void GetPendingReportsForInternalUse(
int limit,
base::OnceCallback<void(std::vector<AttributionReport>)> callback)
override;
void SendReportsForWebUI(const std::vector<AttributionReport::Id>& ids,
base::OnceClosure done) override;
void ClearData(base::Time delete_begin,
base::Time delete_end,
StoragePartition::StorageKeyMatcherFunction filter,
BrowsingDataFilterBuilder* filter_builder,
bool delete_rate_limit_data,
base::OnceClosure done) override;
void NotifyFailedSourceRegistration(
const std::string& header_value,
const attribution_reporting::SuitableOrigin& source_origin,
const attribution_reporting::SuitableOrigin& reporting_origin,
attribution_reporting::mojom::SourceType,
attribution_reporting::mojom::SourceRegistrationError) override;
void GetAllDataKeys(
base::OnceCallback<void(std::set<DataKey>)> callback) override;
void RemoveAttributionDataByDataKey(const DataKey& data_key,
base::OnceClosure callback) override;
void HandleOsRegistration(OsRegistration,
GlobalRenderFrameHostId render_frame_id) override;
void NotifyOsRegistration(const OsRegistration&,
bool is_debug_key_allowed,
attribution_reporting::mojom::OsRegistrationResult);
private:
friend class AttributionManagerImplTest;
using ReportSentCallback = AttributionReportSender::ReportSentCallback;
using SourceOrTrigger = absl::variant<StorableSource, AttributionTrigger>;
struct PendingReportTimings;
AttributionManagerImpl(
StoragePartitionImpl* storage_partition,
const base::FilePath& user_data_directory,
size_t max_pending_events,
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
std::unique_ptr<AttributionStorageDelegate> storage_delegate,
std::unique_ptr<AttributionCookieChecker> cookie_checker,
std::unique_ptr<AttributionReportSender> report_sender,
std::unique_ptr<AttributionOsLevelManager> os_level_manager,
scoped_refptr<base::UpdateableSequencedTaskRunner> storage_task_runner);
void MaybeEnqueueEvent(SourceOrTrigger);
void ProcessEvents();
void ProcessNextEvent(bool is_debug_cookie_set);
void StoreSource(StorableSource source, bool is_debug_cookie_set);
void StoreTrigger(AttributionTrigger trigger, bool is_debug_cookie_set);
void GetReportsToSend();
void OnGetReportsToSendFromWebUI(base::OnceClosure done,
std::vector<AttributionReport> reports);
void SendReports(base::RepeatingClosure web_ui_callback,
std::vector<AttributionReport> reports);
void PrepareToSendReport(AttributionReport report,
bool is_debug_report,
ReportSentCallback callback);
void OnReportSent(base::OnceClosure done,
const AttributionReport&,
SendResult info);
void AssembleAggregatableReport(AttributionReport report,
bool is_debug_report,
ReportSentCallback callback);
void OnAggregatableReportAssembled(
AttributionReport report,
bool is_debug_report,
ReportSentCallback callback,
AggregatableReportRequest,
absl::optional<AggregatableReport> assembled_report,
AggregationService::AssemblyStatus);
void MarkReportCompleted(AttributionReport::Id report_id);
void OnSourceStored(const StorableSource& source,
absl::optional<uint64_t> cleared_debug_key,
bool is_debug_cookie_set,
StoreSourceResult result);
void OnReportStored(const AttributionTrigger& trigger,
absl::optional<uint64_t> cleared_debug_key,
bool is_debug_cookie_set,
CreateReportResult result);
void MaybeSendDebugReport(AttributionReport&&);
void NotifySourcesChanged();
void NotifyReportsChanged();
void NotifyReportSent(bool is_debug_report,
const AttributionReport&,
SendResult);
void NotifyDebugReportSent(const AttributionDebugReport&, int status);
bool IsReportAllowed(const AttributionReport&) const;
void MaybeSendVerboseDebugReport(const StorableSource& source,
bool is_debug_cookie_set,
const StoreSourceResult& result);
void MaybeSendVerboseDebugReport(const AttributionTrigger& trigger,
bool is_debug_cookie_set,
const CreateReportResult& result);
void AddPendingAggregatableReportTiming(const AttributionReport&);
void RecordPendingAggregatableReportsTimings();
void OnClearDataComplete();
void ProcessNextOsEvent();
void OnOsRegistration(const OsRegistration&,
bool is_debug_key_allowed,
bool success);
DestinationThrottler throttler_;
// Never null.
const raw_ptr<StoragePartitionImpl> storage_partition_;
// Holds pending sources and triggers in the order they were received by the
// browser. For the time being, they must be processed in this order in order
// to ensure that behavioral requirements are met. We may be able to loosen
// this requirement in the future so that there are conceptually separate
// queues per <source origin, destination origin, reporting origin>.
base::circular_deque<SourceOrTrigger> pending_events_;
// Controls the maximum size of `pending_events_` to avoid unbounded memory
// growth with adversarial input.
size_t max_pending_events_;
// The task runner for all attribution reporting storage operations.
// Updateable to allow for priority to be temporarily increased to
// `USER_VISIBLE` when a clear data task is queued or running. Otherwise
// `BEST_EFFORT` is used.
scoped_refptr<base::UpdateableSequencedTaskRunner> storage_task_runner_;
// How many clear data storage tasks are queued or running currently, i.e.
// have been posted but the reply has not been run.
int num_pending_clear_data_tasks_ = 0;
base::SequenceBound<AttributionStorage> attribution_storage_;
ReportSchedulerTimer scheduler_timer_;
std::unique_ptr<AttributionDataHostManager> data_host_manager_;
// Storage policy for the browser context |this| is in. May be nullptr.
scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
std::unique_ptr<AttributionCookieChecker> cookie_checker_;
std::unique_ptr<AttributionReportSender> report_sender_;
// Set of all conversion IDs that are currently being sent, deleted, or
// updated. The number of concurrent conversion reports being sent at any time
// is expected to be small, so a `flat_set` is used.
base::flat_set<AttributionReport::Id> reports_being_sent_;
// We keep track of pending reports timings in memory to record metrics
// when the browser becomes unavailable to send reports due to becoming
// offline or being shutdown.
base::flat_map<AttributionReport::Id, PendingReportTimings>
pending_aggregatable_reports_;
base::ObserverList<AttributionObserver> observers_;
const std::unique_ptr<AttributionOsLevelManager> os_level_manager_;
base::circular_deque<OsRegistration> pending_os_events_;
base::WeakPtrFactory<AttributionManagerImpl> weak_factory_{this};
};
// Gets the delay for a report that has failed to be sent
// `failed_send_attempts` times.
// Returns `absl::nullopt` to indicate that no more attempts should be made.
// Otherwise, the return value must be positive. `failed_send_attempts` is
// guaranteed to be positive.
//
// Exposed here for testing.
CONTENT_EXPORT
absl::optional<base::TimeDelta> GetFailedReportDelay(int failed_send_attempts);
} // namespace content
#endif // CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_MANAGER_IMPL_H_