Bug 1113627 - Refactor lifecycle event dispatching and handling. r=baku,bz
authorNikhil Marathe <nsm.nikhil@gmail.com>
Fri, 19 Dec 2014 05:01:53 -0800
changeset 239411 53a300073430e727fe1783df8897c555555eef51
parent 239410 1c33995cc288c060a921054f80808523b3ca949c
child 239412 56339532dd96c7d2a7f4f109026d47828b1c6886
push id497
push usermleibovic@mozilla.com
push dateWed, 28 Jan 2015 16:43:37 +0000
reviewersbaku, bz
bugs1113627
milestone38.0a1
Bug 1113627 - Refactor lifecycle event dispatching and handling. r=baku,bz
dom/events/Event.h
dom/webidl/InstallEvent.webidl
dom/workers/ServiceWorkerEvents.h
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManager.h
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -27,16 +27,22 @@ class nsPresContext;
 namespace mozilla {
 namespace dom {
 
 class EventTarget;
 class WantsPopupControlCheck;
 #define GENERATED_EVENT(EventClass_) class EventClass_;
 #include "mozilla/dom/GeneratedEventList.h"
 #undef GENERATED_EVENT
+// ExtendableEvent and InstallEvent are ServiceWorker events that are not
+// autogenerated since they have some extra methods.
+namespace workers {
+class ExtendableEvent;
+class InstallEvent;
+} // namespace workers
 
 // Dummy class so we can cast through it to get from nsISupports to
 // Event subclasses with only two non-ambiguous static casts.
 class EventBase : public nsIDOMEvent
 {
 };
 
 class Event : public EventBase,
@@ -99,16 +105,28 @@ public:
 #define GENERATED_EVENT(EventClass_) \
   virtual EventClass_* As##EventClass_()  \
   {                                       \
     return nullptr;                       \
   }
 #include "mozilla/dom/GeneratedEventList.h"
 #undef GENERATED_EVENT
 
+  // ExtendableEvent and InstallEvent are ServiceWorker events that are not
+  // autogenerated since they have some extra methods.
+  virtual workers::ExtendableEvent* AsExtendableEvent()
+  {
+    return nullptr;
+  }
+
+  virtual workers::InstallEvent* AsInstallEvent()
+  {
+    return nullptr;
+  }
+
   // nsIDOMEvent Interface
   NS_DECL_NSIDOMEVENT
 
   void InitPresContextData(nsPresContext* aPresContext);
 
   // Returns true if the event should be trusted.
   bool Init(EventTarget* aGlobal);
 
--- a/dom/webidl/InstallEvent.webidl
+++ b/dom/webidl/InstallEvent.webidl
@@ -11,11 +11,11 @@
  Exposed=ServiceWorker]
 interface InstallEvent : ExtendableEvent {
   readonly attribute ServiceWorker? activeWorker;
   void replace();
 };
 
 // Should be in the spec soon to satisfy conventions about events.
 // https://github.com/slightlyoff/ServiceWorker/issues/216.
-dictionary InstallEventInit : EventInit {
+dictionary InstallEventInit : ExtendableEventInit {
   ServiceWorker? activeWorker = null;
 };
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -64,16 +64,21 @@ public:
   WaitUntil(Promise& aPromise);
 
   already_AddRefed<Promise>
   GetPromise() const
   {
     nsRefPtr<Promise> p = mPromise;
     return p.forget();
   }
+
+  virtual ExtendableEvent* AsExtendableEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
 };
 
 class InstallEvent MOZ_FINAL : public ExtendableEvent
 {
   // FIXME(nsm): Bug 982787 will allow actually populating this.
   nsRefPtr<ServiceWorker> mActiveWorker;
   bool mActivateImmediately;
 
@@ -127,12 +132,17 @@ public:
     mActivateImmediately = true;
   };
 
   bool
   ActivateImmediately() const
   {
     return mActivateImmediately;
   }
+
+  InstallEvent* AsInstallEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
 };
 
 END_WORKERS_NAMESPACE
 #endif /* mozilla_dom_workers_serviceworkerevents_h__ */
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -101,36 +101,16 @@ ServiceWorkerRegistrationInfo::ServiceWo
 
 ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
 {
   if (IsControllingDocuments()) {
     NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
   }
 }
 
