Bug 1231213 - Have ServiceWorkerManager block shutdown on "profile-change-teardown" when in the parent process with parent intercept enabled. r=asuth
☠☠ backed out by 3cf55b7f12f2 ☠ ☠
authorPerry Jiang <perry@mozilla.com>
Wed, 14 Aug 2019 16:19:51 +0000
changeset 488067 395062aef2ec1c0abd3b1426fb376f5fef3e0c11
parent 488066 bacf8499ba7b2caf600a8fef352baf7df3a69d6d
child 488068 6ed55807374f0ba63a36990d06200f77baf713a6
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 - Have ServiceWorkerManager block shutdown on "profile-change-teardown" when in the parent process with parent intercept enabled. r=asuth Differential Revision: https://phabricator.services.mozilla.com/D26166
dom/serviceworkers/ServiceWorkerInfo.cpp
dom/serviceworkers/ServiceWorkerManager.cpp
dom/serviceworkers/ServiceWorkerManager.h
--- a/dom/serviceworkers/ServiceWorkerInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerInfo.cpp
@@ -145,16 +145,17 @@ void ServiceWorkerInfo::UpdateState(Serv
   // TODO: Do we care that these events will race with the propagation of the
   //       state change?
   if (State() != aState) {
     mServiceWorkerPrivate->UpdateState(aState);
   }
   mDescriptor.SetState(aState);
   if (State() == ServiceWorkerState::Redundant) {
     serviceWorkerScriptCache::PurgeCache(mPrincipal, mCacheName);
+    mServiceWorkerPrivate->NoteDeadServiceWorkerInfo();
   }
 }
 
 ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
                                      const nsACString& aScope,
                                      uint64_t aRegistrationId,
                                      uint64_t aRegistrationVersion,
                                      const nsACString& aScriptSpec,
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -20,16 +20,17 @@
 #include "nsIScriptError.h"
 #include "nsISimpleEnumerator.h"
 #include "nsITimer.h"
 #include "nsIUploadChannel2.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDebug.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIPermissionManager.h"
+#include "nsXULAppAPI.h"
 
 #include "jsapi.h"
 
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/SystemGroup.h"
@@ -71,16 +72,17 @@
 #include "ServiceWorkerInfo.h"
 #include "ServiceWorkerJobQueue.h"
 #include "ServiceWorkerManagerChild.h"
 #include "ServiceWorkerPrivate.h"
 #include "ServiceWorkerRegisterJob.h"
 #include "ServiceWorkerRegistrar.h"
 #include "ServiceWorkerRegistration.h"
 #include "ServiceWorkerScriptCache.h"
+#include "ServiceWorkerShutdownBlocker.h"
 #include "ServiceWorkerEvents.h"
 #include "ServiceWorkerUnregisterJob.h"
 #include "ServiceWorkerUpdateJob.h"
 #include "ServiceWorkerUpdaterChild.h"
 #include "ServiceWorkerUtils.h"
 
 #ifdef PostMessage
 #  undef PostMessage
@@ -254,16 +256,46 @@ class TeardownRunnable final : public Ru
   }
 
  private:
   ~TeardownRunnable() {}
 
   RefPtr<ServiceWorkerManagerChild> mActor;
 };
 
+bool ServiceWorkersAreCrossProcess() {
+  return ServiceWorkerParentInterceptEnabled() && XRE_IsE10sParentProcess();
+}
+
+const char* GetXPCOMShutdownTopic() {
+  if (ServiceWorkersAreCrossProcess()) {
+    return "profile-change-teardown";
+  }
+
+  return NS_XPCOM_SHUTDOWN_OBSERVER_ID;
+}
+
+already_AddRefed<nsIAsyncShutdownClient> GetAsyncShutdownBarrier() {
+  AssertIsOnMainThread();
+
+  if (!ServiceWorkersAreCrossProcess()) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
+  MOZ_ASSERT(svc);
+
+  nsCOMPtr<nsIAsyncShutdownClient> barrier;
+  DebugOnly<nsresult> rv =
+      svc->GetProfileChangeTeardown(getter_AddRefs(barrier));
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+  return barrier.forget();
+}
+
 }  // namespace
 
 //////////////////////////
 // ServiceWorkerManager //
 //////////////////////////
 
 NS_IMPL_ADDREF(ServiceWorkerManager)
 NS_IMPL_RELEASE(ServiceWorkerManager)
