Bug 1231213 - Implement cross-process ServiceWorkerGlobalScope.skipWaiting(). r=asuth
☠☠ backed out by 3cf55b7f12f2 ☠ ☠
authorPerry Jiang <perry@mozilla.com>
Wed, 14 Aug 2019 16:20:31 +0000
changeset 488076 216591953f9750051e8915543aa246d4ec1600bb
parent 488075 1de357bc192118732798e8dd56e44e137add019b
child 488077 6a40ab6852cb51e9903751b04d797c5d53549fa5
push id113900
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:53:50 +0000
treeherdermozilla-inbound@0db07ff50ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1231213
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1231213 - Implement cross-process ServiceWorkerGlobalScope.skipWaiting(). r=asuth Differential Revision: https://phabricator.services.mozilla.com/D26175
dom/abort/moz.build
dom/console/moz.build
dom/performance/moz.build
dom/serviceworkers/ServiceWorkerPrivateImpl.cpp
dom/serviceworkers/ServiceWorkerPrivateImpl.h
dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
dom/serviceworkers/ServiceWorkerRegistrationInfo.h
dom/workers/WorkerError.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.cpp
dom/workers/moz.build
dom/workers/remoteworkers/PRemoteWorker.ipdl
dom/workers/remoteworkers/PRemoteWorkerController.ipdl
dom/workers/remoteworkers/RemoteWorkerChild.cpp
dom/workers/remoteworkers/RemoteWorkerChild.h
dom/workers/remoteworkers/RemoteWorkerController.cpp
dom/workers/remoteworkers/RemoteWorkerController.h
dom/workers/remoteworkers/RemoteWorkerControllerChild.cpp
dom/workers/remoteworkers/RemoteWorkerControllerChild.h
dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp
dom/workers/remoteworkers/RemoteWorkerControllerParent.h
dom/workers/remoteworkers/RemoteWorkerParent.cpp
dom/workers/remoteworkers/RemoteWorkerParent.h
dom/workers/remoteworkers/moz.build
--- a/dom/abort/moz.build
+++ b/dom/abort/moz.build
@@ -14,9 +14,11 @@ EXPORTS.mozilla.dom += [
     'AbortSignal.h',
 ]
 
 UNIFIED_SOURCES += [
     'AbortController.cpp',
     'AbortSignal.cpp',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
--- a/dom/console/moz.build
+++ b/dom/console/moz.build
@@ -47,9 +47,11 @@ LOCAL_INCLUDES += [
     '/dom/base',
     '/js/xpconnect/src',
 ]
 
 MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
 MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
--- a/dom/performance/moz.build
+++ b/dom/performance/moz.build
@@ -37,11 +37,13 @@ UNIFIED_SOURCES += [
     'PerformanceResourceTiming.cpp',
     'PerformanceServerTiming.cpp',
     'PerformanceService.cpp',
     'PerformanceStorageWorker.cpp',
     'PerformanceTiming.cpp',
     'PerformanceWorker.cpp',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
 
 FINAL_LIBRARY = 'xul'
--- a/dom/serviceworkers/ServiceWorkerPrivateImpl.cpp
+++ b/dom/serviceworkers/ServiceWorkerPrivateImpl.cpp
@@ -383,16 +383,44 @@ nsresult ServiceWorkerPrivateImpl::Initi
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
+RefPtr<GenericPromise> ServiceWorkerPrivateImpl::SetSkipWaitingFlag() {
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mOuter);
+  MOZ_ASSERT(mOuter->mInfo);
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+  if (!swm) {
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
+  RefPtr<ServiceWorkerRegistrationInfo> regInfo =
+      swm->GetRegistration(mOuter->mInfo->Principal(), mOuter->mInfo->Scope());
+
+  if (!regInfo) {
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
+  mOuter->mInfo->SetSkipWaitingFlag();
+
+  RefPtr<GenericPromise::Private> promise =
+      new GenericPromise::Private(__func__);
+
+  regInfo->TryToActivateAsync([promise] { promise->Resolve(true, __func__); });
+
+  return promise;
+}
+
 nsresult ServiceWorkerPrivateImpl::RefreshRemoteWorkerData(
     const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration) {
   AssertIsOnMainThread();
   MOZ_ASSERT(mOuter);
   MOZ_ASSERT(mOuter->mInfo);
 
   nsTArray<KeyAndPermissions> permissions;
   nsCOMPtr<nsIPermissionManager> permManager = services::GetPermissionManager();
--- a/dom/serviceworkers/ServiceWorkerPrivateImpl.h
+++ b/dom/serviceworkers/ServiceWorkerPrivateImpl.h
@@ -47,16 +47,18 @@ class ServiceWorkerPrivateImpl final : p
                                        public RemoteWorkerObserver {
  public:
   NS_INLINE_DECL_REFCOUNTING(ServiceWorkerPrivateImpl, override);
 
   explicit ServiceWorkerPrivateImpl(RefPtr<ServiceWorkerPrivate> aOuter);
 
   nsresult Initialize();
 
+  RefPtr<GenericPromise> SetSkipWaitingFlag();
+
  private:
   class RAIIActorPtrHolder;
 
   ~ServiceWorkerPrivateImpl();
 
   /**
    * ServiceWorkerPrivate::Inner
    */
--- a/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
@@ -289,33 +289,41 @@ ServiceWorkerRegistrationInfo::GetServic
     serviceWorker = mWaitingWorker;
   } else if (mActiveWorker && mActiveWorker->ID() == aId) {
     serviceWorker = mActiveWorker;
   }
 
   return serviceWorker.forget();
 }
 
-void ServiceWorkerRegistrationInfo::TryToActivateAsync() {
+void ServiceWorkerRegistrationInfo::TryToActivateAsync(
+    TryToActivateCallback&& aCallback) {
   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
-      NewRunnableMethod("ServiceWorkerRegistrationInfo::TryToActivate", this,
-                        &ServiceWorkerRegistrationInfo::TryToActivate)));
+      NewRunnableMethod<StoreCopyPassByRRef<TryToActivateCallback>>(
+          "ServiceWorkerRegistrationInfo::TryToActivate", this,
+          &ServiceWorkerRegistrationInfo::TryToActivate,
+          std::move(aCallback))));
 }
 
 /*
  * TryToActivate should not be called directly, use TryToActivateAsync instead.
  */