-class QueueFireUpdateFoundRunnable MOZ_FINAL : public nsRunnable
-{
-  nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-public:
-  explicit QueueFireUpdateFoundRunnable(ServiceWorkerRegistrationInfo* aReg)
-    : mRegistration(aReg)
-  {
-    MOZ_ASSERT(aReg);
-  }
-
-  NS_IMETHOD
-  Run()
-  {
-    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->FireEventOnServiceWorkerRegistrations(mRegistration,
-                                               NS_LITERAL_STRING("updatefound"));
-    return NS_OK;
-  }
-};
-
 //////////////////////////
 // ServiceWorkerManager //
 //////////////////////////
 
 NS_IMPL_ADDREF(ServiceWorkerManager)
 NS_IMPL_RELEASE(ServiceWorkerManager)
 
 NS_INTERFACE_MAP_BEGIN(ServiceWorkerManager)
@@ -158,70 +138,118 @@ ServiceWorkerManager::CleanupServiceWork
                                                       void *aUnused)
 {
   aDomainInfo->mServiceWorkerRegistrationInfos.Clear();
   return PL_DHASH_NEXT;
 }
 
 class ServiceWorkerRegisterJob;
 
-class FinishInstallRunnable MOZ_FINAL : public nsRunnable
+class ContinueLifecycleTask : public nsISupports
+{
+  NS_DECL_ISUPPORTS
+
+protected:
+  virtual ~ContinueLifecycleTask()
+  { }
+
+public:
+  virtual void ContinueAfterWorkerEvent(bool aSuccess,
+                                        bool aActivateImmediately) = 0;
+};
+
+NS_IMPL_ISUPPORTS0(ContinueLifecycleTask);
+
+class ContinueInstallTask MOZ_FINAL : public ContinueLifecycleTask
 {
-  nsMainThreadPtrHandle<nsISupports> mJob;
+  nsRefPtr<ServiceWorkerRegisterJob> mJob;
+
+public:
+  explicit ContinueInstallTask(ServiceWorkerRegisterJob* aJob)
+    : mJob(aJob)
+  { }
+
+  void ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately) MOZ_OVERRIDE;
+};
+
+class ContinueActivateTask MOZ_FINAL : public ContinueLifecycleTask
+{
+  nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
+
+public:
+  explicit ContinueActivateTask(ServiceWorkerRegistrationInfo* aReg)
+    : mRegistration(aReg)
+  { }
+
+  void
+  ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately /* unused */) MOZ_OVERRIDE
+  {
+    mRegistration->FinishActivate(aSuccess);
+  }
+};
+
+class ContinueLifecycleRunnable MOZ_FINAL : public nsRunnable
+{
+  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
   bool mSuccess;
   bool mActivateImmediately;
 
 public:
-  explicit FinishInstallRunnable(const nsMainThreadPtrHandle<nsISupports>& aJob,
-                                 bool aSuccess,
-                                 bool aActivateImmediately)
-    : mJob(aJob)
+  ContinueLifecycleRunnable(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
+                            bool aSuccess,
+                            bool aActivateImmediately)
+    : mTask(aTask)
     , mSuccess(aSuccess)
     , mActivateImmediately(aActivateImmediately)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   NS_IMETHOD
-  Run() MOZ_OVERRIDE;
+  Run() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+    mTask->ContinueAfterWorkerEvent(mSuccess, mActivateImmediately);
+    return NS_OK;
+  }
 };
 
 /*
  * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  * since it fires the event. This is ok since there can't be nested
  * ServiceWorkers, so the parent thread -> worker thread requirement for
  * runnables is satisfied.
  */
-class InstallEventRunnable MOZ_FINAL : public WorkerRunnable
+class LifecycleEventWorkerRunnable MOZ_FINAL : public WorkerRunnable
 {
-  nsMainThreadPtrHandle<nsISupports> mJob;
-  nsCString mScope;
+  nsString mEventName;
+  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
 
 public:
-  InstallEventRunnable(WorkerPrivate* aWorkerPrivate,
-                       const nsMainThreadPtrHandle<nsISupports>& aJob,
-                       const nsCString& aScope)
-      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
-        mJob(aJob),
-        mScope(aScope)
+  LifecycleEventWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+                               const nsString& aEventName,
+                               const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask)
+      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+      , mEventName(aEventName)
+      , mTask(aTask)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aWorkerPrivate);
   }
 
   bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
   {
     MOZ_ASSERT(aWorkerPrivate);
-    return DispatchInstallEvent(aCx, aWorkerPrivate);
+    return DispatchLifecycleEvent(aCx, aWorkerPrivate);
   }
 
 private:
   bool
