Commit 88179435 authored by Mugdha Lakhani's avatar Mugdha Lakhani Committed by Commit Bot

[Background Sync] Add 'Periodic Sync' to Devtools

This lives under the Service Worker section of the Application tab in
Devtools and allows dispatching a periodicsync event with a given tag
so that developers can test how they respond to it.

Screenshots here:
https://bugs.chromium.org/p/chromium/issues/detail?id=961238#c4

Bug: 961238
Change-Id: I2f5fe2c41ad9d2c50db99c44d873d8cc61964913
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1725893Reviewed-by: default avatarJoel Einbinder <einbinder@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarRayan Kanso <rayankans@chromium.org>
Commit-Queue: Mugdha Lakhani <nator@chromium.org>
Auto-Submit: Mugdha Lakhani <nator@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685540}
parent 8d670518
......@@ -560,6 +560,21 @@ void BackgroundSyncManager::EmulateDispatchSyncEvent(
std::move(callback));
}
void BackgroundSyncManager::EmulateDispatchPeriodicSyncEvent(
const std::string& tag,
scoped_refptr<ServiceWorkerVersion> active_version,
ServiceWorkerVersion::StatusCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
blink::ServiceWorkerStatusCode code = CanEmulateSyncEvent(active_version);
if (code != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(code);
return;
}
DispatchPeriodicSyncEvent(tag, std::move(active_version),
std::move(callback));
}
void BackgroundSyncManager::EmulateServiceWorkerOffline(
int64_t service_worker_id,
bool is_offline) {
......
......@@ -133,6 +133,10 @@ class CONTENT_EXPORT BackgroundSyncManager
scoped_refptr<ServiceWorkerVersion> active_version,
bool last_chance,
ServiceWorkerVersion::StatusCallback callback);
void EmulateDispatchPeriodicSyncEvent(
const std::string& tag,
scoped_refptr<ServiceWorkerVersion> active_version,
ServiceWorkerVersion::StatusCallback callback);
// Called from DevTools to toggle service worker "offline" status
void EmulateServiceWorkerOffline(int64_t service_worker_id, bool is_offline);
......
......@@ -127,11 +127,26 @@ void DidFindRegistrationForDispatchSyncEventOnIO(
registration->active_version());
// Keep the registration while dispatching the sync event.
background_sync_manager->EmulateDispatchSyncEvent(
tag, std::move(version), last_chance,
base::BindOnce(base::DoNothing::Once<
scoped_refptr<content::ServiceWorkerRegistration>,
blink::ServiceWorkerStatusCode>(),
std::move(registration)));
tag, std::move(version), last_chance, base::DoNothing());
}
void DidFindRegistrationForDispatchPeriodicSyncEventOnIO(
scoped_refptr<BackgroundSyncContextImpl> sync_context,
const std::string& tag,
blink::ServiceWorkerStatusCode status,
scoped_refptr<content::ServiceWorkerRegistration> registration) {
if (status != blink::ServiceWorkerStatusCode::kOk ||
!registration->active_version()) {
return;
}
BackgroundSyncManager* background_sync_manager =
sync_context->background_sync_manager();
scoped_refptr<content::ServiceWorkerVersion> version(
registration->active_version());
// Keep the registration while dispatching the sync event.
background_sync_manager->EmulateDispatchPeriodicSyncEvent(
tag, std::move(version), base::DoNothing());
}
void DispatchSyncEventOnIO(
......@@ -147,6 +162,18 @@ void DispatchSyncEventOnIO(
tag, last_chance));
}
void DispatchPeriodicSyncEventOnIO(
scoped_refptr<ServiceWorkerContextWrapper> context,
scoped_refptr<BackgroundSyncContextImpl> sync_context,
const GURL& origin,
int64_t registration_id,
const std::string& tag) {
context->FindReadyRegistrationForId(
registration_id, origin,
base::BindOnce(&DidFindRegistrationForDispatchPeriodicSyncEventOnIO,
sync_context, tag));
}
} // namespace
ServiceWorkerHandler::ServiceWorkerHandler()
......@@ -346,6 +373,29 @@ Response ServiceWorkerHandler::DispatchSyncEvent(
return Response::OK();
}
Response ServiceWorkerHandler::DispatchPeriodicSyncEvent(
const std::string& origin,
const std::string& registration_id,
const std::string& tag) {
if (!enabled_)
return CreateDomainNotEnabledErrorResponse();
if (!storage_partition_)
return CreateContextErrorResponse();
int64_t id = 0;
if (!base::StringToInt64(registration_id, &id))
return CreateInvalidVersionIdErrorResponse();
BackgroundSyncContextImpl* sync_context =
storage_partition_->GetBackgroundSyncContext();
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&DispatchPeriodicSyncEventOnIO, context_,
base::WrapRefCounted(sync_context), GURL(origin), id,
tag));
return Response::OK();
}
void ServiceWorkerHandler::OpenNewDevToolsWindow(int process_id,
int devtools_agent_route_id) {
scoped_refptr<DevToolsAgentHostImpl> agent_host(
......
......@@ -56,7 +56,9 @@ class ServiceWorkerHandler : public DevToolsDomainHandler,
const std::string& registration_id,
const std::string& tag,
bool last_chance) override;
// TODO(crbug.com/961238): Add DispatchPeriodicSyncEvent().
Response DispatchPeriodicSyncEvent(const std::string& origin,
const std::string& registration_id,
const std::string& tag) override;
private:
void OnWorkerRegistrationUpdated(
......
......@@ -6198,6 +6198,12 @@ experimental domain ServiceWorker
string tag
boolean lastChance
command dispatchPeriodicSyncEvent
parameters
string origin
RegistrationID registrationId
string tag
command enable
command inspectWorker
......
......@@ -319,6 +319,8 @@ Resources.ServiceWorkersView.Section = class {
this._pushNotificationDataSetting =
Common.settings.createLocalSetting('pushData', Common.UIString('Test push message from DevTools.'));
this._syncTagNameSetting = Common.settings.createLocalSetting('syncTagName', 'test-tag-from-devtools');
this._periodicSyncTagNameSetting =
Common.settings.createLocalSetting('periodicSyncTagName', 'test-tag-from-devtools');
this._toolbar = section.createToolbar();
this._toolbar.renderAsLinks();
......@@ -339,6 +341,11 @@ Resources.ServiceWorkersView.Section = class {
this._push.bind(this));
this._createSyncNotificationField(
Common.UIString('Sync'), this._syncTagNameSetting.get(), Common.UIString('Sync tag'), this._sync.bind(this));
if (Runtime.experiments.isEnabled('backgroundServicesPeriodicBackgroundSync')) {
this._createSyncNotificationField(
ls`Periodic Sync`, this._periodicSyncTagNameSetting.get(), ls`Periodic Sync tag`,
tag => this._periodicSync(tag));
}
this._linkifier = new Components.Linkifier();
/** @type {!Map<string, !Protocol.Target.TargetInfo>} */
......@@ -559,6 +566,14 @@ Resources.ServiceWorkersView.Section = class {
this._manager.dispatchSyncEvent(this._registration.id, tag, true);
}
/**
* @param {string} tag
*/
_periodicSync(tag) {
this._periodicSyncTagNameSetting.set(tag);
this._manager.dispatchPeriodicSyncEvent(this._registration.id, tag);
}
/**
* @param {!Element} element
* @param {?Protocol.Target.TargetInfo} targetInfo
......
......@@ -12,12 +12,18 @@
<message name="IDS_DEVTOOLS_09428a9282bbb3ffcf3caa7826f0bf83" desc="Message in Database Model of the Application panel">
An unexpected error <ph name="SQLERROR_CODE">$1s<ex>-197</ex></ph> occurred.
</message>
<message name="IDS_DEVTOOLS_0ace6faf288026c1adc56a2a1e7bb6be" desc="Default tag for a periodicsync event in Service Workers View of the Application panel">
Periodic Sync tag
</message>
<message name="IDS_DEVTOOLS_0d6fa553290eb4bf9eabe203a43b01d9" desc="Text in Clear Storage View of the Application panel">
Application cache
</message>
<message name="IDS_DEVTOOLS_0f558243fbf45f1cd840fff01957f57b" desc="Text in Service Workers View of the Application panel">
Clients
</message>
<message name="IDS_DEVTOOLS_10a77618ffc0466753fde85f9bec01fd" desc="Text for button in Service Workers View of the Application panel that dispatches a periodicsync event">
Periodic Sync
</message>
<message name="IDS_DEVTOOLS_1351a3eaa0f925dad980e83905bc1230" desc="Text of a DOM element in Service Workers View of the Application panel">
Worker: <ph name="TARGETINFO_URL">$1s<ex>example.com</ex></ph>
</message>
......
......@@ -150,6 +150,18 @@ SDK.ServiceWorkerManager = class extends SDK.SDKModel {
this._agent.dispatchSyncEvent(origin, registrationId, tag, lastChance);
}
/**
* @param {string} registrationId
* @param {string} tag
*/
dispatchPeriodicSyncEvent(registrationId, tag) {
const registration = this._registrations.get(registrationId);
if (!registration)
return;
const origin = Common.ParsedURL.extractOrigin(registration.scopeURL);
this._agent.dispatchPeriodicSyncEvent(origin, registrationId, tag);
}
/**
* @param {string} scope
*/
......
Tests delivery of a periodicsync event to the service worker.
Got periodicsync event with tag: test-tag-from-devtools
(async testRunner => {
const { page, session, dp } = await testRunner.startURL(
'resources/periodicsync-event-worker.html',
`Tests delivery of a periodicsync event to the service worker.`);
async function waitForServiceWorkerActivation() {
let versions;
do {
const result = await dp.ServiceWorker.onceWorkerVersionUpdated();
versions = result.params.versions;
} while (!versions.length || versions[0].status !== "activated");
return versions[0].registrationId;
}
const registrationIdPromise = waitForServiceWorkerActivation();
await dp.Runtime.enable();
await dp.ServiceWorker.enable();
const registrationId = await registrationIdPromise;
dp.ServiceWorker.dispatchPeriodicSyncEvent({ origin: 'http://127.0.0.1:8000', registrationId: registrationId, tag: 'devtools-test-tag' });
const tag = await session.evaluateAsync('window.__periodicsyncTagPromise');
testRunner.log(`Got periodicsync event with tag: ` + tag);
testRunner.completeTest();
});
<!DOCTYPE html>
<html>
<head>
<title>Test periodicsync event in a serviceworker.</title>
<script>
function installSW() {
navigator.serviceWorker.register('periodicsync-event-worker.js');
}
window.__periodicsyncTagPromise = new Promise(fulfill =>
navigator.serviceWorker.onmessage = message => fulfill(message.data));
</script>
</head>
<body onload="installSW()"></body>
</html>
self.addEventListener('periodicsync', async event => {
const clients = await self.clients.matchAll({ includeUncontrolled: true });
for (const client of clients)
client.postMessage('test-tag-from-devtools');
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment