Bug 1231213 - Make ServiceWorkerPrivate use ServiceWorkerPrivateImpl when parent-intercept is enabled. r=asuth
☠☠ backed out by 3cf55b7f12f2 ☠ ☠
authorPerry Jiang <perry@mozilla.com>
Wed, 14 Aug 2019 16:20:40 +0000
changeset 488078 906b80778539e1362a444033c435759d01dfe7f0
parent 488077 6a40ab6852cb51e9903751b04d797c5d53549fa5
child 488079 a275eb0b1a191cce3d7b6461ee6b816b3d87ddac
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 - Make ServiceWorkerPrivate use ServiceWorkerPrivateImpl when parent-intercept is enabled. r=asuth Differential Revision: https://phabricator.services.mozilla.com/D26177
dom/serviceworkers/ServiceWorkerPrivate.cpp
dom/serviceworkers/ServiceWorkerPrivate.h
--- a/dom/serviceworkers/ServiceWorkerPrivate.cpp
+++ b/dom/serviceworkers/ServiceWorkerPrivate.cpp
@@ -1,18 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "ServiceWorkerPrivate.h"
 
+#include <utility>
+
 #include "ServiceWorkerCloneData.h"
 #include "ServiceWorkerManager.h"
+#include "ServiceWorkerPrivateImpl.h"
+#include "ServiceWorkerUtils.h"
 #include "nsContentUtils.h"
 #include "nsICacheInfoChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsINamed.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPushErrorReporter.h"
 #include "nsISupportsImpl.h"
@@ -35,18 +39,20 @@
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/PushEventBinding.h"
 #include "mozilla/dom/RequestBinding.h"
 #include "mozilla/dom/WorkerDebugger.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
+#include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/net/CookieSettings.h"
 #include "mozilla/net/NeckoChannelParams.h"
+#include "mozilla/Services.h"
 #include "mozilla/StaticPrefs_dom.h"
 #include "mozilla/Unused.h"
 #include "nsIReferrerInfo.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace mozilla {
@@ -84,21 +90,30 @@ NS_IMPL_ISUPPORTS0(KeepAliveToken)
 
 ServiceWorkerPrivate::ServiceWorkerPrivate(ServiceWorkerInfo* aInfo)
     : mInfo(aInfo), mDebuggerCount(0), mTokenCount(0) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aInfo);
 
   mIdleWorkerTimer = NS_NewTimer();
   MOZ_ASSERT(mIdleWorkerTimer);
+
+  if (ServiceWorkerParentInterceptEnabled()) {
+    RefPtr<ServiceWorkerPrivateImpl> inner = new ServiceWorkerPrivateImpl(this);
+    nsresult rv = inner->Initialize();
+    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+    mInner = inner.forget();
+  }
 }
 
 ServiceWorkerPrivate::~ServiceWorkerPrivate() {
   MOZ_ASSERT(!mWorkerPrivate);
   MOZ_ASSERT(!mTokenCount);
+  MOZ_ASSERT(!mInner);
   MOZ_ASSERT(!mInfo);
   MOZ_ASSERT(mSupportsArray.IsEmpty());
   MOZ_ASSERT(mIdlePromiseHolder.IsEmpty());
 
   mIdleWorkerTimer->Cancel();
 }
 
 namespace {
@@ -175,16 +190,22 @@ class CheckScriptEvaluationWithCallback 
         mWorkerPrivate->DispatchToMainThread(mScriptEvaluationCallback));
   }
 };
 
 }  // anonymous namespace
 
 nsresult ServiceWorkerPrivate::CheckScriptEvaluation(
     LifeCycleEventCallback* aScriptEvaluationCallback) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mInner) {
+    return mInner->CheckScriptEvaluation(aScriptEvaluationCallback);
+  }
+
   nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<WorkerRunnable> r = new CheckScriptEvaluationWithCallback(
       mWorkerPrivate, this, token, aScriptEvaluationCallback);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