-  DispatchInstallEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
+  DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
 
 };
 
 class ServiceWorkerUpdateFinishCallback
 {
 protected:
   virtual ~ServiceWorkerUpdateFinishCallback()
   { }
@@ -351,17 +379,17 @@ public:
 
     return true;
   }
 };
 
 class ServiceWorkerRegisterJob MOZ_FINAL : public ServiceWorkerJob,
                                            public nsIStreamLoaderObserver
 {
-  friend class FinishInstallRunnable;
+  friend class ContinueInstallTask;
 
   nsCString mScope;
   nsCString mScriptSpec;
   nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
   nsRefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
 
   ~ServiceWorkerRegisterJob()
   { }
@@ -526,39 +554,38 @@ public:
 
     swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
                                                    WhichServiceWorker::INSTALLING_WORKER);
     mRegistration->mInstallingWorker = new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec);
     mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
 
     Succeed();
 
-    nsRefPtr<QueueFireUpdateFoundRunnable> upr =
-      new QueueFireUpdateFoundRunnable(mRegistration);
+    nsCOMPtr<nsIRunnable> upr =
+      NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm,
+                                                                  &ServiceWorkerManager::FireUpdateFound,
+                                                                  mRegistration);
     NS_DispatchToMainThread(upr);
 
-    // XXXnsm this leads to double fetches right now, ideally we'll be able to
-    // use the persistent cache later.
-    nsRefPtr<ServiceWorkerJob> upcasted = this;
-    nsMainThreadPtrHandle<nsISupports> handle(
-        new nsMainThreadPtrHolder<nsISupports>(upcasted));
+    nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
+        new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
 
     nsRefPtr<ServiceWorker> serviceWorker;
     nsresult rv =
       swm->CreateServiceWorker(mRegistration->mInstallingWorker->ScriptSpec(),
                                mRegistration->mScope,
                                getter_AddRefs(serviceWorker));
 
     if (NS_WARN_IF(NS_FAILED(rv))) {
       ContinueAfterInstallEvent(false /* success */, false /* activate immediately */);
       return;
     }
 
-    nsRefPtr<InstallEventRunnable> r =
-      new InstallEventRunnable(serviceWorker->GetWorkerPrivate(), handle, mRegistration->mScope);
+    nsRefPtr<LifecycleEventWorkerRunnable> r =
+      new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("install"), handle);
 
     AutoJSAPI jsapi;
     jsapi.Init();
     r->Dispatch(jsapi.cx());
   }
 
 private:
   void
@@ -700,16 +727,22 @@ ContinueUpdateRunnable::Run()
 {
   AssertIsOnMainThread();
   nsRefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
   nsRefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
   upjob->ContinueInstall();
   return NS_OK;
 }
 