-void ServiceWorkerRegistrationInfo::TryToActivate() {
+void ServiceWorkerRegistrationInfo::TryToActivate(
+    TryToActivateCallback&& aCallback) {
   MOZ_ASSERT(NS_IsMainThread());
   bool controlling = IsControllingClients();
   bool skipWaiting = mWaitingWorker && mWaitingWorker->SkipWaitingFlag();
   bool idle = IsIdle();
   if (idle && (!controlling || skipWaiting)) {
     Activate();
   }
+
+  if (aCallback) {
+    aCallback();
+  }
 }
 
 void ServiceWorkerRegistrationInfo::Activate() {
   if (!mWaitingWorker) {
     return;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
--- a/dom/serviceworkers/ServiceWorkerRegistrationInfo.h
+++ b/dom/serviceworkers/ServiceWorkerRegistrationInfo.h
@@ -2,16 +2,18 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_serviceworkerregistrationinfo_h
 #define mozilla_dom_serviceworkerregistrationinfo_h
 
+#include <functional>
+
 #include "mozilla/dom/ServiceWorkerInfo.h"
 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
 #include "nsProxyRelease.h"
 #include "nsTObserverArray.h"
 
 namespace mozilla {
 namespace dom {
@@ -63,16 +65,18 @@ class ServiceWorkerRegistrationInfo fina
   bool mUnregistered;
 
   bool mCorrupt;
 
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERREGISTRATIONINFO
 
+  typedef std::function<void()> TryToActivateCallback;
+
   ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                 nsIPrincipal* aPrincipal,
                                 ServiceWorkerUpdateViaCache aUpdateViaCache);
 
   void AddInstance(ServiceWorkerRegistrationListener* aInstance,
                    const ServiceWorkerRegistrationDescriptor& aDescriptor);
 
   void RemoveInstance(ServiceWorkerRegistrationListener* aInstance);
@@ -115,19 +119,19 @@ class ServiceWorkerRegistrationInfo fina
   }
 
   void Clear();
 
   void ClearAsCorrupt();
 
   bool IsCorrupt() const;
 
-  void TryToActivateAsync();
+  void TryToActivateAsync(TryToActivateCallback&& aCallback = nullptr);
 
-  void TryToActivate();
+  void TryToActivate(TryToActivateCallback&& aCallback);
 
   void Activate();
 
   void FinishActivate(bool aSuccess);
 
   void RefreshLastUpdateCheckTime();
 
   bool IsLastUpdateCheckTimeOverOneDay() const;
--- a/dom/workers/WorkerError.cpp
+++ b/dom/workers/WorkerError.cpp
@@ -6,16 +6,17 @@
 
 #include "WorkerError.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
+#include "mozilla/dom/ServiceWorkerUtils.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsGlobalWindowInner.h"
 #include "nsIConsoleService.h"
 #include "nsScriptError.h"
 #include "WorkerRunnable.h"
@@ -75,25 +76,38 @@ class ReportErrorRunnable final : public
                                            /* isErrorEvent */ true);
         return true;
       }
 
       // Service workers do not have a main thread parent global, so normal
       // worker error reporting will crash.  Instead, pass the error to
       // the ServiceWorkerManager to report on any controlled documents.
       if (aWorkerPrivate->IsServiceWorker()) {
-        RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-        if (swm) {
-          swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
-                           aWorkerPrivate->ServiceWorkerScope(),
-                           aWorkerPrivate->ScriptURL(), mReport->mMessage,
-                           mReport->mFilename, mReport->mLine,
-                           mReport->mLineNumber, mReport->mColumnNumber,
-                           mReport->mFlags, mReport->mExnType);
+        if (ServiceWorkerParentInterceptEnabled()) {
+          RefPtr<RemoteWorkerChild> actor(
+              aWorkerPrivate->GetRemoteWorkerControllerWeakRef());
+
+          Unused << NS_WARN_IF(!actor);
+
+          if (actor) {
+            actor->ErrorPropagationOnMainThread(nullptr, false);
+          }
+
+        } else {
+          RefPtr<ServiceWorkerManager> swm =
+              ServiceWorkerManager::GetInstance();
+          if (swm) {
+            swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
+                             aWorkerPrivate->ServiceWorkerScope(),
+                             aWorkerPrivate->ScriptURL(), EmptyString(),
+                             EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
+                             JSEXN_ERR);
+          }
         }
+
         return true;
       }
 
       // The innerWindowId is only required if we are going to ReportError
       // below, which is gated on this condition. The inner window correctness
       // check is only going to succeed when the worker is accepting events.
       if (workerIsAcceptingEvents) {
         aWorkerPrivate->AssertInnerWindowIsCorrect();
@@ -154,24 +168,37 @@ class ReportGenericErrorRunnable final :
 
     if (aWorkerPrivate->IsSharedWorker()) {
       aWorkerPrivate->GetRemoteWorkerController()->ErrorPropagationOnMainThread(
           nullptr, false);
       return true;
     }
 
     if (aWorkerPrivate->IsServiceWorker()) {
-      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-      if (swm) {
-        swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
-                         aWorkerPrivate->ServiceWorkerScope(),
-                         aWorkerPrivate->ScriptURL(), EmptyString(),
-                         EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
-                         JSEXN_ERR);
+      if (ServiceWorkerParentInterceptEnabled()) {
+        RefPtr<RemoteWorkerChild> actor(
+            aWorkerPrivate->GetRemoteWorkerControllerWeakRef());
+
+        Unused << NS_WARN_IF(!actor);
+
+        if (actor) {
+          actor->ErrorPropagationOnMainThread(nullptr, false);
+        }
+
+      } else {
+        RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+        if (swm) {
+          swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
+                           aWorkerPrivate->ServiceWorkerScope(),
+                           aWorkerPrivate->ScriptURL(), EmptyString(),
+                           EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
+                           JSEXN_ERR);
+        }
       }
+
       return true;
     }
 
     if (!aWorkerPrivate->IsAcceptingEvents()) {
       return true;
     }
 
     RefPtr<mozilla::dom::EventTarget> parentEventTarget =
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -31,16 +31,17 @@
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/PerformanceStorageWorker.h"
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/RemoteWorkerChild.h"
+#include "mozilla/dom/RemoteWorkerService.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/StorageAccess.h"
 #include "mozilla/ThreadEventQueue.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/WorkerTimelineMarker.h"
 #include "nsCycleCollector.h"