@@ -275,25 +307,50 @@ NS_INTERFACE_MAP_BEGIN(ServiceWorkerMana
 NS_INTERFACE_MAP_END
 
 ServiceWorkerManager::ServiceWorkerManager()
     : mActor(nullptr), mShuttingDown(false) {}
 
 ServiceWorkerManager::~ServiceWorkerManager() {
   // The map will assert if it is not empty when destroyed.
   mRegistrationInfos.Clear();
-  MOZ_ASSERT(!mActor);
+
+  if (!ServiceWorkersAreCrossProcess()) {
+    MOZ_ASSERT(!mActor);
+  }
+}
+
+void ServiceWorkerManager::BlockShutdownOn(
+    GenericNonExclusivePromise* aPromise) {
+  AssertIsOnMainThread();
+
+  // This may be called when in non-e10s mode with parent-intercept enabled.
+  if (!ServiceWorkersAreCrossProcess()) {
+    return;
+  }
+
+  MOZ_ASSERT(mShutdownBlocker);
+  MOZ_ASSERT(aPromise);
+
+  mShutdownBlocker->WaitOnPromise(aPromise);
 }
 
 void ServiceWorkerManager::Init(ServiceWorkerRegistrar* aRegistrar) {
+  nsCOMPtr<nsIAsyncShutdownClient> shutdownBarrier = GetAsyncShutdownBarrier();
+
+  if (shutdownBarrier) {
+    mShutdownBlocker =
+        ServiceWorkerShutdownBlocker::CreateAndRegisterOn(shutdownBarrier);
+    MOZ_ASSERT(mShutdownBlocker);
+  }
+
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     DebugOnly<nsresult> rv;
-    rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
-                          false /* ownsWeak */);
+    rv = obs->AddObserver(this, GetXPCOMShutdownTopic(), false /* ownsWeak */);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   if (XRE_IsParentProcess()) {
     MOZ_DIAGNOSTIC_ASSERT(aRegistrar);
 
     nsTArray<ServiceWorkerRegistrationData> data;
     aRegistrar->GetRegistrations(data);
@@ -446,19 +503,23 @@ void ServiceWorkerManager::MaybeStartShu
 
     for (auto it2 = it1.UserData()->mInfos.Iter(); !it2.Done(); it2.Next()) {
       RefPtr<ServiceWorkerRegistrationInfo> regInfo = it2.UserData();
       regInfo->Clear();
     }
     it1.UserData()->mInfos.Clear();
   }
 
+  if (mShutdownBlocker) {
+    mShutdownBlocker->StopAcceptingPromises();
+  }
+
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
-    obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+    obs->RemoveObserver(this, GetXPCOMShutdownTopic());
 
     if (XRE_IsParentProcess()) {
       obs->RemoveObserver(this, CLEAR_ORIGIN_DATA);
     }
   }
 
   if (!mActor) {
     return;
@@ -2732,17 +2793,17 @@ ServiceWorkerManager::Observe(nsISupport
     MOZ_ASSERT(XRE_IsParentProcess());
     OriginAttributesPattern pattern;
     MOZ_ALWAYS_TRUE(pattern.Init(nsAutoString(aData)));
 
     RemoveAllRegistrations(&pattern);
     return NS_OK;
   }
 
-  if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+  if (strcmp(aTopic, GetXPCOMShutdownTopic()) == 0) {
     MaybeStartShutdown();
     return NS_OK;
   }
 
   MOZ_CRASH("Received message we aren't supposed to be registered for!");
   return NS_OK;
 }
 
--- a/dom/serviceworkers/ServiceWorkerManager.h
+++ b/dom/serviceworkers/ServiceWorkerManager.h
@@ -46,16 +46,17 @@ class PrincipalInfo;
 namespace dom {
 
 class ContentParent;
 class ServiceWorkerInfo;
 class ServiceWorkerJobQueue;
 class ServiceWorkerManagerChild;
 class ServiceWorkerPrivate;
 class ServiceWorkerRegistrar;
+class ServiceWorkerShutdownBlocker;
 
 class ServiceWorkerUpdateFinishCallback {
  protected:
   virtual ~ServiceWorkerUpdateFinishCallback() {}
 
  public:
   NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback)
 
@@ -275,16 +276,18 @@ class ServiceWorkerManager final : publi
 
   void CheckPendingReadyPromises();
 
   void RemovePendingReadyPromise(const ClientInfo& aClientInfo);
 
   void NoteInheritedController(const ClientInfo& aClientInfo,
                                const ServiceWorkerDescriptor& aController);
 
+  void BlockShutdownOn(GenericNonExclusivePromise* aPromise);
+
   nsresult GetClientRegistration(
       const ClientInfo& aClientInfo,
       ServiceWorkerRegistrationInfo** aRegistrationInfo);
 
  private:
   ServiceWorkerManager();
   ~ServiceWorkerManager();
 
@@ -380,14 +383,16 @@ class ServiceWorkerManager final : publi
   nsresult SendNotificationEvent(const nsAString& aEventName,
                                  const nsACString& aOriginSuffix,
                                  const nsACString& aScope, 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);
+
+  RefPtr<ServiceWorkerShutdownBlocker> mShutdownBlocker;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_workers_serviceworkermanager_h