Bug 1174381 - ServiceWorkerManager::TeardownRunnable should be called when xpcom-shutdown notification is received, r=nsm
☠☠ backed out by 557cd9bb68b6 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Sun, 21 Jun 2015 10:21:28 +0100
changeset 268017 b7653e3d5f919816b8e58750450ef505257027a8
parent 268016 ed1115ca40839f7e31bca14293c447f2373fc550
child 268018 b00b2c78aa4af4c2d032e6542b696e45856911aa
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-esr52@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnsm
bugs1174381
milestone41.0a1
Bug 1174381 - ServiceWorkerManager::TeardownRunnable should be called when xpcom-shutdown notification is received, r=nsm
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -374,33 +374,27 @@ NS_INTERFACE_MAP_BEGIN(ServiceWorkerMana
   NS_INTERFACE_MAP_ENTRY(nsIServiceWorkerManager)
   NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIServiceWorkerManager)
 NS_INTERFACE_MAP_END
 
 ServiceWorkerManager::ServiceWorkerManager()
   : mActor(nullptr)
+  , mShuttingDown(false)
 {
   // Register this component to PBackground.
   MOZ_ALWAYS_TRUE(BackgroundChild::GetOrCreateForCurrentThread(this));
 }
 
 ServiceWorkerManager::~ServiceWorkerManager()
 {
   // The map will assert if it is not empty when destroyed.
   mRegistrationInfos.Clear();
-
-  if (mActor) {
-    mActor->ManagerShuttingDown();
-
-    nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
-    nsresult rv = NS_DispatchToMainThread(runnable);
-    unused << NS_WARN_IF(NS_FAILED(rv));
-  }
+  MOZ_ASSERT(!mActor);
 }
 
 void
 ServiceWorkerManager::Init()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsRefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
     MOZ_ASSERT(swr);
@@ -1478,29 +1472,33 @@ ServiceWorkerManager::Register(nsIDOMWin
 void
 ServiceWorkerManager::AppendPendingOperation(ServiceWorkerJobQueue* aQueue,
                                              ServiceWorkerJob* aJob)
 {
   MOZ_ASSERT(!mActor);
   MOZ_ASSERT(aQueue);
   MOZ_ASSERT(aJob);
 
-  PendingOperation* opt = mPendingOperations.AppendElement();
-  opt->mQueue = aQueue;
-  opt->mJob = aJob;
+  if (!mShuttingDown) {
+    PendingOperation* opt = mPendingOperations.AppendElement();
+    opt->mQueue = aQueue;
+    opt->mJob = aJob;
+  }
 }
 
 void
 ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
 {
   MOZ_ASSERT(!mActor);
   MOZ_ASSERT(aRunnable);
 
-  PendingOperation* opt = mPendingOperations.AppendElement();
-  opt->mRunnable = aRunnable;
+  if (!mShuttingDown) {
+    PendingOperation* opt = mPendingOperations.AppendElement();
+    opt->mRunnable = aRunnable;
+  }
 }
 
 /*
  * Used to handle ExtendableEvent::waitUntil() and proceed with
  * installation/activation.
  */
 class LifecycleEventPromiseHandler final : public PromiseNativeHandler
 {
@@ -2350,18 +2348,20 @@ private:
         return NS_OK;
       }
 
       // "Invoke [[Clear Registration]]..."
       registration->Clear();
       swm->RemoveRegistration(registration);
     }
 
-    MOZ_ASSERT(swm->mActor);
-    swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
+    // We could be shutting down.
+    if (swm->mActor) {
+      swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
+    }
 
     return NS_OK;
   }
 
   // The unregister job is done irrespective of success or failure of any sort.
   void
   UnregisterAndDone()
   {
@@ -2660,20 +2660,25 @@ ServiceWorkerManager::ActorCreated(mozil
   mPendingOperations.Clear();
 }
 
 void
 ServiceWorkerManager::StoreRegistration(
                                    nsIPrincipal* aPrincipal,
                                    ServiceWorkerRegistrationInfo* aRegistration)
 {
-  MOZ_ASSERT(mActor);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aRegistration);
 
+  if (mShuttingDown) {
+    return;
+  }
+
+  MOZ_ASSERT(mActor);
+
   ServiceWorkerRegistrationData data;
   nsresult rv = PopulateRegistrationData(aPrincipal, aRegistration, data);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   PrincipalInfo principalInfo;
   if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
@@ -3989,16 +3994,20 @@ ServiceWorkerManager::MaybeRemoveRegistr
 }
 
 void
 ServiceWorkerManager::RemoveRegistrationInternal(ServiceWorkerRegistrationInfo* aRegistration)
 {
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(!aRegistration->IsControllingDocuments());
 
+  if (mShuttingDown) {
+    return;
+  }
+
   // All callers should be either from a job in which case the actor is
   // available, or from MaybeStopControlling(), in which case, this will only be
   // called if a valid registration is found. If a valid registration exists,
   // it means the actor is available since the original map of registrations is
   // populated by it, and any new registrations wait until the actor is
   // available before proceeding (See ServiceWorkerRegisterJob::Start).
   MOZ_ASSERT(mActor);
 
@@ -4427,23 +4436,34 @@ ServiceWorkerManager::Observe(nsISupport
     nsCOMPtr<nsIPrincipal> principal;
     app->GetPrincipal(getter_AddRefs(principal));
     if (NS_WARN_IF(!principal)) {
       return NS_OK;
     }
 
     RemoveAllRegistrations(principal);
   } else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+    mShuttingDown = true;
+
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
       obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
       obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
       obs->RemoveObserver(this, WEBAPPS_CLEAR_DATA);
     }
+
+    if (mActor) {
+      mActor->ManagerShuttingDown();
+
+      nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
+      nsresult rv = NS_DispatchToMainThread(runnable);
+      unused << NS_WARN_IF(NS_FAILED(rv));
+      mActor = nullptr;
+    }
   } else {
     MOZ_CRASH("Received message we aren't supposed to be registered for!");
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -535,15 +535,17 @@ private:
   // Removes all service worker registrations for a given principal.
   void
   RemoveAllRegistrations(nsIPrincipal* aPrincipal);
 
   nsRefPtr<ServiceWorkerManagerChild> mActor;
 
   struct PendingOperation;
   nsTArray<PendingOperation> mPendingOperations;
+
+  bool mShuttingDown;
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkermanager_h