@@ -48,16 +49,17 @@
 #include "nsNetUtil.h"
 #include "nsIMemoryReporter.h"
 #include "nsIPermissionManager.h"
 #include "nsIRandomGenerator.h"
 #include "nsIScriptError.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsPrintfCString.h"
+#include "nsProxyRelease.h"
 #include "nsQueryObject.h"
 #include "nsRFPService.h"
 #include "nsSandboxFlags.h"
 #include "nsUTF8Utils.h"
 
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "mozilla/dom/ServiceWorkerEvents.h"
@@ -4842,16 +4844,50 @@ void WorkerPrivate::SetRemoteWorkerContr
 }
 
 RemoteWorkerChild* WorkerPrivate::GetRemoteWorkerController() {
   AssertIsOnMainThread();
   MOZ_ASSERT(mRemoteWorkerController);
   return mRemoteWorkerController;
 }
 
+void WorkerPrivate::SetRemoteWorkerControllerWeakRef(
+    ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef) {
+  MOZ_ASSERT(aWeakRef);
+  MOZ_ASSERT(!mRemoteWorkerControllerWeakRef);
+  MOZ_ASSERT(IsServiceWorker());
+
+  mRemoteWorkerControllerWeakRef = std::move(aWeakRef);
+}
+
+ThreadSafeWeakPtr<RemoteWorkerChild>
+WorkerPrivate::GetRemoteWorkerControllerWeakRef() {
+  MOZ_ASSERT(IsServiceWorker());
+  return mRemoteWorkerControllerWeakRef;
+}
+
+RefPtr<GenericPromise> WorkerPrivate::SetServiceWorkerSkipWaitingFlag() {
+  AssertIsOnWorkerThread();
+  MOZ_ASSERT(IsServiceWorker());
+
+  RefPtr<RemoteWorkerChild> rwc(mRemoteWorkerControllerWeakRef);
+
+  if (!rwc) {
+    return GenericPromise::CreateAndReject(NS_ERROR_DOM_ABORT_ERR, __func__);
+  }
+
+  RefPtr<GenericPromise> promise =
+      rwc->MaybeSendSetServiceWorkerSkipWaitingFlag();
+
+  NS_ProxyRelease("WorkerPrivate::mRemoteWorkerControllerWeakRef",
+                  RemoteWorkerService::Thread(), rwc.forget());
+
+  return promise;
+}
+
 nsAString& WorkerPrivate::Id() {
   AssertIsOnMainThread();
 
   if (mID.IsEmpty()) {
     nsresult rv;
     nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
         do_GetService("@mozilla.org/uuid-generator;1", &rv);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -7,24 +7,27 @@
 #ifndef mozilla_dom_workers_workerprivate_h__
 #define mozilla_dom_workers_workerprivate_h__
 
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/dom/WorkerStatus.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/MozPromise.h"
 #include "mozilla/RelativeTimeline.h"
 #include "mozilla/StorageAccess.h"
+#include "mozilla/ThreadSafeWeakPtr.h"
 #include "nsContentUtils.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIEventTarget.h"
 #include "nsTObserverArray.h"
 
 #include "js/ContextOptions.h"
+#include "mozilla/dom/RemoteWorkerChild.h"
 #include "mozilla/dom/Worker.h"
 #include "mozilla/dom/WorkerLoadInfo.h"
 #include "mozilla/dom/workerinternals/JSSettings.h"
 #include "mozilla/dom/workerinternals/Queue.h"
 #include "mozilla/PerformanceCounter.h"
 #include "mozilla/ThreadBound.h"
 
 class nsIThreadInternal;
@@ -38,17 +41,16 @@ namespace dom {
 enum WorkerType { WorkerTypeDedicated, WorkerTypeShared, WorkerTypeService };
 
 class ClientInfo;
 class ClientSource;
 class Function;
 class MessagePort;
 class MessagePortIdentifier;
 class PerformanceStorage;
-class RemoteWorkerChild;
 class TimeoutHandler;
 class WorkerControlRunnable;
 class WorkerCSPEventListener;
 class WorkerDebugger;
 class WorkerDebuggerGlobalScope;
 class WorkerErrorReport;
 class WorkerEventTarget;
 class WorkerGlobalScope;
@@ -784,16 +786,23 @@ class WorkerPrivate : public RelativeTim
     // any thread
     mLoadingWorkerScript = aLoadingWorkerScript;
   }
 
   RemoteWorkerChild* GetRemoteWorkerController();
 
   void SetRemoteWorkerController(RemoteWorkerChild* aController);
 
+  void SetRemoteWorkerControllerWeakRef(
+      ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef);
+
+  ThreadSafeWeakPtr<RemoteWorkerChild> GetRemoteWorkerControllerWeakRef();
+
+  RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag();
+
   // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
   // as these are only used for globals going in and out of the bfcache.
   bool Freeze(nsPIDOMWindowInner* aWindow);
 
   bool Thaw(nsPIDOMWindowInner* aWindow);
 
   void PropagateFirstPartyStorageAccessGranted();
 
@@ -1060,16 +1069,19 @@ class WorkerPrivate : public RelativeTim
   RefPtr<WorkerCSPEventListener> mCSPEventListener;
 
   // Protected by mMutex.
   nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
 
   // Only touched on the parent thread. This is set only if IsSharedWorker().
   RefPtr<RemoteWorkerChild> mRemoteWorkerController;
 
+  // This is set only if IsServiceWorker().
+  ThreadSafeWeakPtr<RemoteWorkerChild> mRemoteWorkerControllerWeakRef;
+
   JS::UniqueChars mDefaultLocale;  // nulled during worker JSContext init
   TimeStamp mKillTime;
   WorkerStatus mParentStatus;
   WorkerStatus mStatus;
 
   // This is touched on parent thread only, but it can be read on a different
   // thread before crashing because hanging.
   Atomic<uint64_t> mBusyCount;
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/IDBFactory.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
+#include "mozilla/dom/ServiceWorkerUtils.h"
 #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerLocation.h"
 #include "mozilla/dom/WorkerNavigator.h"
 #include "mozilla/dom/cache/CacheStorage.h"
@@ -853,16 +854,31 @@ already_AddRefed<Promise> ServiceWorkerG
   mWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
 
   RefPtr<Promise> promise = Promise::Create(this, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
+  if (ServiceWorkerParentInterceptEnabled()) {
+    mWorkerPrivate->SetServiceWorkerSkipWaitingFlag()->Then(
+        GetCurrentThreadSerialEventTarget(), __func__,
+        [promise](bool aOk) {
+          Unused << NS_WARN_IF(!aOk);
+          promise->MaybeResolveWithUndefined();
+        },
+        [promise](nsresult aRv) {
+          MOZ_ASSERT(NS_FAILED(aRv));
+          promise->MaybeResolveWithUndefined();
+        });
+
+    return promise.forget();
+  }
+
   RefPtr<PromiseWorkerProxy> promiseProxy =
       PromiseWorkerProxy::Create(mWorkerPrivate, promise);
   if (!promiseProxy) {
     promise->MaybeResolveWithUndefined();
     return promise.forget();
   }
 
   RefPtr<WorkerScopeSkipWaitingRunnable> runnable =
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -66,16 +66,17 @@ UNIFIED_SOURCES += [
     'WorkerThread.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/caps',
     '/dom/base',
     '/dom/bindings',
     '/dom/system',
+    '/dom/workers/remoteworkers',
     '/js/xpconnect/loader',
     '/netwerk/base',
     '/xpcom/build',
     '/xpcom/threads',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     LOCAL_INCLUDES += [
--- a/dom/workers/remoteworkers/PRemoteWorker.ipdl
+++ b/dom/workers/remoteworkers/PRemoteWorker.ipdl
@@ -64,16 +64,18 @@ protocol PRemoteWorker
 
 parent:
   async Created(bool aStatus);
 
   async Error(ErrorValue aValue);
 
   async Close();
 
+  async SetServiceWorkerSkipWaitingFlag() returns (bool aOk);
+
 child:
   async PFetchEventOpProxy(ServiceWorkerFetchEventOpArgs aArgs);
 
   async __delete__();
 
   async ExecOp(RemoteWorkerOp op);
 
   async ExecServiceWorkerOp(ServiceWorkerOpArgs aArgs)
--- a/dom/workers/remoteworkers/PRemoteWorkerController.ipdl
+++ b/dom/workers/remoteworkers/PRemoteWorkerController.ipdl
@@ -20,16 +20,18 @@ protocol PRemoteWorkerController {
   async CreationFailed();
 
   async CreationSucceeded();
 
   async ErrorReceived(ErrorValue aError);
 
   async Terminated();
 
+  async SetServiceWorkerSkipWaitingFlag() returns (bool aOk);
+
  parent:
   async PFetchEventOp(ServiceWorkerFetchEventOpArgs aArgs);
 
   async __delete__();
 
   async Shutdown() returns (bool aOk);
 
   async ExecServiceWorkerOp(ServiceWorkerOpArgs aArgs)
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -449,16 +449,19 @@ nsresult RemoteWorkerChild::ExecWorkerOn
   if (NS_WARN_IF(error.Failed())) {
     MOZ_ASSERT(!workerPrivate);
 
     rv = error.StealNSResult();
     return rv;
   }
 
   if (mIsServiceWorker) {
+    RefPtr<RemoteWorkerChild> self = this;
+    workerPrivate->SetRemoteWorkerControllerWeakRef(
+        ThreadSafeWeakPtr<RemoteWorkerChild>(self));
   } else {
     workerPrivate->SetRemoteWorkerController(this);
   }
 
   RefPtr<InitializeWorkerRunnable> runnable =
       new InitializeWorkerRunnable(std::move(workerPrivate), SelfHolder(this));
 
   if (NS_WARN_IF(!runnable->Dispatch())) {
@@ -931,16 +934,52 @@ IPCResult RemoteWorkerChild::RecvExecSer
       aArgs.type() != ServiceWorkerOpArgs::TServiceWorkerFetchEventOpArgs,
       "FetchEvent operations should be sent via PFetchEventOp(Proxy) actors!");
 
   MaybeStartOp(ServiceWorkerOp::Create(aArgs, std::move(aResolve)));
 
   return IPC_OK();
 }
 
+RefPtr<GenericPromise>
+RemoteWorkerChild::MaybeSendSetServiceWorkerSkipWaitingFlag() {
+  RefPtr<GenericPromise::Private> promise =
+      new GenericPromise::Private(__func__);
+
+  RefPtr<RemoteWorkerChild> self = this;
+
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__, [self = std::move(
+                                                                  self),
+                                                              promise] {
+    MOZ_ACCESS_THREAD_BOUND(self->mLauncherData, launcherData);
+
+    if (!launcherData->mIPCActive) {
+      promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
+      return;
+    }
+
+    self->SendSetServiceWorkerSkipWaitingFlag()->Then(
+        GetCurrentThreadSerialEventTarget(), __func__,
+        [promise](
+            const SetServiceWorkerSkipWaitingFlagPromise::ResolveOrRejectValue&
+                aResult) {
+          if (NS_WARN_IF(aResult.IsReject())) {
+            promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
+            return;
+          }
+
+          promise->Resolve(aResult.ResolveValue(), __func__);
+        });
+  });
+
+  GetOwningEventTarget()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
+
+  return promise;
+}
+
 /**
  * PFetchEventOpProxy methods
  */
 PFetchEventOpProxyChild* RemoteWorkerChild::AllocPFetchEventOpProxyChild(
     const ServiceWorkerFetchEventOpArgs& aArgs) {
   RefPtr<FetchEventOpProxyChild> actor = new FetchEventOpProxyChild();
 
   return actor.forget().take();
--- a/dom/workers/remoteworkers/RemoteWorkerChild.h
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.h
@@ -58,17 +58,17 @@ class RemoteWorkerChild final
 
   void FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter);
 
   void AddPortIdentifier(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                          const MessagePortIdentifier& aPortIdentifier);
 
   RefPtr<GenericNonExclusivePromise> GetTerminationPromise();
 
-  void CloseWorkerOnMainThread();
+  RefPtr<GenericPromise> MaybeSendSetServiceWorkerSkipWaitingFlag();
 
  private:
   class InitializeWorkerRunnable;
 
   class Op;
   class SharedWorkerOp;
 
   struct Pending {
--- a/dom/workers/remoteworkers/RemoteWorkerController.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerController.cpp
@@ -273,16 +273,31 @@ RefPtr<ServiceWorkerOpPromise> RemoteWor
 
   if (!op->MaybeStart(this)) {
     mPendingOps.AppendElement(std::move(op));
   }
 
   return promise;
 }
 
+RefPtr<GenericPromise> RemoteWorkerController::SetServiceWorkerSkipWaitingFlag()
+    const {
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mObserver);
+
+  RefPtr<GenericPromise::Private> promise =
+      new GenericPromise::Private(__func__);
+
+  static_cast<RemoteWorkerControllerParent*>(mObserver.get())
+      ->MaybeSendSetServiceWorkerSkipWaitingFlag(
+          [promise](bool aOk) { promise->Resolve(aOk, __func__); });
+
+  return promise;
+}
+
 RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
     Type aType, uint64_t aWindowID)
     : mType(aType), mWindowID(aWindowID) {
   AssertIsOnBackgroundThread();
 }
 
 RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
     const MessagePortIdentifier& aPortIdentifier)
--- a/dom/workers/remoteworkers/RemoteWorkerController.h
+++ b/dom/workers/remoteworkers/RemoteWorkerController.h
@@ -130,16 +130,18 @@ class RemoteWorkerController final {
 
   void Freeze();
 
   void Thaw();
 
   RefPtr<ServiceWorkerOpPromise> ExecServiceWorkerOp(
       ServiceWorkerOpArgs&& aArgs);
 
+  RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag() const;
+
  private:
   RemoteWorkerController(const RemoteWorkerData& aData,
                          RemoteWorkerObserver* aObserver);
 
   ~RemoteWorkerController();
 
   void SetWorkerActor(RemoteWorkerParent* aActor);
 
--- a/dom/workers/remoteworkers/RemoteWorkerControllerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerControllerChild.cpp
@@ -7,16 +7,17 @@
 #include "RemoteWorkerControllerChild.h"
 
 #include <utility>
 
 #include "MainThreadUtils.h"
 #include "nsError.h"
 #include "nsThreadUtils.h"
 
+#include "ServiceWorkerPrivateImpl.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/PFetchEventOpChild.h"
 
 namespace mozilla {
 
 using ipc::IPCResult;
@@ -91,16 +92,37 @@ IPCResult RemoteWorkerControllerChild::R
 
   if (mObserver) {
     mObserver->Terminated();
   }
 
   return IPC_OK();
 }
 
+IPCResult RemoteWorkerControllerChild::RecvSetServiceWorkerSkipWaitingFlag(
+    SetServiceWorkerSkipWaitingFlagResolver&& aResolve) {
+  AssertIsOnMainThread();
+
+  if (mObserver) {
+    static_cast<ServiceWorkerPrivateImpl*>(mObserver.get())
+        ->SetSkipWaitingFlag()
+        ->Then(GetCurrentThreadSerialEventTarget(), __func__,
+               [resolve = std::move(aResolve)](
+                   const GenericPromise::ResolveOrRejectValue& aResult) {
+                 resolve(aResult.IsResolve() ? aResult.ResolveValue() : false);
+               });
+
+    return IPC_OK();
+  }
+
+  aResolve(false);
+
+  return IPC_OK();
+}
+
 void RemoteWorkerControllerChild::RevokeObserver(
     RemoteWorkerObserver* aObserver) {
   AssertIsOnMainThread();
   MOZ_ASSERT(aObserver);
   MOZ_ASSERT(aObserver == mObserver);
 
   mObserver = nullptr;
 }
--- a/dom/workers/remoteworkers/RemoteWorkerControllerChild.h
+++ b/dom/workers/remoteworkers/RemoteWorkerControllerChild.h
@@ -43,16 +43,19 @@ class RemoteWorkerControllerChild final 
   mozilla::ipc::IPCResult RecvCreationFailed();
 
   mozilla::ipc::IPCResult RecvCreationSucceeded();
 
   mozilla::ipc::IPCResult RecvErrorReceived(const ErrorValue& aError);
 
   mozilla::ipc::IPCResult RecvTerminated();
 
+  mozilla::ipc::IPCResult RecvSetServiceWorkerSkipWaitingFlag(
+      SetServiceWorkerSkipWaitingFlagResolver&& aResolve);
+
   RefPtr<RemoteWorkerObserver> mObserver;
 
   bool mIPCActive = true;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
--- a/dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp
@@ -37,16 +37,35 @@ RemoteWorkerControllerParent::RemoteWork
 RefPtr<RemoteWorkerParent> RemoteWorkerControllerParent::GetRemoteWorkerParent()
     const {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mRemoteWorkerController);
 
   return mRemoteWorkerController->mActor;
 }
 
+void RemoteWorkerControllerParent::MaybeSendSetServiceWorkerSkipWaitingFlag(
+    std::function<void(bool)>&& aCallback) {
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aCallback);
+
+  if (!mIPCActive) {
+    aCallback(false);
+    return;
+  }
+
+  SendSetServiceWorkerSkipWaitingFlag()->Then(
+      GetCurrentThreadSerialEventTarget(), __func__,
+      [callback = std::move(aCallback)](
+          const SetServiceWorkerSkipWaitingFlagPromise::ResolveOrRejectValue&
+              aResult) {
+        callback(aResult.IsResolve() ? aResult.ResolveValue() : false);
+      });
+}
+
 RemoteWorkerControllerParent::~RemoteWorkerControllerParent() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mIPCActive);
   MOZ_ASSERT(!mRemoteWorkerController);
 }
 
 PFetchEventOpParent* RemoteWorkerControllerParent::AllocPFetchEventOpParent(
     const ServiceWorkerFetchEventOpArgs& aArgs) {
--- a/dom/workers/remoteworkers/RemoteWorkerControllerParent.h
+++ b/dom/workers/remoteworkers/RemoteWorkerControllerParent.h
@@ -26,16 +26,19 @@ class RemoteWorkerControllerParent final
   NS_INLINE_DECL_REFCOUNTING(RemoteWorkerControllerParent, override)
 
   explicit RemoteWorkerControllerParent(
       const RemoteWorkerData& aRemoteWorkerData);
 
   // Returns the corresponding RemoteWorkerParent (if any).
   RefPtr<RemoteWorkerParent> GetRemoteWorkerParent() const;
 
+  void MaybeSendSetServiceWorkerSkipWaitingFlag(
+      std::function<void(bool)>&& aCallback);
+
  private:
   ~RemoteWorkerControllerParent();
 
   PFetchEventOpParent* AllocPFetchEventOpParent(
       const ServiceWorkerFetchEventOpArgs& aArgs);
 
   mozilla::ipc::IPCResult RecvPFetchEventOpConstructor(
       PFetchEventOpParent* aActor,
--- a/dom/workers/remoteworkers/RemoteWorkerParent.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerParent.cpp
@@ -160,10 +160,27 @@ IPCResult RemoteWorkerParent::RecvClose(
 
 void RemoteWorkerParent::SetController(RemoteWorkerController* aController) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(XRE_IsParentProcess());
 
   mController = aController;
 }
 
+IPCResult RemoteWorkerParent::RecvSetServiceWorkerSkipWaitingFlag(
+    SetServiceWorkerSkipWaitingFlagResolver&& aResolve) {
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (mController) {
+    mController->SetServiceWorkerSkipWaitingFlag()->Then(
+        GetCurrentThreadSerialEventTarget(), __func__,
+        [resolve = aResolve](bool /* unused */) { resolve(true); },
+        [resolve = aResolve](nsresult /* unused */) { resolve(false); });
+  } else {
+    aResolve(false);
+  }
+
+  return IPC_OK();
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/workers/remoteworkers/RemoteWorkerParent.h
+++ b/dom/workers/remoteworkers/RemoteWorkerParent.h
@@ -39,16 +39,19 @@ class RemoteWorkerParent final : public 
   void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
 
   mozilla::ipc::IPCResult RecvError(const ErrorValue& aValue);
 
   mozilla::ipc::IPCResult RecvClose();
 
   mozilla::ipc::IPCResult RecvCreated(const bool& aStatus);
 
+  mozilla::ipc::IPCResult RecvSetServiceWorkerSkipWaitingFlag(
+      SetServiceWorkerSkipWaitingFlagResolver&& aResolve);
+
   bool mDeleteSent = false;
   RefPtr<RemoteWorkerController> mController;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_RemoteWorkerParent_h
--- a/dom/workers/remoteworkers/moz.build
+++ b/dom/workers/remoteworkers/moz.build
@@ -23,16 +23,17 @@ UNIFIED_SOURCES += [
     'RemoteWorkerManager.cpp',
     'RemoteWorkerParent.cpp',
     'RemoteWorkerService.cpp',
     'RemoteWorkerServiceChild.cpp',
     'RemoteWorkerServiceParent.cpp',
 ]
 
 LOCAL_INCLUDES += [
+    '/dom/serviceworkers',
     '/xpcom/build',
 ]
 
 IPDL_SOURCES += [
     'PRemoteWorker.ipdl',
     'PRemoteWorkerController.ipdl',
     'PRemoteWorkerService.ipdl',
     'RemoteWorkerTypes.ipdlh',