[BackgroundSync] Componentize BackgroundSyncControllerImpl.

Bug: 1087486, 1091211
Change-Id: I9c4ed3d09cce8c9e4fc7e708f1c94b990d8e93af
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2454169
Reviewed-by: Alexei Svitkine <[email protected]>
Reviewed-by: Colin Blundell <[email protected]>
Reviewed-by: Josh Karlin <[email protected]>
Commit-Queue: Alexei Svitkine <[email protected]>
Auto-Submit: Mugdha Lakhani <[email protected]>
Cr-Commit-Position: refs/heads/master@{#815153}
diff --git a/components/background_sync/BUILD.gn b/components/background_sync/BUILD.gn
index 3b0f0745..6a3f3309 100644
--- a/components/background_sync/BUILD.gn
+++ b/components/background_sync/BUILD.gn
@@ -4,6 +4,8 @@
 
 static_library("background_sync") {
   sources = [
+    "background_sync_controller_impl.cc",
+    "background_sync_controller_impl.h",
     "background_sync_delegate.h",
     "background_sync_metrics.cc",
     "background_sync_metrics.h",
@@ -15,9 +17,14 @@
     "//components/content_settings/core/browser",
     "//components/content_settings/core/common",
     "//components/permissions",
+    "//components/variations",
+    "//content/public/browser",
     "//services/metrics/public/cpp:ukm_builders",
     "//third_party/blink/public/common:headers",
   ]
+  if (!is_android) {
+    deps += [ "//components/keep_alive_registry" ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/components/background_sync/DEPS b/components/background_sync/DEPS
index 563121c..189c93c 100644
--- a/components/background_sync/DEPS
+++ b/components/background_sync/DEPS
@@ -1,5 +1,8 @@
 include_rules = [
   "+components/content_settings/core",
+  "+components/keep_alive_registry",
+  "+components/keyed_service/core",
+  "+components/variations",
   "+components/permissions",
   "+content/public/browser",
   "+content/public/test",
diff --git a/components/background_sync/background_sync_controller_impl.cc b/components/background_sync/background_sync_controller_impl.cc
new file mode 100644
index 0000000..8fe72bb
--- /dev/null
+++ b/components/background_sync/background_sync_controller_impl.cc
@@ -0,0 +1,408 @@
+// Copyright 2015 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 "components/background_sync/background_sync_controller_impl.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/keep_alive_registry/keep_alive_registry.h"
+#include "components/variations/variations_associated_data.h"
+#include "content/public/browser/background_sync_context.h"
+#include "content/public/browser/background_sync_controller.h"
+#include "content/public/browser/background_sync_parameters.h"
+#include "content/public/browser/background_sync_registration.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/storage_partition.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+// static
+const char BackgroundSyncControllerImpl::kFieldTrialName[] = "BackgroundSync";
+const char BackgroundSyncControllerImpl::kDisabledParameterName[] = "disabled";
+#if defined(OS_ANDROID)
+const char BackgroundSyncControllerImpl::kRelyOnAndroidNetworkDetection[] =
+    "rely_on_android_network_detection";
+#endif
+const char BackgroundSyncControllerImpl::kKeepBrowserAwakeParameterName[] =
+    "keep_browser_awake_till_events_complete";
+const char BackgroundSyncControllerImpl::kSkipPermissionsCheckParameterName[] =
+    "skip_permissions_check_for_testing";
+const char BackgroundSyncControllerImpl::kMaxAttemptsParameterName[] =
+    "max_sync_attempts";
+const char BackgroundSyncControllerImpl::
+    kMaxAttemptsWithNotificationPermissionParameterName[] =
+        "max_sync_attempts_with_notification_permission";
+const char BackgroundSyncControllerImpl::kInitialRetryParameterName[] =
+    "initial_retry_delay_sec";
+const char BackgroundSyncControllerImpl::kRetryDelayFactorParameterName[] =
+    "retry_delay_factor";
+const char BackgroundSyncControllerImpl::kMinSyncRecoveryTimeName[] =
+    "min_recovery_time_sec";
+const char BackgroundSyncControllerImpl::kMaxSyncEventDurationName[] =
+    "max_sync_event_duration_sec";
+const char BackgroundSyncControllerImpl::kMinPeriodicSyncEventsInterval[] =
+    "min_periodic_sync_events_interval_sec";
+
+BackgroundSyncControllerImpl::BackgroundSyncControllerImpl(
+    content::BrowserContext* browser_context,
+    std::unique_ptr<background_sync::BackgroundSyncDelegate> delegate)
+    : browser_context_(browser_context), delegate_(std::move(delegate)) {
+  DCHECK(browser_context_);
+  DCHECK(delegate_);
+
+  background_sync_metrics_ =
+      std::make_unique<BackgroundSyncMetrics>(delegate_.get());
+  delegate_->GetHostContentSettingsMap()->AddObserver(this);
+}
+
+BackgroundSyncControllerImpl::~BackgroundSyncControllerImpl() = default;
+
+void BackgroundSyncControllerImpl::OnContentSettingChanged(
+    const ContentSettingsPattern& primary_pattern,
+    const ContentSettingsPattern& secondary_pattern,
+    ContentSettingsType content_type,
+    const std::string& resource_identifier) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (content_type != ContentSettingsType::BACKGROUND_SYNC &&
+      content_type != ContentSettingsType::PERIODIC_BACKGROUND_SYNC) {
+    return;
+  }
+
+  std::vector<url::Origin> affected_origins;
+  for (const auto& origin : periodic_sync_origins_) {
+    if (!IsContentSettingBlocked(origin))
+      continue;
+
+    auto* storage_partition =
+        content::BrowserContext::GetStoragePartitionForSite(
+            browser_context_, origin.GetURL(), /* can_create= */ false);
+    if (!storage_partition)
+      continue;
+
+    auto* background_sync_context =
+        storage_partition->GetBackgroundSyncContext();
+    if (!background_sync_context)
+      continue;
+
+    background_sync_context->UnregisterPeriodicSyncForOrigin(origin);
+    affected_origins.push_back(origin);
+  }
+
+  // Stop tracking affected origins.
+  for (const auto& origin : affected_origins) {
+    periodic_sync_origins_.erase(origin);
+  }
+}
+
+void BackgroundSyncControllerImpl::GetParameterOverrides(
+    content::BackgroundSyncParameters* parameters) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+#if defined(OS_ANDROID)
+  if (delegate_->ShouldDisableBackgroundSync())
+    parameters->disable = true;
+#endif
+
+  std::map<std::string, std::string> field_params;
+  if (!variations::GetVariationParams(kFieldTrialName, &field_params))
+    return;
+
+  if (base::LowerCaseEqualsASCII(field_params[kDisabledParameterName],
+                                 "true")) {
+    parameters->disable = true;
+  }
+
+  if (base::LowerCaseEqualsASCII(field_params[kKeepBrowserAwakeParameterName],
+                                 "true")) {
+    parameters->keep_browser_awake_till_events_complete = true;
+  }
+
+  if (base::LowerCaseEqualsASCII(
+          field_params[kSkipPermissionsCheckParameterName], "true")) {
+    parameters->skip_permissions_check_for_testing = true;
+  }
+
+  if (base::Contains(field_params,
+                     kMaxAttemptsWithNotificationPermissionParameterName)) {
+    int max_attempts;
+    if (base::StringToInt(
+            field_params[kMaxAttemptsWithNotificationPermissionParameterName],
+            &max_attempts)) {
+      parameters->max_sync_attempts_with_notification_permission = max_attempts;
+    }
+  }
+
+  if (base::Contains(field_params, kMaxAttemptsParameterName)) {
+    int max_attempts;
+    if (base::StringToInt(field_params[kMaxAttemptsParameterName],
+                          &max_attempts)) {
+      parameters->max_sync_attempts = max_attempts;
+    }
+  }
+
+  if (base::Contains(field_params, kInitialRetryParameterName)) {
+    int initial_retry_delay_sec;
+    if (base::StringToInt(field_params[kInitialRetryParameterName],
+                          &initial_retry_delay_sec)) {
+      parameters->initial_retry_delay =
+          base::TimeDelta::FromSeconds(initial_retry_delay_sec);
+    }
+  }
+
+  if (base::Contains(field_params, kRetryDelayFactorParameterName)) {
+    int retry_delay_factor;
+    if (base::StringToInt(field_params[kRetryDelayFactorParameterName],
+                          &retry_delay_factor)) {
+      parameters->retry_delay_factor = retry_delay_factor;
+    }
+  }
+
+  if (base::Contains(field_params, kMinSyncRecoveryTimeName)) {
+    int min_sync_recovery_time_sec;
+    if (base::StringToInt(field_params[kMinSyncRecoveryTimeName],
+                          &min_sync_recovery_time_sec)) {
+      parameters->min_sync_recovery_time =
+          base::TimeDelta::FromSeconds(min_sync_recovery_time_sec);
+    }
+  }
+
+  if (base::Contains(field_params, kMaxSyncEventDurationName)) {
+    int max_sync_event_duration_sec;
+    if (base::StringToInt(field_params[kMaxSyncEventDurationName],
+                          &max_sync_event_duration_sec)) {
+      parameters->max_sync_event_duration =
+          base::TimeDelta::FromSeconds(max_sync_event_duration_sec);
+    }
+  }
+
+  if (base::Contains(field_params, kMinPeriodicSyncEventsInterval)) {
+    int min_periodic_sync_events_interval_sec;
+    if (base::StringToInt(field_params[kMinPeriodicSyncEventsInterval],
+                          &min_periodic_sync_events_interval_sec)) {
+      parameters->min_periodic_sync_events_interval =
+          base::TimeDelta::FromSeconds(min_periodic_sync_events_interval_sec);
+    }
+  }
+
+  return;
+}
+
+void BackgroundSyncControllerImpl::NotifyOneShotBackgroundSyncRegistered(
+    const url::Origin& origin,
+    bool can_fire,
+    bool is_reregistered) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  background_sync_metrics_->MaybeRecordOneShotSyncRegistrationEvent(
+      origin, can_fire, is_reregistered);
+}
+
+void BackgroundSyncControllerImpl::NotifyPeriodicBackgroundSyncRegistered(
+    const url::Origin& origin,
+    int min_interval,
+    bool is_reregistered) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  background_sync_metrics_->MaybeRecordPeriodicSyncRegistrationEvent(
+      origin, min_interval, is_reregistered);
+}
+
+void BackgroundSyncControllerImpl::NotifyOneShotBackgroundSyncCompleted(
+    const url::Origin& origin,
+    blink::ServiceWorkerStatusCode status_code,
+    int num_attempts,
+    int max_attempts) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  background_sync_metrics_->MaybeRecordOneShotSyncCompletionEvent(
+      origin, status_code, num_attempts, max_attempts);
+}
+
+void BackgroundSyncControllerImpl::NotifyPeriodicBackgroundSyncCompleted(
+    const url::Origin& origin,
+    blink::ServiceWorkerStatusCode status_code,
+    int num_attempts,
+    int max_attempts) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  background_sync_metrics_->MaybeRecordPeriodicSyncEventCompletion(
+      origin, status_code, num_attempts, max_attempts);
+}
+
+void BackgroundSyncControllerImpl::ScheduleBrowserWakeUpWithDelay(
+    blink::mojom::BackgroundSyncType sync_type,
+    base::TimeDelta delay) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (delegate_->IsProfileOffTheRecord())
+    return;
+
+#if defined(OS_ANDROID)
+  delegate_->ScheduleBrowserWakeUpWithDelay(sync_type, delay);
+#endif
+}
+
+void BackgroundSyncControllerImpl::CancelBrowserWakeup(
+    blink::mojom::BackgroundSyncType sync_type) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (delegate_->IsProfileOffTheRecord())
+    return;
+
+#if defined(OS_ANDROID)
+  delegate_->CancelBrowserWakeup(sync_type);
+#endif
+}
+
+int BackgroundSyncControllerImpl::GetSiteEngagementPenalty(const GURL& url) {
+  return delegate_->GetSiteEngagementPenalty(url);
+}
+
+base::TimeDelta BackgroundSyncControllerImpl::SnapToMaxOriginFrequency(
+    int64_t min_interval,
+    int64_t min_gap_for_origin) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  DCHECK_GE(min_gap_for_origin, 0);
+  DCHECK_GE(min_interval, 0);
+
+  if (min_interval < min_gap_for_origin)
+    return base::TimeDelta::FromMilliseconds(min_gap_for_origin);
+  if (min_interval % min_gap_for_origin == 0)
+    return base::TimeDelta::FromMilliseconds(min_interval);
+  return base::TimeDelta::FromMilliseconds(
+      (min_interval / min_gap_for_origin + 1) * min_gap_for_origin);
+}
+
+base::TimeDelta BackgroundSyncControllerImpl::ApplyMinGapForOrigin(
+    base::TimeDelta delay,
+    base::TimeDelta time_till_next_scheduled_event_for_origin,
+    base::TimeDelta min_gap_for_origin) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (time_till_next_scheduled_event_for_origin.is_max())
+    return delay;
+
+  if (delay <= time_till_next_scheduled_event_for_origin - min_gap_for_origin)
+    return delay;
+
+  if (delay <= time_till_next_scheduled_event_for_origin)
+    return time_till_next_scheduled_event_for_origin;
+
+  if (delay <= time_till_next_scheduled_event_for_origin + min_gap_for_origin)
+    return time_till_next_scheduled_event_for_origin + min_gap_for_origin;
+
+  return delay;
+}
+
+bool BackgroundSyncControllerImpl::IsContentSettingBlocked(
+    const url::Origin& origin) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  auto* host_content_settings_map = delegate_->GetHostContentSettingsMap();
+  DCHECK(host_content_settings_map);
+
+  auto url = origin.GetURL();
+  return CONTENT_SETTING_ALLOW != host_content_settings_map->GetContentSetting(
+                                      /* primary_url= */ url,
+                                      /* secondary_url= */ url,
+                                      ContentSettingsType::BACKGROUND_SYNC,
+                                      /* resource_identifier= */ std::string());
+}
+
+void BackgroundSyncControllerImpl::Shutdown() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  delegate_->GetHostContentSettingsMap()->RemoveObserver(this);
+  delegate_->Shutdown();
+}
+
+base::TimeDelta BackgroundSyncControllerImpl::GetNextEventDelay(
+    const content::BackgroundSyncRegistration& registration,
+    content::BackgroundSyncParameters* parameters,
+    base::TimeDelta time_till_soonest_scheduled_event_for_origin) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(parameters);
+
+  int num_attempts = registration.num_attempts();
+
+  if (!num_attempts) {
+    // First attempt.
+    switch (registration.sync_type()) {
+      case blink::mojom::BackgroundSyncType::ONE_SHOT:
+        return base::TimeDelta();
+      case blink::mojom::BackgroundSyncType::PERIODIC:
+        int site_engagement_factor =
+            delegate_->GetSiteEngagementPenalty(registration.origin().GetURL());
+        if (!site_engagement_factor)
+          return base::TimeDelta::Max();
+
+        int64_t effective_gap_ms =
+            site_engagement_factor *
+            parameters->min_periodic_sync_events_interval.InMilliseconds();
+        return ApplyMinGapForOrigin(
+            SnapToMaxOriginFrequency(registration.options()->min_interval,
+                                     effective_gap_ms),
+            time_till_soonest_scheduled_event_for_origin,
+            parameters->min_periodic_sync_events_interval);
+    }
+  }
+
+  // After a sync event has been fired.
+  DCHECK_LT(num_attempts, parameters->max_sync_attempts);
+  return parameters->initial_retry_delay *
+         pow(parameters->retry_delay_factor, num_attempts - 1);
+}
+
+std::unique_ptr<content::BackgroundSyncController::BackgroundSyncEventKeepAlive>
+BackgroundSyncControllerImpl::CreateBackgroundSyncEventKeepAlive() {
+#if !defined(OS_ANDROID)
+  if (!KeepAliveRegistry::GetInstance()->IsShuttingDown())
+    return std::make_unique<BackgroundSyncEventKeepAliveImpl>();
+#endif
+  return nullptr;
+}
+
+#if !defined(OS_ANDROID)
+BackgroundSyncControllerImpl::BackgroundSyncEventKeepAliveImpl::
+    BackgroundSyncEventKeepAliveImpl() {
+  keepalive_ = std::unique_ptr<ScopedKeepAlive,
+                               content::BrowserThread::DeleteOnUIThread>(
+      new ScopedKeepAlive(KeepAliveOrigin::BACKGROUND_SYNC,
+                          KeepAliveRestartOption::DISABLED));
+}
+
+BackgroundSyncControllerImpl::BackgroundSyncEventKeepAliveImpl::
+    ~BackgroundSyncEventKeepAliveImpl() = default;
+#endif
+
+void BackgroundSyncControllerImpl::NoteSuspendedPeriodicSyncOrigins(
+    std::set<url::Origin> suspended_origins) {
+  delegate_->NoteSuspendedPeriodicSyncOrigins(std::move(suspended_origins));
+}
+
+void BackgroundSyncControllerImpl::NoteRegisteredPeriodicSyncOrigins(
+    std::set<url::Origin> registered_origins) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  for (auto& origin : registered_origins)
+    periodic_sync_origins_.insert(std::move(origin));
+}
+
+void BackgroundSyncControllerImpl::AddToTrackedOrigins(
+    const url::Origin& origin) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  periodic_sync_origins_.insert(origin);
+}
+
+void BackgroundSyncControllerImpl::RemoveFromTrackedOrigins(
+    const url::Origin& origin) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  periodic_sync_origins_.erase(origin);
+}
diff --git a/components/background_sync/background_sync_controller_impl.h b/components/background_sync/background_sync_controller_impl.h
new file mode 100644
index 0000000..5190de9
--- /dev/null
+++ b/components/background_sync/background_sync_controller_impl.h
@@ -0,0 +1,156 @@
+// Copyright 2015 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 COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_IMPL_H_
+#define COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_IMPL_H_
+
+#include "content/public/browser/background_sync_controller.h"
+
+#include <stdint.h>
+
+#include <set>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/background_sync/background_sync_delegate.h"
+#include "components/background_sync/background_sync_metrics.h"
+#include "components/content_settings/core/browser/content_settings_observer.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/background_sync_registration.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/mojom/background_sync/background_sync.mojom-forward.h"
+
+namespace content {
+struct BackgroundSyncParameters;
+class BrowserContext;
+}  // namespace content
+
+namespace url {
+class Origin;
+}  // namespace url
+
+class GURL;
+
+class BackgroundSyncControllerImpl : public content::BackgroundSyncController,
+                                     public KeyedService,
+                                     public content_settings::Observer {
+ public:
+  static const char kFieldTrialName[];
+  static const char kDisabledParameterName[];
+  static const char kKeepBrowserAwakeParameterName[];
+  static const char kSkipPermissionsCheckParameterName[];
+  static const char kMaxAttemptsParameterName[];
+  static const char kRelyOnAndroidNetworkDetection[];
+  static const char kMaxAttemptsWithNotificationPermissionParameterName[];
+  static const char kInitialRetryParameterName[];
+  static const char kRetryDelayFactorParameterName[];
+  static const char kMinSyncRecoveryTimeName[];
+  static const char kMaxSyncEventDurationName[];
+  static const char kMinPeriodicSyncEventsInterval[];
+
+#if !defined(OS_ANDROID)
+  class BackgroundSyncEventKeepAliveImpl : public BackgroundSyncEventKeepAlive {
+   public:
+    ~BackgroundSyncEventKeepAliveImpl() override;
+    BackgroundSyncEventKeepAliveImpl();
+
+   private:
+    std::unique_ptr<ScopedKeepAlive, content::BrowserThread::DeleteOnUIThread>
+        keepalive_ = nullptr;
+  };
+#endif
+
+  BackgroundSyncControllerImpl(
+      content::BrowserContext* browser_context,
+      std::unique_ptr<background_sync::BackgroundSyncDelegate> delegate);
+  ~BackgroundSyncControllerImpl() override;
+
+  // content::BackgroundSyncController overrides.
+  void GetParameterOverrides(
+      content::BackgroundSyncParameters* parameters) override;
+  void NotifyOneShotBackgroundSyncRegistered(const url::Origin& origin,
+                                             bool can_fire,
+                                             bool is_reregistered) override;
+  void NotifyPeriodicBackgroundSyncRegistered(const url::Origin& origin,
+                                              int min_interval,
+                                              bool is_reregistered) override;
+  void NotifyOneShotBackgroundSyncCompleted(
+      const url::Origin& origin,
+      blink::ServiceWorkerStatusCode status_code,
+      int num_attempts,
+      int max_attempts) override;
+  void NotifyPeriodicBackgroundSyncCompleted(
+      const url::Origin& origin,
+      blink::ServiceWorkerStatusCode status_code,
+      int num_attempts,
+      int max_attempts) override;
+  void ScheduleBrowserWakeUpWithDelay(
+      blink::mojom::BackgroundSyncType sync_type,
+      base::TimeDelta delay) override;
+  void CancelBrowserWakeup(blink::mojom::BackgroundSyncType sync_type) override;
+
+  base::TimeDelta GetNextEventDelay(
+      const content::BackgroundSyncRegistration& registration,
+      content::BackgroundSyncParameters* parameters,
+      base::TimeDelta time_till_soonest_scheduled_event_for_origin) override;
+
+  std::unique_ptr<BackgroundSyncEventKeepAlive>
+  CreateBackgroundSyncEventKeepAlive() override;
+  void NoteSuspendedPeriodicSyncOrigins(
+      std::set<url::Origin> suspended_origins) override;
+  void NoteRegisteredPeriodicSyncOrigins(
+      std::set<url::Origin> registered_origins) override;
+  void AddToTrackedOrigins(const url::Origin& origin) override;
+  void RemoveFromTrackedOrigins(const url::Origin& origin) override;
+
+  // content_settings::Observer overrides.
+  void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
+                               const ContentSettingsPattern& secondary_pattern,
+                               ContentSettingsType content_type,
+                               const std::string& resource_identifier) override;
+
+  bool IsOriginTracked(const url::Origin& origin) {
+    return periodic_sync_origins_.find(origin) != periodic_sync_origins_.end();
+  }
+
+ private:
+  // Gets the site engagement penalty for |url|, which is inversely proportional
+  // to the engagement level. The lower the engagement levels with the site,
+  // the less often periodic sync events will be fired.
+  // Returns kEngagementLevelNonePenalty if the engagement level is
+  // blink::mojom::EngagementLevel::NONE.
+  virtual int GetSiteEngagementPenalty(const GURL& url);
+
+  // Once we've identified the minimum number of hours between each periodicsync
+  // event for an origin, every delay calculated for the origin should be a
+  // multiple of the same.
+  base::TimeDelta SnapToMaxOriginFrequency(int64_t min_interval,
+                                           int64_t min_gap_for_origin);
+
+  // Returns an updated delay for a Periodic Background Sync registration -- one
+  // that ensures the |min_gap_for_origin|.
+  base::TimeDelta ApplyMinGapForOrigin(
+      base::TimeDelta delay,
+      base::TimeDelta time_till_next_scheduled_event_for_origin,
+      base::TimeDelta min_gap_for_origin);
+
+  bool IsContentSettingBlocked(const url::Origin& origin);
+
+  // KeyedService implementation.
+  void Shutdown() override;
+
+  content::BrowserContext* browser_context_;
+
+  std::unique_ptr<background_sync::BackgroundSyncDelegate> delegate_;
+  std::unique_ptr<BackgroundSyncMetrics> background_sync_metrics_;
+
+  std::set<url::Origin> periodic_sync_origins_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundSyncControllerImpl);
+};
+
+#endif  // COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_IMPL_H_