blob: 330616aa8d37a8ffaf042830b69cca8dac22d84f [file] [log] [blame]
// 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 "content/browser/background_sync/background_sync_context_impl.h"
#include <utility>
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "content/browser/background_sync/background_sync_launcher.h"
#include "content/browser/background_sync/background_sync_manager.h"
#include "content/browser/background_sync/one_shot_background_sync_service_impl.h"
#include "content/browser/background_sync/periodic_background_sync_service_impl.h"
#include "content/browser/devtools/devtools_background_services_context_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/blink/public/mojom/background_sync/background_sync.mojom.h"
#include "url/origin.h"
namespace content {
BackgroundSyncContextImpl::BackgroundSyncContextImpl()
: base::RefCountedDeleteOnSequence<BackgroundSyncContextImpl>(
base::CreateSingleThreadTaskRunner(
{ServiceWorkerContext::GetCoreThreadId()})),
test_wakeup_delta_(
{{blink::mojom::BackgroundSyncType::ONE_SHOT, base::TimeDelta::Max()},
{blink::mojom::BackgroundSyncType::PERIODIC,
base::TimeDelta::Max()}}) {}
BackgroundSyncContextImpl::~BackgroundSyncContextImpl() {
// The destructor must run on the core thread because it implicitly accesses
// background_sync_manager_ and services_, when it runs their destructors.
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(!background_sync_manager_);
DCHECK(one_shot_sync_services_.empty());
DCHECK(periodic_sync_services_.empty());
}
// static
#if defined(OS_ANDROID)
void BackgroundSyncContext::FireBackgroundSyncEventsAcrossPartitions(
BrowserContext* browser_context,
blink::mojom::BackgroundSyncType sync_type,
const base::android::JavaParamRef<jobject>& j_runnable) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(browser_context);
BackgroundSyncLauncher::FireBackgroundSyncEvents(browser_context, sync_type,
j_runnable);
}
#endif
// static
void BackgroundSyncContext::GetSoonestWakeupDeltaAcrossPartitions(
blink::mojom::BackgroundSyncType sync_type,
BrowserContext* browser_context,
base::OnceCallback<void(base::TimeDelta)> callback) {
DCHECK(browser_context);
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BackgroundSyncLauncher::GetSoonestWakeupDelta(sync_type, browser_context,
std::move(callback));
}
void BackgroundSyncContextImpl::Init(
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
const scoped_refptr<DevToolsBackgroundServicesContextImpl>&
devtools_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&BackgroundSyncContextImpl::CreateBackgroundSyncManager,
this, service_worker_context, devtools_context));
}
void BackgroundSyncContextImpl::Shutdown() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&BackgroundSyncContextImpl::ShutdownOnCoreThread, this));
}
void BackgroundSyncContextImpl::CreateOneShotSyncService(
mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(
&BackgroundSyncContextImpl::CreateOneShotSyncServiceOnCoreThread,
this, std::move(receiver)));
}
void BackgroundSyncContextImpl::CreatePeriodicSyncService(
mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(
&BackgroundSyncContextImpl::CreatePeriodicSyncServiceOnCoreThread,
this, std::move(receiver)));
}
void BackgroundSyncContextImpl::OneShotSyncServiceHadConnectionError(
OneShotBackgroundSyncServiceImpl* service) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(service);
auto iter = one_shot_sync_services_.find(service);
DCHECK(iter != one_shot_sync_services_.end());
one_shot_sync_services_.erase(iter);
}
void BackgroundSyncContextImpl::PeriodicSyncServiceHadConnectionError(
PeriodicBackgroundSyncServiceImpl* service) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(service);
auto iter = periodic_sync_services_.find(service);
DCHECK(iter != periodic_sync_services_.end());
periodic_sync_services_.erase(iter);
}
BackgroundSyncManager* BackgroundSyncContextImpl::background_sync_manager()
const {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
return background_sync_manager_.get();
}
void BackgroundSyncContextImpl::set_background_sync_manager_for_testing(
std::unique_ptr<BackgroundSyncManager> manager) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
background_sync_manager_ = std::move(manager);
}
void BackgroundSyncContextImpl::set_wakeup_delta_for_testing(
blink::mojom::BackgroundSyncType sync_type,
base::TimeDelta wakeup_delta) {
test_wakeup_delta_[sync_type] = wakeup_delta;
}
void BackgroundSyncContextImpl::GetSoonestWakeupDelta(
blink::mojom::BackgroundSyncType sync_type,
base::Time last_browser_wakeup_for_periodic_sync,
base::OnceCallback<void(base::TimeDelta)> callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// TODO(crbug.com/824858): Remove the else branch after the feature is
// enabled. Also, try to make a RunOrPostTaskOnThreadAndReplyWithResult()
// function so the if/else isn't needed.
if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
base::TimeDelta delta = GetSoonestWakeupDeltaOnCoreThread(
sync_type, last_browser_wakeup_for_periodic_sync);
DidGetSoonestWakeupDelta(std::move(callback), delta);
} else {
base::PostTaskAndReplyWithResult(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(
&BackgroundSyncContextImpl::GetSoonestWakeupDeltaOnCoreThread, this,
sync_type, last_browser_wakeup_for_periodic_sync),
base::BindOnce(&BackgroundSyncContextImpl::DidGetSoonestWakeupDelta,
this, std::move(callback)));
}
}
void BackgroundSyncContextImpl::RevivePeriodicBackgroundSyncRegistrations(
url::Origin origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&BackgroundSyncContextImpl::
RevivePeriodicBackgroundSyncRegistrationsOnCoreThread,
this, std::move(origin)));
}
void BackgroundSyncContextImpl::UnregisterPeriodicSyncForOrigin(
url::Origin origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&BackgroundSyncContextImpl::
UnregisterPeriodicSyncForOriginOnCoreThread,
this, std::move(origin)));
}
base::TimeDelta BackgroundSyncContextImpl::GetSoonestWakeupDeltaOnCoreThread(
blink::mojom::BackgroundSyncType sync_type,
base::Time last_browser_wakeup_for_periodic_sync) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
auto test_wakeup_delta = test_wakeup_delta_[sync_type];
if (!test_wakeup_delta.is_max())
return test_wakeup_delta;
if (!background_sync_manager_)
return base::TimeDelta::Max();
return background_sync_manager_->GetSoonestWakeupDelta(
sync_type, last_browser_wakeup_for_periodic_sync);
}
void BackgroundSyncContextImpl::DidGetSoonestWakeupDelta(
base::OnceCallback<void(base::TimeDelta)> callback,
base::TimeDelta soonest_wakeup_delta) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::move(callback).Run(soonest_wakeup_delta);
}
void BackgroundSyncContextImpl::
RevivePeriodicBackgroundSyncRegistrationsOnCoreThread(url::Origin origin) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (!background_sync_manager_)
return;
background_sync_manager_->RevivePeriodicSyncRegistrations(std::move(origin));
}
void BackgroundSyncContextImpl::UnregisterPeriodicSyncForOriginOnCoreThread(
url::Origin origin) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (!background_sync_manager_)
return;
background_sync_manager_->UnregisterPeriodicSyncForOrigin(origin);
}
void BackgroundSyncContextImpl::FireBackgroundSyncEvents(
blink::mojom::BackgroundSyncType sync_type,
base::OnceClosure done_closure) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(
&BackgroundSyncContextImpl::FireBackgroundSyncEventsOnCoreThread,
this, sync_type, std::move(done_closure)));
}
void BackgroundSyncContextImpl::FireBackgroundSyncEventsOnCoreThread(
blink::mojom::BackgroundSyncType sync_type,
base::OnceClosure done_closure) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (!background_sync_manager_) {
DidFireBackgroundSyncEventsOnCoreThread(std::move(done_closure));
return;
}
background_sync_manager_->FireReadyEvents(
sync_type, /* reschedule= */ false,
base::BindOnce(
&BackgroundSyncContextImpl::DidFireBackgroundSyncEventsOnCoreThread,
this, std::move(done_closure)));
}
void BackgroundSyncContextImpl::DidFireBackgroundSyncEventsOnCoreThread(
base::OnceClosure done_closure) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
// Use PostTask() rather than RunOrPostTaskOnThread() to ensure the callback
// is called asynchronously.
GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(done_closure));
}
void BackgroundSyncContextImpl::CreateBackgroundSyncManager(
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(!background_sync_manager_);
background_sync_manager_ = BackgroundSyncManager::Create(
std::move(service_worker_context), std::move(devtools_context));
}
void BackgroundSyncContextImpl::CreateOneShotSyncServiceOnCoreThread(
mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
receiver) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(background_sync_manager_);
one_shot_sync_services_.insert(
std::make_unique<OneShotBackgroundSyncServiceImpl>(this,
std::move(receiver)));
}
void BackgroundSyncContextImpl::CreatePeriodicSyncServiceOnCoreThread(
mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
receiver) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(background_sync_manager_);
periodic_sync_services_.insert(
std::make_unique<PeriodicBackgroundSyncServiceImpl>(this,
std::move(receiver)));
}
void BackgroundSyncContextImpl::ShutdownOnCoreThread() {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
one_shot_sync_services_.clear();
periodic_sync_services_.clear();
background_sync_manager_.reset();
}
} // namespace content