+void
+ContinueInstallTask::ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately)
+{
+  mJob->ContinueAfterInstallEvent(aSuccess, aActivateImmediately);
+}
+
 // If we return an error code here, the ServiceWorkerContainer will
 // automatically reject the Promise.
 NS_IMETHODIMP
 ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
                                const nsAString& aScope,
                                const nsAString& aScriptURL,
                                nsISupports** aPromise)
 {
@@ -848,82 +881,86 @@ ServiceWorkerManager::Register(nsIDOMWin
   nsRefPtr<ServiceWorkerRegisterJob> job =
     new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb);
   queue->Append(job);
 
   promise.forget(aPromise);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-FinishInstallRunnable::Run()
+/*
+ * Used to handle ExtendableEvent::waitUntil() and proceed with
+ * installation/activation.
+ */
+class LifecycleEventPromiseHandler MOZ_FINAL : public PromiseNativeHandler
 {
-  AssertIsOnMainThread();
-  nsRefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
-  nsRefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
-  MOZ_ASSERT(upjob);
-  upjob->ContinueAfterInstallEvent(mSuccess, mActivateImmediately);
-  return NS_OK;
-}
-
-/*
- * Used to handle InstallEvent::waitUntil() and proceed with installation.
- */
-class FinishInstallHandler MOZ_FINAL : public PromiseNativeHandler
-{
-  nsMainThreadPtrHandle<nsISupports> mJob;
+  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
   bool mActivateImmediately;
 
   virtual
-  ~FinishInstallHandler()
+  ~LifecycleEventPromiseHandler()
   { }
 
 public:
-  FinishInstallHandler(const nsMainThreadPtrHandle<nsISupports>& aJob,
-                       bool aActivateImmediately)
-    : mJob(aJob)
+  LifecycleEventPromiseHandler(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
+                               bool aActivateImmediately)
+    : mTask(aTask)
     , mActivateImmediately(aActivateImmediately)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   void
   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
   {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
     workerPrivate->AssertIsOnWorkerThread();
 
-    nsRefPtr<FinishInstallRunnable> r = new FinishInstallRunnable(mJob, true, mActivateImmediately);
+    nsRefPtr<ContinueLifecycleRunnable> r =
+      new ContinueLifecycleRunnable(mTask, true /* success */, mActivateImmediately);
     NS_DispatchToMainThread(r);
   }
 
   void
   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
   {
-    nsRefPtr<FinishInstallRunnable> r = new FinishInstallRunnable(mJob, false, mActivateImmediately);
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(workerPrivate);
+    workerPrivate->AssertIsOnWorkerThread();
+
+    nsRefPtr<ContinueLifecycleRunnable> r =
+      new ContinueLifecycleRunnable(mTask, false /* success */, mActivateImmediately);
     NS_DispatchToMainThread(r);
   }
 };
 
 bool
-InstallEventRunnable::DispatchInstallEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
-  InstallEventInit init;
-  init.mBubbles = false;
-  init.mCancelable = true;
+
+  nsRefPtr<ExtendableEvent> event;
+  nsRefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
 
-  // FIXME(nsm): Bug 982787 pass previous active worker.
-
-  // FIXME(nsm): Set error handler so we can grab handler errors.
-  nsRefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
-  nsRefPtr<InstallEvent> event =
-    InstallEvent::Constructor(target, NS_LITERAL_STRING("install"), init);
+  if (mEventName.EqualsASCII("install")) {
+    // FIXME(nsm): Bug 982787 pass previous active worker.
+    InstallEventInit init;
+    init.mBubbles = false;
+    init.mCancelable = true;
+    event = InstallEvent::Constructor(target, mEventName, init);
+  } else if (mEventName.EqualsASCII("activate")) {
+    ExtendableEventInit init;
+    init.mBubbles = false;
+    init.mCancelable = true;
+    event = ExtendableEvent::Constructor(target, mEventName, init);
+  } else {
+    MOZ_CRASH("Unexpected lifecycle event");
+  }
 
   event->SetTrusted(true);
 
   nsRefPtr<Promise> waitUntilPromise;
 
   ErrorResult result;
   result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 
@@ -947,145 +984,31 @@ InstallEventRunnable::DispatchInstallEve
     waitUntilPromise = Promise::Reject(sgo, aCx,
                                        JS::UndefinedHandleValue, result);
   }
 
   if (result.Failed()) {
     return false;
   }
 
-  nsRefPtr<FinishInstallHandler> handler =
-    new FinishInstallHandler(mJob, event->ActivateImmediately());
+  // activateimmediately is only relevant to "install" event.
+  bool activateImmediately = false;
+  InstallEvent* installEvent = event->AsInstallEvent();
+  if (installEvent) {
+    activateImmediately = installEvent->ActivateImmediately();
+    // FIXME(nsm): Set activeWorker to the correct thing.
+    // FIXME(nsm): Install error handler for any listener errors.
+  }
+
+  nsRefPtr<LifecycleEventPromiseHandler> handler =
+    new LifecycleEventPromiseHandler(mTask, activateImmediately);
   waitUntilPromise->AppendNativeHandler(handler);
   return true;
 }
 
