Bug 1167296 - patch 2 - ServiceWorkerManager::Remove should use PBackground, r=nsm
authorAndrea Marchesini <amarchesini@mozilla.com>
Sun, 21 Jun 2015 12:19:07 +0100
changeset 268019 e47c1128e79b98f398c8a74dd21ed88b350a2e5d
parent 268018 b00b2c78aa4af4c2d032e6542b696e45856911aa
child 268020 6f19ae2a4c8aac7e2bb1d3fc0cd134ecd5300582
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
bugs1167296
milestone41.0a1
Bug 1167296 - patch 2 - ServiceWorkerManager::Remove should use PBackground, r=nsm
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PContent.ipdl
dom/workers/PServiceWorkerManager.ipdl
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
dom/workers/ServiceWorkerManagerChild.cpp
dom/workers/ServiceWorkerManagerChild.h
dom/workers/ServiceWorkerManagerParent.cpp
dom/workers/ServiceWorkerManagerParent.h
dom/workers/ServiceWorkerManagerService.cpp
dom/workers/ServiceWorkerManagerService.h
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -28,17 +28,17 @@ interface nsIServiceWorkerInfo : nsISupp
   readonly attribute DOMString scope;
   readonly attribute DOMString scriptSpec;
   readonly attribute DOMString currentWorkerURL;
 
   readonly attribute DOMString activeCacheName;
   readonly attribute DOMString waitingCacheName;
 };
 
-[scriptable, builtinclass, uuid(d72bd950-967c-4642-bd34-7f688d9b624a)]
+[scriptable, builtinclass, uuid(aee94712-9adb-4c0b-80a7-a8df34dfa2e8)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -100,17 +100,17 @@ interface nsIServiceWorkerManager : nsIS
    * Clears ServiceWorker registrations from memory and disk for the specified
    * host.
    * - All ServiceWorker instances change their state to redundant.
    * - Existing ServiceWorker instances handling fetches will keep running.
    * - All documents will immediately stop being controlled.
    * - Unregister jobs will be queued for all registrations.
    *   This eventually results in the registration being deleted from disk too.
    */
-  void remove(in AUTF8String aHost);
+  void removeAndPropagate(in AUTF8String aHost);
 
   // Testing
   DOMString getScopeForUrl(in nsIPrincipal aPrincipal, in DOMString aPath);
 
   // Note: This is meant to be used only by about:serviceworkers.
   //It returns an array of nsIServiceWorkerInfo.
   nsIArray getAllRegistrations();
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1239,26 +1239,16 @@ ContentChild::RecvUpdateServiceWorkerReg
 {
     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     if (swm) {
         swm->UpdateAllRegistrations();
     }
     return true;
 }
 
-bool
-ContentChild::RecvRemoveServiceWorkerRegistrationsForDomain(const nsString& aDomain)
-{
-    nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
-    if (swm) {
-        swm->Remove(NS_ConvertUTF16toUTF8(aDomain));
-    }
-    return true;
-}
-
 static CancelableTask* sFirstIdleTask;
 
 static void FirstIdle(void)
 {
     MOZ_ASSERT(sFirstIdleTask);
     sFirstIdleTask = nullptr;
     ContentChild::GetSingleton()->SendFirstIdle();
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -300,18 +300,16 @@ public:
     virtual bool RecvSetConnectivity(const bool& connectivity) override;
 
     virtual bool RecvSpeakerManagerNotify() override;
 
     virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL) override;
 
     virtual bool RecvUpdateServiceWorkerRegistrations() override;
 
-    virtual bool RecvRemoveServiceWorkerRegistrationsForDomain(const nsString& aDomain) override;
-
     virtual bool RecvNotifyVisited(const URIParams& aURI) override;
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId,
                                            const uint32_t& aMemoryAvailable) override;
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -501,18 +501,16 @@ child:
     /**
      * Communication between the PuppetBidiKeyboard and the actual
      * BidiKeyboard hosted by the parent
      */
     async BidiKeyboardNotify(bool isLangRTL);
 
     async UpdateServiceWorkerRegistrations();
 
