Bug 1425975 P2 Add ServiceWorkerManager mControlledClients to track controlled ClientHandle references. r=asuth
authorBen Kelly <ben@wanderview.com>
Fri, 05 Jan 2018 12:10:20 -0500
changeset 398011 ef7cf1394d0fd6fbd9e97bed3cc705cc439107a5
parent 398010 21042078d8070e0e704ebacfc7abd20968d42fda
child 398012 818fd73be280cca813edeea710596876ce91f234
push id33197
push userarchaeopteryx@coole-files.de
push dateFri, 05 Jan 2018 22:34:03 +0000
treeherdermozilla-central@56c1eb9c065a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1425975
milestone59.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 1425975 P2 Add ServiceWorkerManager mControlledClients to track controlled ClientHandle references. r=asuth
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -309,16 +309,51 @@ ServiceWorkerManager::Init(ServiceWorker
     MaybeStartShutdown();
     return;
   }
 
   mActor = static_cast<ServiceWorkerManagerChild*>(actor);
 }
 
 void
+ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo,
+                                             ServiceWorkerRegistrationInfo* aRegistrationInfo)
+{
+  RefPtr<ClientHandle> clientHandle =
+    ClientManager::CreateHandle(aClientInfo,
+                                SystemGroup::EventTargetFor(TaskCategory::Other));
+
+  auto entry = mControlledClients.LookupForAdd(aClientInfo.Id());
+  if (entry) {
+    entry.Data()->mRegistrationInfo = aRegistrationInfo;
+  } else {
+    entry.OrInsert([&] {
+      return new ControlledClientData(clientHandle, aRegistrationInfo);
+    });
+
+    RefPtr<ServiceWorkerManager> self(this);
+    clientHandle->OnDetach()->Then(
+      SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
+      [self = Move(self), aClientInfo] {
+        self->StopControllingClient(aClientInfo);
+      });
+  }
+}
+
+void
+ServiceWorkerManager::StopControllingClient(const ClientInfo& aClientInfo)
+{
+  auto entry = mControlledClients.Lookup(aClientInfo.Id());
+  if (!entry) {
+    return;
+  }
+  entry.Remove();
+}
+
+void
 ServiceWorkerManager::MaybeStartShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown) {
     return;
   }
 
@@ -2357,33 +2392,45 @@ ServiceWorkerManager::StartControllingAD
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aDoc);
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
   MOZ_DIAGNOSTIC_ASSERT(storageAllowed == nsContentUtils::StorageAccess::eAllow);
 #endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
 
-  RefPtr<GenericPromise> ref = GenericPromise::CreateAndResolve(true, __func__);
+  RefPtr<GenericPromise> ref;
+
+  ServiceWorkerInfo* activeWorker = aRegistration->GetActive();
+  if (NS_WARN_IF(!activeWorker)) {
+    ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+                                          __func__);
+    return ref.forget();
+  }
+
+  Maybe<ClientInfo> clientInfo = aDoc->GetClientInfo();
+  if (NS_WARN_IF(clientInfo.isNothing())) {
+    ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+                                          __func__);
+    return ref.forget();
+  }
 
   aRegistration->StartControllingADocument();
   mControlledDocuments.Put(aDoc, aRegistration);
 
+  StartControllingClient(clientInfo.ref(), aRegistration);
+
   // Mark the document's ClientSource as controlled using the ClientHandle
   // interface.  While we could get at the ClientSource directly from the
   // document here, our goal is to move ServiceWorkerManager to a separate
   // process.  Using the ClientHandle supports this remote operation.
-  ServiceWorkerInfo* activeWorker = aRegistration->GetActive();
-  Maybe<ClientInfo> clientInfo = aDoc->GetClientInfo();
-  if (activeWorker && clientInfo.isSome()) {
-    RefPtr<ClientHandle> clientHandle =
-      ClientManager::CreateHandle(clientInfo.ref(),
-                                  SystemGroup::EventTargetFor(TaskCategory::Other));
-    ref = Move(clientHandle->Control(activeWorker->Descriptor()));
-  }
+  RefPtr<ClientHandle> clientHandle =
+    ClientManager::CreateHandle(clientInfo.ref(),
+                                SystemGroup::EventTargetFor(TaskCategory::Other));
+  ref = Move(clientHandle->Control(activeWorker->Descriptor()));
 
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
   return Move(ref);
 }
 
 void
 ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration)
 {
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -16,16 +16,17 @@
 #include "mozilla/ConsoleReportCollector.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ClientHandle.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerCommon.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
 #include "mozilla/dom/workers/ServiceWorkerRegistrationInfo.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
@@ -100,16 +101,31 @@ public:
 
   struct RegistrationDataPerPrincipal;
   nsClassHashtable<nsCStringHashKey, RegistrationDataPerPrincipal> mRegistrationInfos;
 
   nsTObserverArray<ServiceWorkerRegistrationListener*> mServiceWorkerRegistrationListeners;
 
   nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments;
 
+  struct ControlledClientData
+  {
+    RefPtr<ClientHandle> mClientHandle;
+    RefPtr<ServiceWorkerRegistrationInfo> mRegistrationInfo;
+
+    ControlledClientData(ClientHandle* aClientHandle,
+                         ServiceWorkerRegistrationInfo* aRegistrationInfo)
+      : mClientHandle(aClientHandle)
+      , mRegistrationInfo(aRegistrationInfo)
+    {
+    }
+  };
+
+  nsClassHashtable<nsIDHashKey, ControlledClientData> mControlledClients;
+
   // Track all documents that have attempted to register a service worker for a
   // given scope.
   typedef nsTArray<nsCOMPtr<nsIWeakReference>> WeakDocumentList;
   nsClassHashtable<nsCStringHashKey, WeakDocumentList> mRegisteringDocuments;
 
   // Track all intercepted navigation channels for a given scope.  Channels are
   // placed in the appropriate list before dispatch the FetchEvent to the worker
   // thread and removed once FetchEvent processing dispatches back to the main
@@ -324,16 +340,23 @@ public:
 private:
   ServiceWorkerManager();
   ~ServiceWorkerManager();
 
   void
   Init(ServiceWorkerRegistrar* aRegistrar);
 
   void
+  StartControllingClient(const ClientInfo& aClientInfo,
+                         ServiceWorkerRegistrationInfo* aRegistrationInfo);
+
+  void
+  StopControllingClient(const ClientInfo& aClientInfo);
+
+  void
   MaybeStartShutdown();
 
   already_AddRefed<ServiceWorkerJobQueue>
   GetOrCreateJobQueue(const nsACString& aOriginSuffix,
                       const nsACString& aScope);
 
   void
   MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);