-class FinishActivationRunnable MOZ_FINAL : public nsRunnable
-{
-  bool mSuccess;
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  FinishActivationRunnable(bool aSuccess,
-                           const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
-    : mSuccess(aSuccess)
-    , mRegistration(aRegistration)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  NS_IMETHODIMP
-  Run()
-  {
-    AssertIsOnMainThread();
-
-    mRegistration->FinishActivate(mSuccess);
-    return NS_OK;
-  }
-};
-
-class FinishActivateHandler MOZ_FINAL : public PromiseNativeHandler
-{
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  explicit FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
-    : mRegistration(aRegistration)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  virtual
-  ~FinishActivateHandler()
-  { }
-
-  void
-  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
-  {
-    nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(true /* success */, mRegistration);
-    NS_DispatchToMainThread(r);
-  }
-
-  void
-  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
-  {
-    nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(false /* success */, mRegistration);
-    NS_DispatchToMainThread(r);
-  }
-};
-
-class ActivateEventRunnable : public WorkerRunnable
-{
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  ActivateEventRunnable(WorkerPrivate* aWorkerPrivate,
-                        const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
-      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
-        mRegistration(aRegistration)
-  {
-    MOZ_ASSERT(aWorkerPrivate);
-  }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-  {
-    MOZ_ASSERT(aWorkerPrivate);
-    return DispatchActivateEvent(aCx, aWorkerPrivate);
-  }
-
-private:
-  bool
-  DispatchActivateEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-  {
-    MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
-    nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
-
-    // FIXME(nsm): Set activeWorker to the correct thing.
-    EventInit init;
-    init.mBubbles = false;
-    init.mCancelable = true;
-    nsRefPtr<ExtendableEvent> event =
-      ExtendableEvent::Constructor(target, NS_LITERAL_STRING("activate"), init);
-
-    event->SetTrusted(true);
-
-    nsRefPtr<Promise> waitUntilPromise;
-
-    // FIXME(nsm): Install error handler for any listener errors.
-    ErrorResult result;
-    result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
-    WidgetEvent* internalEvent = event->GetInternalNSEvent();
-    if (!result.Failed() && !internalEvent->mFlags.mExceptionHasBeenRisen) {
-      waitUntilPromise = event->GetPromise();
-      if (!waitUntilPromise) {
-        nsCOMPtr<nsIGlobalObject> global =
-          do_QueryObject(aWorkerPrivate->GlobalScope());
-        waitUntilPromise =
-          Promise::Resolve(global,
-                           aCx, JS::UndefinedHandleValue, result);
-      }
-    } else {
-      nsCOMPtr<nsIGlobalObject> global =
-        do_QueryObject(aWorkerPrivate->GlobalScope());
-      // Continue with a canceled install.
-      waitUntilPromise = Promise::Reject(global, aCx,
-                                         JS::UndefinedHandleValue, result);
-    }
-
-    if (result.Failed()) {
-      return false;
-    }
-
-    nsRefPtr<FinishActivateHandler> handler = new FinishActivateHandler(mRegistration);
-    waitUntilPromise->AppendNativeHandler(handler);
-    return true;
-  }
-};
-
 void
 ServiceWorkerRegistrationInfo::TryToActivate()
 {
   mWaitingToActivate = true;
   if (!IsControllingDocuments()) {
     Activate();
   }
 }
@@ -1133,21 +1056,21 @@ ServiceWorkerRegistrationInfo::Activate(
     swm->CreateServiceWorker(mActiveWorker->ScriptSpec(),
                              mScope,
                              getter_AddRefs(serviceWorker));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FinishActivate(false /* success */);
     return;
   }
 
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
-    new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(this));
+  nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
+    new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueActivateTask(this)));
 
-  nsRefPtr<ActivateEventRunnable> r =
-    new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
+  nsRefPtr<LifecycleEventWorkerRunnable> r =
+    new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("activate"), handle);
 
   AutoJSAPI jsapi;
   jsapi.Init();
   r->Dispatch(jsapi.cx());
 }
 
 /*
  * Implements the async aspects of the getRegistrations algorithm.
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -457,16 +457,23 @@ private:
   QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
                                              const nsAString& aName);
 
   void
   FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
                                         const nsAString& aName);
 
   void
+  FireUpdateFound(ServiceWorkerRegistrationInfo* aRegistration)
+  {
+    FireEventOnServiceWorkerRegistrations(aRegistration,
+                                          NS_LITERAL_STRING("updatefound"));
+  }
+
+  void
   FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration);
 
   void
   StorePendingReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
 
   void
   CheckPendingReadyPromises();