Bug 1231213 - Have ServiceWorkerManager block shutdown on "profile-change-teardown" when in the parent process with parent intercept enabled. r=asuth
authorPerry Jiang <perry@mozilla.com>
Thu, 15 Aug 2019 17:26:40 +0000
changeset 488301 fa280993de59a5e729359aa774391c54313c3807
parent 488300 6d3ff0852089c122aa3dc900954cd897c5c863f5
child 488302 1db490b0883e9c5448beb6dd653e292318381755
push id113906
push userncsoregi@mozilla.com
push dateFri, 16 Aug 2019 04:07:24 +0000
treeherdermozilla-inbound@d887276421d3 [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