[go: nahoru, domu]

blob: df21666a20ad31f08345329dda0844cf5e206fec [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 CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATABLE_REPORT_SCHEDULER_H_
#define CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATABLE_REPORT_SCHEDULER_H_
#include <optional>
#include <set>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/aggregation_service/aggregation_service_storage.h"
#include "content/browser/aggregation_service/report_scheduler_timer.h"
#include "content/common/content_export.h"
namespace base {
class ElapsedTimer;
class Time;
} // namespace base
namespace content {
class AggregatableReportRequest;
class AggregationServiceStorageContext;
// UI thread class that is responsible for interacting with the storage layer
// for report requests, waiting for a report's reporting time to be reached and
// then calling the appropriate callback.
//
// Note that report requests can have one of two states: "pending" or
// "in-progress". This represents whether the request is currently being
// processed (i.e. assembled and sent). To ensure that no report is 'lost',
// all requests (that haven't been deleted) become pending once more on start
// up. Note that all reports with future report times are pending (unless wall
// clock time goes backward).
class CONTENT_EXPORT AggregatableReportScheduler {
public:
// Add uniform random noise in the range of [0, 1 minutes] to the report time
// when the browser comes back online. Aligned with
// `AttributionStorageDelegateImpl::GetOfflineReportDelayConfig()`.
static constexpr base::TimeDelta kOfflineReportTimeMinimumDelay =
base::Minutes(0);
static constexpr base::TimeDelta kOfflineReportTimeMaximumDelay =
base::Minutes(1);
// Configuration for retrying to send reports that failed to send
static constexpr int kMaxRetries = 2;
static constexpr base::TimeDelta kInitialRetryDelay = base::Minutes(5);
static constexpr int kRetryDelayFactor = 3;
AggregatableReportScheduler(
AggregationServiceStorageContext* storage_context,
base::RepeatingCallback<
void(std::vector<AggregationServiceStorage::RequestAndId>)>
on_scheduled_report_time_reached);
AggregatableReportScheduler(const AggregatableReportScheduler& other) =
delete;
AggregatableReportScheduler& operator=(
const AggregatableReportScheduler& other) = delete;
virtual ~AggregatableReportScheduler();
// Methods are virtual for testing.
// Schedules the `request` to be assembled and sent at
// `request.shared_info().scheduled_report_time`.
virtual void ScheduleRequest(AggregatableReportRequest request);
// Notifies that the request to assemble and send the report with `request_id`
// was successfully completed. There must be an in-progress request stored
// with that `request_id`.
virtual void NotifyInProgressRequestSucceeded(
AggregationServiceStorage::RequestId request_id);
// Notifies that the request to assemble and send the report with `request_id`
// completed unsuccessfully. There must be an in-progress request stored with
// that `request_id`.`failed_attemps_before_sending` is the number of times
// that this request previously failed. ie. not counting the failure being
// notified on.
// Returns true when the request will be scheduled to be retried.
// Returns false when the request is dropped. ie. it wont be retried.
virtual bool NotifyInProgressRequestFailed(
AggregationServiceStorage::RequestId request_id,
int previous_failed_attempts);
private:
class TimerDelegate : public ReportSchedulerTimer::Delegate {
public:
TimerDelegate(AggregationServiceStorageContext* storage_context,
base::RepeatingCallback<void(
std::vector<AggregationServiceStorage::RequestAndId>)>
on_scheduled_report_time_reached);
~TimerDelegate() override;
TimerDelegate(const TimerDelegate&) = delete;
TimerDelegate& operator=(const TimerDelegate&) = delete;
TimerDelegate(TimerDelegate&&) = delete;
TimerDelegate& operator=(TimerDelegate&&) = delete;
// Notifies that we no longer need to track `request_id` as in-progress.
void NotifySendAttemptCompleted(
AggregationServiceStorage::RequestId request_id);
base::WeakPtr<AggregatableReportScheduler::TimerDelegate> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
// ReportSchedulerTimer::Delegate:
void GetNextReportTime(base::OnceCallback<void(std::optional<base::Time>)>,
base::Time now) override;
void OnReportingTimeReached(base::Time now,
base::Time timer_desired_run_time) override;
void AdjustOfflineReportTimes(
base::OnceCallback<void(std::optional<base::Time>)>) override;
void OnRequestsReturnedFromStorage(
base::ElapsedTimer task_timer,
std::vector<AggregationServiceStorage::RequestAndId> requests_and_ids);
// Using a raw reference is safe because `storage_context_` is guaranteed to
// outlive `this`.
raw_ref<AggregationServiceStorageContext> storage_context_;
// Called when a report request's scheduled report time is reached. May
// return multiple requests if their report times were all reached before
// the timer fired. If multiple requests are returned, they will be ordered
// by the report time (which may differ from the initially scheduled report
// time).
base::RepeatingCallback<void(
std::vector<AggregationServiceStorage::RequestAndId>)>
on_scheduled_report_time_reached_;
// The set of IDs of all in-progress report requests.
// TODO(alexmt): Consider switching to a flat_set when we have metrics on
// the typical size.
std::set<AggregationServiceStorage::RequestId> in_progress_requests_;
// Set iff the private aggregation developer mode is enabled.
bool should_not_delay_reports_;
base::WeakPtrFactory<AggregatableReportScheduler::TimerDelegate>
weak_ptr_factory_{this};
};
// Returns how long to wait before attempting to send a report that has
// previously failed to be sent failed_send_attempts times. Returns
// `std::nullopt` to indicate that no more attempts should be made.
// Otherwise, the return value must be positive. `failed_send_attempts`
// must be positive.
static std::optional<base::TimeDelta> GetFailedReportDelay(
int failed_send_attempts);
// Using a raw reference is safe because `storage_context_` is guaranteed to
// outlive `this`.
raw_ref<AggregationServiceStorageContext> storage_context_;
// Using a raw pointer is safe because it's owned by `timer_`. Will be cleared
// in the destructor to avoid a dangling pointer.
raw_ptr<TimerDelegate> timer_delegate_;
ReportSchedulerTimer timer_;
};
} // namespace content
#endif // CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATABLE_REPORT_SCHEDULER_H_