@@ -493,16 +514,20 @@ class SendMessageEventRunnable final : p
 
 }  // anonymous namespace
 
 nsresult ServiceWorkerPrivate::SendMessageEvent(
     RefPtr<ServiceWorkerCloneData>&& aData,
     const ClientInfoAndState& aClientInfoAndState) {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (mInner) {
+    return mInner->SendMessageEvent(std::move(aData), aClientInfoAndState);
+  }
+
   nsresult rv = SpawnWorkerIfNeeded(MessageEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<SendMessageEventRunnable> runnable = new SendMessageEventRunnable(
       mWorkerPrivate, token, aClientInfoAndState, std::move(aData));
 
   if (!runnable->Dispatch()) {
@@ -701,16 +726,22 @@ bool LifecycleEventWorkerRunnable::Dispa
 
   return true;
 }
 
 }  // anonymous namespace
 
 nsresult ServiceWorkerPrivate::SendLifeCycleEvent(
     const nsAString& aEventType, LifeCycleEventCallback* aCallback) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mInner) {
+    return mInner->SendLifeCycleEvent(aEventType, aCallback);
+  }
+
   nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<WorkerRunnable> r = new LifecycleEventWorkerRunnable(
       mWorkerPrivate, token, aEventType, aCallback);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
@@ -861,16 +892,22 @@ class SendPushSubscriptionChangeEventRun
   }
 };
 
 }  // anonymous namespace
 
 nsresult ServiceWorkerPrivate::SendPushEvent(
     const nsAString& aMessageId, const Maybe<nsTArray<uint8_t>>& aData,
     ServiceWorkerRegistrationInfo* aRegistration) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mInner) {
+    return mInner->SendPushEvent(aRegistration, aMessageId, aData);
+  }
+
   nsresult rv = SpawnWorkerIfNeeded(PushEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
 
   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> regInfo(
       new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(
           "ServiceWorkerRegistrationInfoProxy", aRegistration, false));
@@ -888,16 +925,22 @@ nsresult ServiceWorkerPrivate::SendPushE
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult ServiceWorkerPrivate::SendPushSubscriptionChangeEvent() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mInner) {
+    return mInner->SendPushSubscriptionChangeEvent();
+  }
+
   nsresult rv = SpawnWorkerIfNeeded(PushSubscriptionChangeEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<WorkerRunnable> r =
       new SendPushSubscriptionChangeEventRunnable(mWorkerPrivate, token);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
@@ -1103,28 +1146,36 @@ class SendNotificationEventRunnable fina
 
 }  // namespace
 
 nsresult ServiceWorkerPrivate::SendNotificationEvent(
     const nsAString& aEventName, const nsAString& aID, const nsAString& aTitle,
     const nsAString& aDir, const nsAString& aLang, const nsAString& aBody,
     const nsAString& aTag, const nsAString& aIcon, const nsAString& aData,
     const nsAString& aBehavior, const nsAString& aScope) {
+  MOZ_ASSERT(NS_IsMainThread());
+
   WakeUpReason why;
   if (aEventName.EqualsLiteral(NOTIFICATION_CLICK_EVENT_NAME)) {
     why = NotificationClickEvent;
     gDOMDisableOpenClickDelay =
         Preferences::GetInt("dom.serviceWorkers.disable_open_click_delay");
   } else if (aEventName.EqualsLiteral(NOTIFICATION_CLOSE_EVENT_NAME)) {
     why = NotificationCloseEvent;
   } else {
     MOZ_ASSERT_UNREACHABLE("Invalid notification event name");
     return NS_ERROR_FAILURE;
   }
 
+  if (mInner) {
+    return mInner->SendNotificationEvent(aEventName, aID, aTitle, aDir, aLang,
+                                         aBody, aTag, aIcon, aData, aBehavior,
+                                         aScope, gDOMDisableOpenClickDelay);
+  }
+
   nsresult rv = SpawnWorkerIfNeeded(why);
   NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
 
   RefPtr<WorkerRunnable> r = new SendNotificationEventRunnable(
       mWorkerPrivate, token, aEventName, aID, aTitle, aDir, aLang, aBody, aTag,
       aIcon, aData, aBehavior, aScope);
@@ -1564,16 +1615,21 @@ nsresult ServiceWorkerPrivate::SendFetch
     }
 
     // Trigger soft updates if necessary.
     registration->MaybeScheduleTimeCheckAndUpdate();
 
     return NS_OK;
   }
 
