123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- // 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/containers/contains.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_util.h"
- #include "base/time/time.h"
- #include "build/build_config.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 BUILDFLAG(IS_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,
- ContentSettingsTypeSet content_type_set) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (!content_type_set.Contains(ContentSettingsType::BACKGROUND_SYNC) &&
- !content_type_set.Contains(
- 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 = browser_context_->GetStoragePartitionForUrl(
- 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 BUILDFLAG(IS_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::EqualsCaseInsensitiveASCII(field_params[kDisabledParameterName],
- "true")) {
- parameters->disable = true;
- }
- if (base::EqualsCaseInsensitiveASCII(
- field_params[kKeepBrowserAwakeParameterName], "true")) {
- parameters->keep_browser_awake_till_events_complete = true;
- }
- if (base::EqualsCaseInsensitiveASCII(
- 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::Seconds(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::Seconds(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::Seconds(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::Seconds(min_periodic_sync_events_interval_sec);
- }
- }
- #if BUILDFLAG(IS_ANDROID)
- // Check if the delegate explicitly disabled this feature.
- if (delegate_->ShouldDisableAndroidNetworkDetection()) {
- parameters->rely_on_android_network_detection = false;
- } else if (base::Contains(field_params, kRelyOnAndroidNetworkDetection)) {
- if (base::EqualsCaseInsensitiveASCII(
- field_params[kRelyOnAndroidNetworkDetection], "true")) {
- parameters->rely_on_android_network_detection = true;
- }
- }
- #endif
- 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 BUILDFLAG(IS_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 BUILDFLAG(IS_ANDROID)
- delegate_->CancelBrowserWakeup(sync_type);
- #endif
- }
- 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::Milliseconds(min_gap_for_origin);
- if (min_interval % min_gap_for_origin == 0)
- return base::Milliseconds(min_interval);
- return base::Milliseconds((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);
- }
- 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 BUILDFLAG(IS_ANDROID)
- // Not needed on Android.
- return nullptr;
- #else
- return delegate_->CreateBackgroundSyncEventKeepAlive();
- #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);
- }
|