diff --git a/toolkit/components/extensions/ExtensionPageChild.jsm b/toolkit/components/extensions/ExtensionPageChild.jsm index 2b5862ec12d0..26f9fb504d04 100644 --- a/toolkit/components/extensions/ExtensionPageChild.jsm +++ b/toolkit/components/extensions/ExtensionPageChild.jsm @@ -166,6 +166,11 @@ function getContextChildManagerGetter( viewType: this.viewType, url: this.uri.spec, incognito: this.incognito, + // Additional data a BaseContext subclass may optionally send + // as part of the CreateProxyContext request sent to the main process + // (e.g. WorkerContexChild implements this method to send the service + // worker descriptor id along with the details send by default here). + ...this.getCreateProxyContextData?.(), } ); diff --git a/toolkit/components/extensions/ExtensionParent.jsm b/toolkit/components/extensions/ExtensionParent.jsm index b39e9b3fa6d0..e1654528acf2 100644 --- a/toolkit/components/extensions/ExtensionParent.jsm +++ b/toolkit/components/extensions/ExtensionParent.jsm @@ -736,6 +736,26 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent { } } +/** + * The parent side of proxied API context for extension background service + * worker script. + */ +class BackgroundWorkerContextParent extends ProxyContextParent { + constructor(envType, extension, params) { + // TODO: split out from ProxyContextParent a base class that + // doesn't expect a xulBrowser and one for contexts that are + // expected to have a xulBrowser associated. + super(envType, extension, params, null, extension.principal); + + this.viewType = params.viewType; + this.workerDescriptorId = params.workerDescriptorId; + + this.extension.views.add(this); + + extension.emit("extension-proxy-context-load", this); + } +} + ParentAPIManager = { proxyContexts: new Map(), @@ -844,7 +864,9 @@ ParentAPIManager = { } } - if (envType == "addon_parent") { + if (envType == "addon_parent" && data.viewType === "background_worker") { + context = new BackgroundWorkerContextParent(envType, extension, data); + } else if (envType == "addon_parent") { context = new ExtensionPageContextParent( envType, extension, diff --git a/toolkit/components/extensions/ExtensionWorkerChild.jsm b/toolkit/components/extensions/ExtensionWorkerChild.jsm index b3671edfe249..7c896997c52d 100644 --- a/toolkit/components/extensions/ExtensionWorkerChild.jsm +++ b/toolkit/components/extensions/ExtensionWorkerChild.jsm @@ -619,6 +619,11 @@ class WorkerContextChild extends BaseContext { }; } + getCreateProxyContextData() { + const { workerDescriptorId } = this; + return { workerDescriptorId }; + } + openConduit(subject, address) { let proc = ChromeUtils.domProcessChild; let conduit = proc.getActor("ProcessConduits").openConduit(subject, { @@ -626,6 +631,7 @@ class WorkerContextChild extends BaseContext { extensionId: this.extension.id, envType: this.envType, workerScriptURL: this.uri.spec, + workerDescriptorId: this.workerDescriptorId, ...address, }); this.callOnClose(conduit); @@ -639,6 +645,7 @@ class WorkerContextChild extends BaseContext { this.childManager.conduit.sendContextLoaded({ childId: this.childManager.id, extensionId: this.extension.id, + workerDescriptorId: this.workerDescriptorId, }); } diff --git a/toolkit/components/extensions/parent/ext-backgroundPage.js b/toolkit/components/extensions/parent/ext-backgroundPage.js index ff4ba2d6fc30..cf8f4dc876be 100644 --- a/toolkit/components/extensions/parent/ext-backgroundPage.js +++ b/toolkit/components/extensions/parent/ext-backgroundPage.js @@ -115,7 +115,6 @@ class BackgroundPage extends HiddenExtensionPage { // Responsible for the background.service_worker section of the manifest. class BackgroundWorker { constructor(extension, options) { - this.registrationInfo = null; this.extension = extension; this.workerScript = options.service_worker; @@ -124,6 +123,24 @@ class BackgroundWorker { } } + get registrationInfo() { + const { principal } = this.extension; + return serviceWorkerManager.getRegistrationForAddonPrincipal(principal); + } + + getWorkerInfo(descriptorId) { + return this.registrationInfo?.getWorkerByID(descriptorId); + } + + validateWorkerInfoForContext(context) { + const { extension } = this; + if (!this.getWorkerInfo(context.workerDescriptorId)) { + throw new Error( + `ServiceWorkerInfo not found for ${extension.policy.debugName} contextId ${context.contextId}` + ); + } + } + async build() { const { extension } = this; @@ -134,6 +151,7 @@ class BackgroundWorker { { extension, viewType: "background_worker" }, context => { unwatch(); + this.validateWorkerInfoForContext(context); resolve(context); } ); @@ -141,12 +159,9 @@ class BackgroundWorker { // TODO(Bug 17228327): follow up to spawn the active worker for a previously installed // background service worker. - const regInfo = await serviceWorkerManager.registerForAddonPrincipal( + await serviceWorkerManager.registerForAddonPrincipal( this.extension.principal ); - this.registrationInfo = regInfo.QueryInterface( - Ci.nsIServiceWorkerRegistrationInfo - ); context = await contextPromise; @@ -192,8 +207,6 @@ class BackgroundWorker { if (!isAppShutdown) { this.registrationInfo?.forceShutdown(); } - - this.registrationInfo = null; } waitForActiveWorker() {