+  if (mInner) {
+    return mInner->SendFetchEvent(std::move(registration), aChannel, aClientId,
+                                  aResultingClientId, aIsReload);
+  }
+
   aChannel->SetLaunchServiceWorkerStart(TimeStamp::Now());
   aChannel->SetDispatchFetchEventStart(TimeStamp::Now());
 
   bool newWorkerCreated = false;
   rv = SpawnWorkerIfNeeded(FetchEvent, &newWorkerCreated, aLoadGroup);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!newWorkerCreated) {
@@ -1611,16 +1667,17 @@ nsresult ServiceWorkerPrivate::SendFetch
 
   return NS_OK;
 }
 
 nsresult ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
                                                    bool* aNewWorkerCreated,
                                                    nsILoadGroup* aLoadGroup) {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mInner);
 
   // Defaults to no new worker created, but if there is one, we'll set the value
   // to true at the end of this function.
   if (aNewWorkerCreated) {
     *aNewWorkerCreated = false;
   }
 
   // If the worker started shutting down on itself we may have a stale
@@ -1767,16 +1824,20 @@ bool ServiceWorkerPrivate::MaybeStoreISu
 void ServiceWorkerPrivate::RemoveISupports(nsISupports* aSupports) {
   MOZ_ASSERT(NS_IsMainThread());
   mSupportsArray.RemoveElement(aSupports);
 }
 
 void ServiceWorkerPrivate::TerminateWorker() {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (mInner) {
+    return mInner->TerminateWorker();
+  }
+
   mIdleWorkerTimer->Cancel();
   mIdleKeepAliveToken = nullptr;
   if (mWorkerPrivate) {
     if (StaticPrefs::dom_serviceWorkers_testing_enabled()) {
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
       if (os) {
         os->NotifyObservers(nullptr, "service-worker-shutdown", nullptr);
       }
@@ -1794,18 +1855,25 @@ void ServiceWorkerPrivate::TerminateWork
     for (uint32_t i = 0; i < pendingEvents.Length(); ++i) {
       pendingEvents[i]->Cancel();
     }
   }
 }
 
 void ServiceWorkerPrivate::NoteDeadServiceWorkerInfo() {
   MOZ_ASSERT(NS_IsMainThread());
+
+  if (mInner) {
+    mInner->NoteDeadOuter();
+    mInner = nullptr;
+  } else {
+    TerminateWorker();
+  }
+
   mInfo = nullptr;
-  TerminateWorker();
 }
 
 namespace {
 
 class UpdateStateControlRunnable final
     : public MainThreadWorkerControlRunnable {
   const ServiceWorkerState mState;
 
@@ -1821,16 +1889,20 @@ class UpdateStateControlRunnable final
       : MainThreadWorkerControlRunnable(aWorkerPrivate), mState(aState) {}
 };
 
 }  // anonymous namespace
 
 void ServiceWorkerPrivate::UpdateState(ServiceWorkerState aState) {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (mInner) {
+    return mInner->UpdateState(aState);
+  }
+
   if (!mWorkerPrivate) {
     MOZ_DIAGNOSTIC_ASSERT(mPendingFunctionalEvents.IsEmpty());
     return;
   }
 
   RefPtr<WorkerRunnable> r =
       new UpdateStateControlRunnable(mWorkerPrivate, aState);
   Unused << r->Dispatch();
@@ -1849,31 +1921,40 @@ void ServiceWorkerPrivate::UpdateState(S
     }
   }
 }
 
 nsresult ServiceWorkerPrivate::GetDebugger(nsIWorkerDebugger** aResult) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aResult);
 