-    async RemoveServiceWorkerRegistrationsForDomain(nsString aDomain);
-
     async DataStoreNotify(uint32_t aAppId, nsString aName,
                           nsString aManifestURL);
 
     /**
      * Dump this process's GC and CC logs to the provided files.
      *
      * For documentation on the other args, see dumpGCAndCCLogsToFile in
      * nsIMemoryInfoDumper.idl
--- a/dom/workers/PServiceWorkerManager.ipdl
+++ b/dom/workers/PServiceWorkerManager.ipdl
@@ -20,23 +20,26 @@ parent:
   Register(ServiceWorkerRegistrationData data);
 
   Unregister(PrincipalInfo principalInfo, nsString scope);
 
   PropagateSoftUpdate(OriginAttributes originAttributes,
                       nsString scope);
   PropagateUnregister(PrincipalInfo principalInfo, nsString scope);
 
+  PropagateRemove(nsCString host);
+
   PropagateRemoveAll();
 
   Shutdown();
 
 child:
   NotifyRegister(ServiceWorkerRegistrationData data);
   NotifySoftUpdate(OriginAttributes originAttributes, nsString scope);
   NotifyUnregister(PrincipalInfo principalInfo, nsString scope);
+  NotifyRemove(nsCString host);
   NotifyRemoveAll();
 
   __delete__();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -778,16 +778,64 @@ private:
   ~PropagateUnregisterRunnable()
   {}
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
   const nsString mScope;
 };
 
+class RemoveRunnable final : public nsRunnable
+{
+public:
+  explicit RemoveRunnable(const nsACString& aHost)
+  {}
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    MOZ_ASSERT(swm);
+
+    swm->Remove(mHost);
+    return NS_OK;
+  }
+
+private:
+  ~RemoveRunnable()
+  {}
+
+  const nsCString mHost;
+};
+
+class PropagateRemoveRunnable final : public nsRunnable
+{
+public:
+  explicit PropagateRemoveRunnable(const nsACString& aHost)
+  {}
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    MOZ_ASSERT(swm);
+
+    swm->PropagateRemove(mHost);
+    return NS_OK;
+  }
+
+private:
+  ~PropagateRemoveRunnable()
+  {}
+
+  const nsCString mHost;
+};
+
 class PropagateRemoveAllRunnable final : public nsRunnable
 {
 public:
   PropagateRemoveAllRunnable()
   {}
 
   NS_IMETHOD Run() override
   {
@@ -2328,16 +2376,21 @@ private:
     PrincipalInfo principalInfo;
     if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(mPrincipal,
                                                       &principalInfo)))) {
       return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
     }
 
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
+    // We could be shutting down.
+    if (swm->mActor) {
+      swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
+    }
+
     nsAutoCString scopeKey;
     nsresult rv = swm->PrincipalToScopeKey(mPrincipal, scopeKey);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
     }
 
     // "Let registration be the result of running [[Get Registration]]
     // algorithm passing scope as the argument."
@@ -2370,21 +2423,16 @@ private:
         return NS_OK;
       }
 
       // "Invoke [[Clear Registration]]..."
       registration->Clear();
       swm->RemoveRegistration(registration);
     }
 
-    // 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()
   {
     nsresult rv = Unregister();
@@ -4348,22 +4396,52 @@ ServiceWorkerManager::ForceUnregister(Re
     queue->CancelJobs();
   }
 
   // Since Unregister is async, it is ok to call it in an enumeration.
   Unregister(aRegistration->mPrincipal, nullptr, NS_ConvertUTF8toUTF16(aRegistration->mScope));
 }
 
 NS_IMETHODIMP
+ServiceWorkerManager::RemoveAndPropagate(const nsACString& aHost)
+{
+  Remove(aHost);
+  PropagateRemove(aHost);
+  return NS_OK;
+}
+
+void
 ServiceWorkerManager::Remove(const nsACString& aHost)
 {
   AssertIsOnMainThread();
+
+  // We need to postpone this operation in case we don't have an actor because
+  // this is needed by the ForceUnregister.
+  if (!mActor) {
+    nsRefPtr<nsIRunnable> runnable = new RemoveRunnable(aHost);
+    AppendPendingOperation(runnable);
+    return;
+  }
+
   mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal,
                                    &const_cast<nsACString&>(aHost));
-  return NS_OK;
+}
+
+void
+ServiceWorkerManager::PropagateRemove(const nsACString& aHost)
+{
+  AssertIsOnMainThread();
+
+  if (!mActor) {
+    nsRefPtr<nsIRunnable> runnable = new PropagateRemoveRunnable(aHost);
+    AppendPendingOperation(runnable);
+    return;
+  }
+
+  mActor->SendPropagateRemove(nsCString(aHost));
 }
 
 void
 ServiceWorkerManager::RemoveAll()
 {
   AssertIsOnMainThread();
   mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal, nullptr);
 }
@@ -4431,27 +4509,23 @@ ServiceWorkerManager::Observe(nsISupport
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
   if (strcmp(aTopic, PURGE_SESSION_HISTORY) == 0) {
     RemoveAll();
     PropagateRemoveAll();
     return NS_OK;
   }
 
-  nsAutoTArray<ContentParent*,1> children;
-  ContentParent::GetAll(children);
-
   if (strcmp(aTopic, PURGE_DOMAIN_DATA) == 0) {
     nsAutoString domain(aData);
-    for (uint32_t i = 0; i < children.Length(); i++) {
-      unused << children[i]->SendRemoveServiceWorkerRegistrationsForDomain(domain);
-    }
-
-    Remove(NS_ConvertUTF16toUTF8(domain));
-  } else if (strcmp(aTopic, WEBAPPS_CLEAR_DATA) == 0) {
+    RemoveAndPropagate(NS_ConvertUTF16toUTF8(domain));
+    return NS_OK;
+  }
+
+  if (strcmp(aTopic, WEBAPPS_CLEAR_DATA) == 0) {
     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
       do_QueryInterface(aSubject);
     if (NS_WARN_IF(!params)) {
       return NS_OK;
     }
 
     uint32_t appId;
     nsresult rv = params->GetAppId(&appId);
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -304,16 +304,22 @@ public:
   void
   SoftUpdate(const OriginAttributes& aOriginAttributes, const nsACString& aScope);
 
   void
   PropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
                       const nsAString& aScope);
 
   void
+  PropagateRemove(const nsACString& aHost);
+
+  void
+  Remove(const nsACString& aHost);
+
+  void
   PropagateRemoveAll();
 
   void
   RemoveAll();
 
   already_AddRefed<ServiceWorkerRegistrationInfo>
   GetRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope) const;
 
--- a/dom/workers/ServiceWorkerManagerChild.cpp
+++ b/dom/workers/ServiceWorkerManagerChild.cpp
@@ -63,16 +63,30 @@ ServiceWorkerManagerChild::RecvNotifyUnr
   }
 
   nsresult rv = swm->Unregister(principal, nullptr, aScope);
   unused << NS_WARN_IF(NS_FAILED(rv));
   return true;
 }
 
 bool
+ServiceWorkerManagerChild::RecvNotifyRemove(const nsCString& aHost)
+{
+  if (mShuttingDown) {
+    return true;
+  }
+
+  nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  MOZ_ASSERT(swm);
+
+  swm->Remove(aHost);
+  return true;
+}
+
+bool
 ServiceWorkerManagerChild::RecvNotifyRemoveAll()
 {
   if (mShuttingDown) {
     return true;
   }
 
   nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   MOZ_ASSERT(swm);
--- a/dom/workers/ServiceWorkerManagerChild.h
+++ b/dom/workers/ServiceWorkerManagerChild.h
@@ -37,16 +37,18 @@ public:
                                                                        override;
 
   virtual bool RecvNotifySoftUpdate(const OriginAttributes& aOriginAttributes,
                                     const nsString& aScope) override;
 
   virtual bool RecvNotifyUnregister(const PrincipalInfo& aPrincipalInfo,
                                     const nsString& aScope) override;
 
+  virtual bool RecvNotifyRemove(const nsCString& aHost) override;
+
   virtual bool RecvNotifyRemoveAll() override;
 
 private:
   ServiceWorkerManagerChild()
     : mShuttingDown(false)
   {}
 
   ~ServiceWorkerManagerChild() {}
--- a/dom/workers/ServiceWorkerManagerParent.cpp
+++ b/dom/workers/ServiceWorkerManagerParent.cpp
@@ -252,16 +252,29 @@ ServiceWorkerManagerParent::RecvPropagat
     return false;
   }
 
   mService->PropagateUnregister(mID, aPrincipalInfo, aScope);
   return true;
 }
 
 bool
+ServiceWorkerManagerParent::RecvPropagateRemove(const nsCString& aHost)
+{
+  AssertIsOnBackgroundThread();
+
+  if (NS_WARN_IF(!mService)) {
+    return false;
+  }
+
+  mService->PropagateRemove(mID, aHost);
+  return true;
+}
+
+bool
 ServiceWorkerManagerParent::RecvPropagateRemoveAll()
 {
   AssertIsOnBackgroundThread();
 
   if (NS_WARN_IF(!mService)) {
     return false;
   }
 
--- a/dom/workers/ServiceWorkerManagerParent.h
+++ b/dom/workers/ServiceWorkerManagerParent.h
@@ -43,16 +43,18 @@ private:
                               const nsString& aScope) override;
 
   virtual bool RecvPropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
                                        const nsString& aScope) override;
 
   virtual bool RecvPropagateUnregister(const PrincipalInfo& aPrincipalInfo,
                                        const nsString& aScope) override;
 
+  virtual bool RecvPropagateRemove(const nsCString& aHost) override;
+
   virtual bool RecvPropagateRemoveAll() override;
 
   virtual bool RecvShutdown() override;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   nsRefPtr<ServiceWorkerManagerService> mService;
 
--- a/dom/workers/ServiceWorkerManagerService.cpp
+++ b/dom/workers/ServiceWorkerManagerService.cpp
@@ -224,17 +224,17 @@ UnregisterEnumerator(nsPtrHashKey<Servic
 #endif
   }
 
   return PL_DHASH_NEXT;
 }
 
 struct MOZ_STACK_CLASS RemoveAllData final
 {
-  RemoveAllData(uint64_t aParentID)
+  explicit RemoveAllData(uint64_t aParentID)
     : mParentID(aParentID)
 #ifdef DEBUG
     , mParentFound(false)
 #endif
   {
     MOZ_COUNT_CTOR(RemoveAllData);
   }
 
@@ -264,16 +264,61 @@ RemoveAllEnumerator(nsPtrHashKey<Service
   } else {
     data->mParentFound = true;
 #endif
   }
 
   return PL_DHASH_NEXT;
 }
 
+struct MOZ_STACK_CLASS RemoveData final
+{
+  RemoveData(const nsACString& aHost,
+             uint64_t aParentID)
+    : mHost(aHost)
+    , mParentID(aParentID)
+#ifdef DEBUG
+    , mParentFound(false)
+#endif
+  {
+    MOZ_COUNT_CTOR(RemoveData);
+  }
+
+  ~RemoveData()
+  {
+    MOZ_COUNT_DTOR(RemoveData);
+  }
+
+  const nsCString mHost;
+  const uint64_t mParentID;
+#ifdef DEBUG
+  bool mParentFound;
+#endif
+};
+
+PLDHashOperator
+RemoveEnumerator(nsPtrHashKey<ServiceWorkerManagerParent>* aKey, void* aPtr)
+{
+  AssertIsOnBackgroundThread();
+
+  auto* data = static_cast<RemoveData*>(aPtr);
+  ServiceWorkerManagerParent* parent = aKey->GetKey();
+  MOZ_ASSERT(parent);
+
+  if (parent->ID() != data->mParentID) {
+    unused << parent->SendNotifyRemove(data->mHost);
+#ifdef DEBUG
+  } else {
+    data->mParentFound = true;
+#endif
+  }
+
+  return PL_DHASH_NEXT;
+}
+
 } // anonymous namespce
 
 void
 ServiceWorkerManagerService::PropagateRegistration(
                                            uint64_t aParentID,
                                            ServiceWorkerRegistrationData& aData)
 {
   AssertIsOnBackgroundThread();
@@ -323,16 +368,30 @@ ServiceWorkerManagerService::PropagateUn
   mAgents.EnumerateEntries(UnregisterEnumerator, &data);
 
 #ifdef DEBUG
   MOZ_ASSERT(data.mParentFound);
 #endif
 }
 
 void
+ServiceWorkerManagerService::PropagateRemove(uint64_t aParentID,
+                                             const nsACString& aHost)
+{
+  AssertIsOnBackgroundThread();
+
+  RemoveData data(aHost, aParentID);
+  mAgents.EnumerateEntries(RemoveEnumerator, &data);
+
+#ifdef DEBUG
+  MOZ_ASSERT(data.mParentFound);
+#endif
+}
+
+void
 ServiceWorkerManagerService::PropagateRemoveAll(uint64_t aParentID)
 {
   AssertIsOnBackgroundThread();
 
   nsRefPtr<dom::ServiceWorkerRegistrar> service =
     dom::ServiceWorkerRegistrar::Get();
   MOZ_ASSERT(service);
 
--- a/dom/workers/ServiceWorkerManagerService.h
+++ b/dom/workers/ServiceWorkerManagerService.h
@@ -44,16 +44,18 @@ public:
   void PropagateSoftUpdate(uint64_t aParentID,
                            const OriginAttributes& aOriginAttributes,
                            const nsAString& aScope);
 
   void PropagateUnregister(uint64_t aParentID,
                            const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
                            const nsAString& aScope);
 
+  void PropagateRemove(uint64_t aParentID, const nsACString& aHost);
+
   void PropagateRemoveAll(uint64_t aParentID);
 
 private:
   ServiceWorkerManagerService();
   ~ServiceWorkerManagerService();
 
   nsTHashtable<nsPtrHashKey<ServiceWorkerManagerParent>> mAgents;
 };