+  if (mInner) {
+    *aResult = nullptr;
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
   if (!mDebuggerCount) {
     return NS_OK;
   }
 
   MOZ_ASSERT(mWorkerPrivate);
 
   nsCOMPtr<nsIWorkerDebugger> debugger = mWorkerPrivate->Debugger();
   debugger.forget(aResult);
 
   return NS_OK;
 }
 
 nsresult ServiceWorkerPrivate::AttachDebugger() {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (mInner) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
   // When the first debugger attaches to a worker, we spawn a worker if needed,
   // and cancel the idle timeout. The idle timeout should not be reset until
   // the last debugger detached from the worker.
   if (!mDebuggerCount) {
     nsresult rv = SpawnWorkerIfNeeded(AttachEvent);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mIdleWorkerTimer->Cancel();
@@ -1882,16 +1963,20 @@ nsresult ServiceWorkerPrivate::AttachDeb
   ++mDebuggerCount;
 
   return NS_OK;
 }
 
 nsresult ServiceWorkerPrivate::DetachDebugger() {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (mInner) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
   if (!mDebuggerCount) {
     return NS_ERROR_UNEXPECTED;
   }
 
   --mDebuggerCount;
 
   // When the last debugger detaches from a worker, we either reset the idle
   // timeout, or terminate the worker if there are no more active tokens.
@@ -1963,17 +2048,20 @@ NS_IMPL_ISUPPORTS(ServiceWorkerPrivateTi
 void ServiceWorkerPrivate::NoteIdleWorkerCallback(nsITimer* aTimer) {
   MOZ_ASSERT(NS_IsMainThread());
 
   MOZ_ASSERT(aTimer == mIdleWorkerTimer, "Invalid timer!");
 
   // Release ServiceWorkerPrivate's token, since the grace period has ended.
   mIdleKeepAliveToken = nullptr;
 
-  if (mWorkerPrivate) {
+  if (mWorkerPrivate || (mInner && !mInner->WorkerIsDead())) {
+    // There sould only be EITHER mWorkerPrivate or mInner (but not both).
+    MOZ_ASSERT(!(mWorkerPrivate && mInner));
+
     // If we still have a workerPrivate at this point it means there are pending
     // waitUntil promises. Wait a bit more until we forcibly terminate the
     // worker.
     uint32_t timeout =
         Preferences::GetInt("dom.serviceWorkers.idle_extended_timeout");
     nsCOMPtr<nsITimerCallback> cb = new ServiceWorkerPrivateTimerCallback(
         this, &ServiceWorkerPrivate::TerminateWorkerCallback);
     DebugOnly<nsresult> rv = mIdleWorkerTimer->InitWithCallback(
@@ -1994,17 +2082,17 @@ void ServiceWorkerPrivate::TerminateWork
       mInfo->Scope(), "ServiceWorkerGraceTimeoutTermination",
       nsTArray<nsString>{NS_ConvertUTF8toUTF16(mInfo->Scope())});
 
   TerminateWorker();
 }
 
 void ServiceWorkerPrivate::RenewKeepAliveToken(WakeUpReason aWhy) {
   // We should have an active worker if we're renewing the keep alive token.
-  MOZ_ASSERT(mWorkerPrivate);
+  MOZ_ASSERT(mWorkerPrivate || (mInner && !mInner->WorkerIsDead()));
 
   // If there is at least one debugger attached to the worker, the idle worker
   // timeout was canceled when the first debugger attached to the worker. It
   // should not be reset until the last debugger detaches from the worker.
   if (!mDebuggerCount) {
     ResetIdleTimeout();
   }
 
@@ -2049,18 +2137,23 @@ void ServiceWorkerPrivate::ReleaseToken(
       }
     }
   }
 }
 
 already_AddRefed<KeepAliveToken>
 ServiceWorkerPrivate::CreateEventKeepAliveToken() {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mWorkerPrivate);
-  MOZ_ASSERT(mIdleKeepAliveToken);
+
+  // When the WorkerPrivate is in a separate process, we first hold a normal
+  // KeepAliveToken. Then, after we're notified that the worker is alive, we
+  // create the idle KeepAliveToken.
+  MOZ_ASSERT(mWorkerPrivate || (mInner && !mInner->WorkerIsDead()));
+  MOZ_ASSERT(mIdleKeepAliveToken || (mInner && !mInner->WorkerIsDead()));
+
   RefPtr<KeepAliveToken> ref = new KeepAliveToken(this);
   return ref.forget();
 }
 
 void ServiceWorkerPrivate::SetHandlesFetch(bool aValue) {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (NS_WARN_IF(!mInfo)) {
--- a/dom/serviceworkers/ServiceWorkerPrivate.h
+++ b/dom/serviceworkers/ServiceWorkerPrivate.h
@@ -263,16 +263,18 @@ class ServiceWorkerPrivate final {
   // |StoreISupports| and |RemoveISupports|. Note that the array is also
   // cleared whenever the worker is terminated.
   nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
 
   // Array of function event worker runnables that are pending due to
   // the worker activating.  Main thread only.
   nsTArray<RefPtr<WorkerRunnable>> mPendingFunctionalEvents;
 
+  RefPtr<Inner> mInner;
+
   // Used by the owning `ServiceWorkerRegistrationInfo` when it wants to call
   // `Clear` after being unregistered and isn't controlling any clients but this
   // worker (i.e. the registration's active worker) isn't idle yet. Note that
   // such an event should happen at most once in a
   // `ServiceWorkerRegistrationInfo`s lifetime, so this promise should also only
   // be obtained at most once.
   MozPromiseHolder<GenericPromise> mIdlePromiseHolder;