Backed out 6 changesets (bug 1595964, bug 1596939) for causing failures in browser_application_panel_list-domain-workers.js
authorNoemi Erli <nerli@mozilla.com>
Sat, 07 Dec 2019 20:13:22 +0200
changeset 568102 ae020aef580f046a2e5277b726c3e2d4f50734e1
parent 568101 8a2f3dae304dbf22bf8305dfaaf7db75a8a5aba9
child 568103 df371f905d3afb90b216009a8d4fc4d78ad33ae2
push id12493
push userffxbld-merge
push dateMon, 06 Jan 2020 15:38:57 +0000
treeherdermozilla-beta@63ae456b848d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1595964, 1596939
milestone73.0a1
backs out65c870147654362c1bfa0013726498943636278c
74a982a9144a2891fb46acf98121ea4f81a9c0ee
c21c15689e77367049baa119e6c71c370756266a
a6848f4d219d7ac513295e5421ebafe6509549d6
4f538e6c6dccb2945b9878872efaaec685694137
d1c93f700b8c8788925d1fa60806a46cd5d658e0
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
Backed out 6 changesets (bug 1595964, bug 1596939) for causing failures in browser_application_panel_list-domain-workers.js Backed out changeset 65c870147654 (bug 1595964) Backed out changeset 74a982a9144a (bug 1596939) Backed out changeset c21c15689e77 (bug 1596939) Backed out changeset a6848f4d219d (bug 1596939) Backed out changeset 4f538e6c6dcc (bug 1595964) Backed out changeset d1c93f700b8c (bug 1595964)
devtools/client/debugger/src/client/firefox/events.js
devtools/client/debugger/src/client/firefox/targets.js
devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js
devtools/client/debugger/test/mochitest/examples/service-worker.sjs
devtools/server/actors/root.js
devtools/server/actors/targets/browsing-context.js
devtools/server/actors/targets/content-process.js
devtools/server/actors/worker/service-worker-registration.js
devtools/server/actors/worker/service-worker.js
devtools/server/actors/worker/worker-target-actor-list.js
devtools/shared/fronts/root.js
devtools/shared/fronts/worker/service-worker-registration.js
devtools/shared/specs/targets/content-process.js
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/serviceworkers/ServiceWorkerInfo.cpp
dom/serviceworkers/ServiceWorkerOp.cpp
dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
dom/serviceworkers/ServiceWorkerRegistrationInfo.h
dom/serviceworkers/test/test_devtools_track_serviceworker_time.html
dom/serviceworkers/test/test_serviceworkerregistrationinfo.xhtml
--- a/devtools/client/debugger/src/client/firefox/events.js
+++ b/devtools/client/debugger/src/client/firefox/events.js
@@ -45,22 +45,24 @@ function attachAllTargets(currentTarget:
 }
 
 function setupEvents(dependencies: Dependencies) {
   const { tabTarget, threadFront, debuggerClient } = dependencies;
   actions = dependencies.actions;
   sourceQueue.initialize(actions);
 
   addThreadEventListeners(threadFront);
-  tabTarget.on("workerListChanged", () => threadListChanged());
-  debuggerClient.mainRoot.on("processListChanged", () => threadListChanged());
+  tabTarget.on("workerListChanged", () => threadListChanged("worker"));
+  debuggerClient.mainRoot.on("processListChanged", () =>
+    threadListChanged("contentProcess")
+  );
 
   if (features.windowlessServiceWorkers || attachAllTargets(tabTarget)) {
     const workersListener = new WorkersListener(debuggerClient.mainRoot);
-    workersListener.addListener(() => threadListChanged());
+    workersListener.addListener(() => threadListChanged("worker"));
   }
 }
 
 async function paused(threadFront: ThreadFront, packet: PausedPacket) {
   // When reloading we might get pauses from threads before they have been
   // added to the store. Ensure the pause won't be processed until we've
   // finished adding the thread.
   await actions.ensureHasThread(threadFront.actor);
@@ -107,18 +109,18 @@ function resumed(threadFront: ThreadFron
 
 function newSource(threadFront: ThreadFront, { source }: SourcePacket) {
   sourceQueue.queue({
     type: "generated",
     data: prepareSourcePayload(threadFront, source),
   });
 }
 
-function threadListChanged() {
-  actions.updateThreads();
+function threadListChanged(type) {
+  actions.updateThreads(type);
 }
 
 function replayFramePositions(
   threadFront: ThreadFront,
   { positions, frame, thread }: Object
 ) {
   actions.setFramePositions(positions, frame, thread);
 }
--- a/devtools/client/debugger/src/client/firefox/targets.js
+++ b/devtools/client/debugger/src/client/firefox/targets.js
@@ -85,88 +85,67 @@ async function listWorkerTargets(args: A
 
     const {
       registrations,
     } = await debuggerClient.mainRoot.listServiceWorkerRegistrations();
     serviceWorkerRegistrations = registrations;
   } else {
     workers = (await currentTarget.listWorkers()).workers;
     if (currentTarget.url && features.windowlessServiceWorkers) {
-      allWorkers = await debuggerClient.mainRoot.listAllWorkerTargets();
       const {
         registrations,
       } = await debuggerClient.mainRoot.listServiceWorkerRegistrations();
       serviceWorkerRegistrations = registrations.filter(front =>
         sameOrigin(front.url, currentTarget.url)
       );
     }
   }
 
   for (const front of serviceWorkerRegistrations) {
-    const {
-      activeWorker,
-      waitingWorker,
-      installingWorker,
-      evaluatingWorker,
-    } = front;
+    const { activeWorker, waitingWorker, installingWorker } = front;
     await maybeMarkServiceWorker(activeWorker, "active");
     await maybeMarkServiceWorker(waitingWorker, "waiting");
     await maybeMarkServiceWorker(installingWorker, "installing");
-    await maybeMarkServiceWorker(evaluatingWorker, "evaluating");
   }
 
   async function maybeMarkServiceWorker(info, status) {
     if (!info) {
       return;
     }
 
+    if (!allWorkers) {
+      allWorkers = await debuggerClient.mainRoot.listAllWorkerTargets();
+    }
     const worker = allWorkers.find(front => front && front.id == info.id);
     if (!worker) {
       return;
     }
 
     worker.debuggerServiceWorkerStatus = status;
     if (!workers.includes(worker)) {
       workers.push(worker);
     }
   }
 
   return workers;
 }
 
-async function getAllProcessTargets(args) {
-  const { debuggerClient } = args;
+async function listProcessTargets(args: Args) {
+  const { currentTarget, debuggerClient } = args;
+  if (!attachAllTargets(currentTarget)) {
+    return [];
+  }
+
   const { processes } = await debuggerClient.mainRoot.listProcesses();
-  return Promise.all(
+  const targets = await Promise.all(
     processes
       .filter(descriptor => !descriptor.isParent)
       .map(descriptor => descriptor.getTarget())
   );
-}
 
-async function listProcessTargets(args: Args) {
-  const { currentTarget } = args;
-  if (!attachAllTargets(currentTarget)) {
-    if (currentTarget.url && features.windowlessServiceWorkers) {
-      // Service workers associated with our target's origin need to pause until
-      // we attach, regardless of which process they are running in.
-      const origin = new URL(currentTarget.url).origin;
-      const targets = await getAllProcessTargets(args);
-      try {
-        await Promise.all(
-          targets.map(t => t.pauseMatchingServiceWorkers({ origin }))
-        );
-      } catch (e) {
-        // Old servers without pauseMatchingServiceWorkers will throw.
-        // @backward-compatibility: remove in Firefox 75
-      }
-    }
-    return [];
-  }
-
-  return getAllProcessTargets(args);
+  return targets;
 }
 
 export async function updateTargets(args: Args) {
   const workers = await listWorkerTargets(args);
   const processes = await listProcessTargets(args);
   await attachTargets([...workers, ...processes], args);
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js
@@ -2,24 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 async function checkWorkerThreads(dbg, count) {
   await waitUntil(() => dbg.selectors.getThreads().length == count);
   ok(true, `Have ${count} threads`);
 }
 
-async function checkWorkerStatus(dbg, status) {
-  await waitUntil(() => {
-    const threads = dbg.selectors.getThreads();
-    return threads.some(t => t.serviceWorkerStatus == status);
-  });
-  ok(true, `Have thread with status ${status}`);
-}
-
 // Test that we can detect a new service worker and hit breakpoints that we've
 // set in it.
 add_task(async function() {
   info("Subtest #1");
 
   await pushPref("devtools.debugger.features.windowless-service-workers", true);
   await pushPref("devtools.debugger.workers-visible", true);
   await pushPref("dom.serviceWorkers.enabled", true);
@@ -34,19 +26,18 @@ add_task(async function() {
 
   await addBreakpoint(dbg, "service-worker.sjs", 13);
 
   invokeInTab("fetchFromWorker");
 
   await waitForPaused(dbg);
   assertPausedAtSourceAndLine(dbg, workerSource.id, 13);
 
-  // Leave the breakpoint and worker in place for the next subtest.
+  // Leave the breakpoint in place for the next subtest.
   await resume(dbg);
-  await waitForRequestsToSettle(dbg);
   await removeTab(gBrowser.selectedTab);
 });
 
 // Test that breakpoints can be immediately hit in service workers when reloading.
 add_task(async function() {
   info("Subtest #2");
 
   const toolbox = await openNewTabAndToolbox(EXAMPLE_URL + "doc-service-workers.html", "jsdebugger");
@@ -65,30 +56,28 @@ add_task(async function() {
   await checkWorkerThreads(dbg, 1);
 
   await resume(dbg);
   await dbg.actions.removeAllBreakpoints(getContext(dbg));
 
   invokeInTab("unregisterWorker");
 
   await checkWorkerThreads(dbg, 0);
-  await waitForRequestsToSettle(dbg);
   await removeTab(gBrowser.selectedTab);
 });
 
 // Test having a waiting and active service worker for the same registration.
 add_task(async function() {
   info("Subtest #3");
 
   const toolbox = await openNewTabAndToolbox(EXAMPLE_URL + "doc-service-workers.html", "jsdebugger");
   const dbg = createDebuggerContext(toolbox);
 
   invokeInTab("registerWorker");
   await checkWorkerThreads(dbg, 1);
-  await checkWorkerStatus(dbg, "active");
 
   const firstTab = gBrowser.selectedTab;
 
   await addTab(EXAMPLE_URL + "service-worker.sjs?setStatus=newServiceWorker");
   await removeTab(gBrowser.selectedTab);
 
   const secondTab = await addTab(EXAMPLE_URL + "doc-service-workers.html");
 
@@ -107,60 +96,18 @@ add_task(async function() {
 
   await selectSource(dbg, sources[1]);
   await waitForLoadedSource(dbg, sources[1]);
   const content1 = findSourceContent(dbg, sources[1]);
 
   ok(content0.value.includes("newServiceWorker") != content1.value.includes("newServiceWorker"),
      "Got two different sources for service worker");
 
-  // Add a breakpoint for the next subtest.
-  await addBreakpoint(dbg, "service-worker.sjs", 2);
-
   invokeInTab("unregisterWorker");
 
   await checkWorkerThreads(dbg, 0);
-  await waitForRequestsToSettle(dbg);
   await removeTab(firstTab);
   await removeTab(secondTab);
 
   // Reset the SJS in case we will be repeating the test.
   await addTab(EXAMPLE_URL + "service-worker.sjs?setStatus=");
   await removeTab(gBrowser.selectedTab);
 });
-
-// Test setting breakpoints while the service worker is starting up.
-add_task(async function() {
-  info("Subtest #4");
-
-  const toolbox = await openNewTabAndToolbox(EXAMPLE_URL + "doc-service-workers.html", "jsdebugger");
-  const dbg = createDebuggerContext(toolbox);
-
-  invokeInTab("registerWorker");
-  await checkWorkerThreads(dbg, 1);
-
-  await waitForSource(dbg, "service-worker.sjs");
-  const workerSource = findSource(dbg, "service-worker.sjs");
-
-  await waitForBreakpointCount(dbg, 1);
-  await waitForPaused(dbg);
-  assertPausedAtSourceAndLine(dbg, workerSource.id, 2);
-  await checkWorkerStatus(dbg, "evaluating");
-
-  await addBreakpoint(dbg, "service-worker.sjs", 19);
-  await resume(dbg);
-  await waitForPaused(dbg);
-  assertPausedAtSourceAndLine(dbg, workerSource.id, 19);
-  await checkWorkerStatus(dbg, "installing");
-
-  await addBreakpoint(dbg, "service-worker.sjs", 5);
-  await resume(dbg);
-  await waitForPaused(dbg);
-  assertPausedAtSourceAndLine(dbg, workerSource.id, 5);
-  await checkWorkerStatus(dbg, "active");
-
-  await resume(dbg);
-  invokeInTab("unregisterWorker");
-
-  await checkWorkerThreads(dbg, 0);
-  await waitForRequestsToSettle(dbg);
-  await removeTab(gBrowser.selectedTab);
-});
--- a/devtools/client/debugger/test/mochitest/examples/service-worker.sjs
+++ b/devtools/client/debugger/test/mochitest/examples/service-worker.sjs
@@ -14,25 +14,33 @@ self.addEventListener("activate", event 
 self.addEventListener("fetch", event => {
   const url = event.request.url;
   dump("Fetch: " + url + "\\n");
   if (url.includes("whatever")) {
     const response = new Response("Service worker response STATUS", { statusText: "OK" });
     event.respondWith(response);
   }
 });
-
-self.addEventListener("install", event => {
-  dump("Install\\n");
-});
 `;
 
 function handleRequest(request, response) {
   response.setHeader("Content-Type", "text/javascript");
 
   const arr = /setStatus=(.*)/.exec(request.queryString);
   if (arr) {
     setState("status", arr[1]);
   }
 
   const status = getState("status");
-  response.write(body.replace("STATUS", status));
+
+  let newBody = body.replace("STATUS", status);
+
+  if (status == "stuckInstall") {
+newBody += `
+self.addEventListener("install", event => {
+  dump("Install\\n");
+  event.waitUntil(new Promise(resolve => {}));
+});
+`;
+  }
+
+  response.write(newBody);
 }
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -189,17 +189,17 @@ RootActor.prototype = {
     /* Tell the live lists we aren't watching any more. */
     if (this._parameters.tabList) {
       this._parameters.tabList.destroy();
     }
     if (this._parameters.addonList) {
       this._parameters.addonList.onListChanged = null;
     }
     if (this._parameters.workerList) {
-      this._parameters.workerList.destroy();
+      this._parameters.workerList.onListChanged = null;
     }
     if (this._parameters.serviceWorkerRegistrationList) {
       this._parameters.serviceWorkerRegistrationList.onListChanged = null;
     }
     if (this._parameters.processList) {
       this._parameters.processList.onListChanged = null;
     }
     if (typeof this._parameters.onShutdown === "function") {
--- a/devtools/server/actors/targets/browsing-context.js
+++ b/devtools/server/actors/targets/browsing-context.js
@@ -679,19 +679,17 @@ const browsingContextTargetPrototype = {
         type: Ci.nsIWorkerDebugger.TYPE_DEDICATED,
         window: this.window,
       });
     }
     return this._workerTargetActorList;
   },
 
   pauseWorkersUntilAttach(shouldPause) {
-    this.ensureWorkerTargetActorList().workerPauser.setPauseMatching(
-      shouldPause
-    );
+    this.ensureWorkerTargetActorList().setPauseMatchingWorkers(shouldPause);
   },
 
   listWorkers(request) {
     if (!this.attached) {
       return { error: "wrongState" };
     }
 
     return this.ensureWorkerTargetActorList()
@@ -957,17 +955,18 @@ const browsingContextTargetPrototype = {
     this._styleSheetActors.clear();
     if (this._targetScopedActorPool) {
       this._targetScopedActorPool.destroy();
       this._targetScopedActorPool = null;
     }
 
     // Make sure that no more workerListChanged notifications are sent.
     if (this._workerTargetActorList !== null) {
-      this._workerTargetActorList.destroy();
+      this._workerTargetActorList.onListChanged = null;
+      this._workerTargetActorList.setPauseMatchingWorkers(false);
       this._workerTargetActorList = null;
     }
 
     if (this._workerTargetActorPool !== null) {
       this._workerTargetActorPool.destroy();
       this._workerTargetActorPool = null;
     }
 
--- a/devtools/server/actors/targets/content-process.js
+++ b/devtools/server/actors/targets/content-process.js
@@ -134,64 +134,53 @@ const ContentProcessTargetActor = ActorC
       memoryActor: this.memoryActor.actorID,
 
       traits: {
         networkMonitor: false,
       },
     };
   },
 
-  ensureWorkerList() {
+  listWorkers: function() {
     if (!this._workerList) {
       this._workerList = new WorkerTargetActorList(this.conn, {});
     }
-    return this._workerList;
-  },
-
-  listWorkers: function() {
-    return this.ensureWorkerList()
-      .getList()
-      .then(actors => {
-        const pool = new Pool(this.conn);
-        for (const actor of actors) {
-          pool.manage(actor);
-        }
+    return this._workerList.getList().then(actors => {
+      const pool = new Pool(this.conn);
+      for (const actor of actors) {
+        pool.manage(actor);
+      }
 
-        // Do not destroy the pool before transfering ownership to the newly created
-        // pool, so that we do not accidentally destroy actors that are still in use.
-        if (this._workerTargetActorPool) {
-          this._workerTargetActorPool.destroy();
-        }
+      // Do not destroy the pool before transfering ownership to the newly created
+      // pool, so that we do not accidentally destroy actors that are still in use.
+      if (this._workerTargetActorPool) {
+        this._workerTargetActorPool.destroy();
+      }
 
-        this._workerTargetActorPool = pool;
-        this._workerList.onListChanged = this._onWorkerListChanged;
+      this._workerTargetActorPool = pool;
+      this._workerList.onListChanged = this._onWorkerListChanged;
 
-        return {
-          from: this.actorID,
-          workers: actors,
-        };
-      });
+      return {
+        from: this.actorID,
+        workers: actors,
+      };
+    });
   },
 
   _onWorkerListChanged: function() {
     this.conn.send({ from: this.actorID, type: "workerListChanged" });
     this._workerList.onListChanged = null;
   },
 
-  pauseMatchingServiceWorkers(request) {
-    this.ensureWorkerList().workerPauser.setPauseServiceWorkers(request.origin);
-  },
-
   destroy: function() {
     Actor.prototype.destroy.call(this);
 
     // Tell the live lists we aren't watching any more.
     if (this._workerList) {
-      this._workerList.destroy();
-      this._workerList = null;
+      this._workerList.onListChanged = null;
     }
 
     if (this._sources) {
       this._sources.destroy();
       this._sources = null;
     }
 
     if (this._dbg) {
--- a/devtools/server/actors/worker/service-worker-registration.js
+++ b/devtools/server/actors/worker/service-worker-registration.js
@@ -66,33 +66,30 @@ const ServiceWorkerRegistrationActor = p
     onChange() {
       this._destroyServiceWorkerActors();
       this._createServiceWorkerActors();
       this.emit("registration-changed");
     },
 
     form() {
       const registration = this._registration;
-      const evaluatingWorker = this._evaluatingWorker.form();
       const installingWorker = this._installingWorker.form();
       const waitingWorker = this._waitingWorker.form();
       const activeWorker = this._activeWorker.form();
 
-      const newestWorker =
-        activeWorker || waitingWorker || installingWorker || evaluatingWorker;
+      const newestWorker = activeWorker || waitingWorker || installingWorker;
 
       const isParentInterceptEnabled = swm.isParentInterceptEnabled();
       const isMultiE10sWithOldImplementation =
         Services.appinfo.browserTabsRemoteAutostart &&
         !isParentInterceptEnabled;
       return {
         actor: this.actorID,
         scope: registration.scope,
         url: registration.scriptSpec,
-        evaluatingWorker,
         installingWorker,
         waitingWorker,
         activeWorker,
         fetch: newestWorker && newestWorker.fetch,
         // - In old multi e10s: only active registrations are available.
         // - In non-e10s or new implementaion: check if we have an active worker
         active: isMultiE10sWithOldImplementation ? true : !!activeWorker,
         lastUpdateTime: registration.lastUpdateTime,
@@ -119,17 +116,16 @@ const ServiceWorkerRegistrationActor = p
       this._registration = null;
       if (this._pushSubscriptionActor) {
         this._pushSubscriptionActor.destroy();
       }
       this._pushSubscriptionActor = null;
 
       this._destroyServiceWorkerActors();
 
-      this._evaluatingWorker = null;
       this._installingWorker = null;
       this._waitingWorker = null;
       this._activeWorker = null;
     },
 
     /**
      * Standard observer interface to listen to push messages and changes.
      */
@@ -296,44 +292,37 @@ const ServiceWorkerRegistrationActor = p
             this._pushSubscriptionActor = pushSubscriptionActor;
             resolve(pushSubscriptionActor);
           }
         );
       });
     },
 
     _destroyServiceWorkerActors() {
-      this._evaluatingWorker.destroy();
       this._installingWorker.destroy();
       this._waitingWorker.destroy();
       this._activeWorker.destroy();
     },
 
     _createServiceWorkerActors() {
       const {
-        evaluatingWorker,
         installingWorker,
         waitingWorker,
         activeWorker,
       } = this._registration;
 
-      this._evaluatingWorker = new ServiceWorkerActor(
-        this._conn,
-        evaluatingWorker
-      );
       this._installingWorker = new ServiceWorkerActor(
         this._conn,
         installingWorker
       );
       this._waitingWorker = new ServiceWorkerActor(this._conn, waitingWorker);
       this._activeWorker = new ServiceWorkerActor(this._conn, activeWorker);
 
       // Add the ServiceWorker actors as children of this ServiceWorkerRegistration actor,
       // assigning them valid actorIDs.
-      this.manage(this._evaluatingWorker);
       this.manage(this._installingWorker);
       this.manage(this._waitingWorker);
       this.manage(this._activeWorker);
     },
   }
 );
 
 exports.ServiceWorkerRegistrationActor = ServiceWorkerRegistrationActor;
--- a/devtools/server/actors/worker/service-worker.js
+++ b/devtools/server/actors/worker/service-worker.js
@@ -1,42 +1,35 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { Ci } = require("chrome");
 const protocol = require("devtools/shared/protocol");
 const {
   serviceWorkerSpec,
 } = require("devtools/shared/specs/worker/service-worker");
 
 const ServiceWorkerActor = protocol.ActorClassWithSpec(serviceWorkerSpec, {
   initialize(conn, worker) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this._worker = worker;
   },
 
   form() {
     if (!this._worker) {
       return null;
     }
 
-    // handlesFetchEvents is not available if the worker's main script is in the
-    // evaluating state.
-    const isEvaluating =
-      this._worker.state == Ci.nsIServiceWorkerInfo.STATE_PARSED;
-    const fetch = isEvaluating ? undefined : this._worker.handlesFetchEvents;
-
     return {
       actor: this.actorID,
       url: this._worker.scriptSpec,
       state: this._worker.state,
-      fetch,
+      fetch: this._worker.handlesFetchEvents,
       id: this._worker.id,
     };
   },
 
   destroy() {
     protocol.Actor.prototype.destroy.call(this);
     this._worker = null;
   },
--- a/devtools/server/actors/worker/worker-target-actor-list.js
+++ b/devtools/server/actors/worker/worker-target-actor-list.js
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { Ci } = require("chrome");
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 loader.lazyRequireGetter(
   this,
   "WorkerTargetActor",
   "devtools/server/actors/targets/worker",
   true
 );
 
@@ -33,97 +32,56 @@ function matchWorkerDebugger(dbg, option
     if (window !== options.window) {
       return false;
     }
   }
 
   return true;
 }
 
-function matchServiceWorker(dbg, origin) {
-  return (
-    dbg.type == Ci.nsIWorkerDebugger.TYPE_SERVICE &&
-    new URL(dbg.url).origin == origin
-  );
-}
-
 // When a new worker appears, in some cases (i.e. the debugger is running) we
 // want it to pause during registration until a later time (i.e. the debugger
 // finishes attaching to the worker). This is an optional WorkderDebuggerManager
 // listener that can be installed in addition to the WorkerTargetActorList
-// listener. It always listens to new workers and pauses any matching filters
-// which have been set on it.
-//
-// Two kinds of filters are supported:
-//
-// setPauseMatching(true) will pause all workers which match the options strcut
-// passed in on creation.
-//
-// setPauseServiceWorkers(origin) will pause all service workers which have the
-// specified origin.
-//
-// FIXME Bug 1601279 separate WorkerPauser from WorkerTargetActorList and give
-// it a more consistent interface.
-function WorkerPauser(options) {
+// listener. It always listens to new workers and pauses any which are matched
+// by the WorkerTargetActorList.
+function PauseMatchingWorkers(options) {
   this._options = options;
-  this._pauseMatching = null;
-  this._pauseServiceWorkerOrigin = null;
-
   this.onRegister = this._onRegister.bind(this);
   this.onUnregister = () => {};
 
   wdm.addListener(this);
 }
 
-WorkerPauser.prototype = {
+PauseMatchingWorkers.prototype = {
   destroy() {
     wdm.removeListener(this);
   },
 
   _onRegister(dbg) {
-    if (
-      (this._pauseMatching && matchWorkerDebugger(dbg, this._options)) ||
-      (this._pauseServiceWorkerOrigin &&
-        matchServiceWorker(dbg, this._pauseServiceWorkerOrigin))
-    ) {
+    if (matchWorkerDebugger(dbg, this._options)) {
       // Prevent the debuggee from executing in this worker until the debugger
       // has finished attaching to it.
       dbg.setDebuggerReady(false);
     }
   },
-
-  setPauseMatching(shouldPause) {
-    this._pauseMatching = shouldPause;
-  },
-
-  setPauseServiceWorkers(origin) {
-    this._pauseServiceWorkerOrigin = origin;
-  },
 };
 
 function WorkerTargetActorList(conn, options) {
   this._conn = conn;
   this._options = options;
   this._actors = new Map();
   this._onListChanged = null;
-  this._workerPauser = null;
+  this._pauseMatchingWorkers = null;
   this._mustNotify = false;
   this.onRegister = this.onRegister.bind(this);
   this.onUnregister = this.onUnregister.bind(this);
 }
 
 WorkerTargetActorList.prototype = {
-  destroy() {
-    this.onListChanged = null;
-    if (this._workerPauser) {
-      this._workerPauser.destroy();
-      this._workerPauser = null;
-    }
-  },
-
   getList() {
     // Create a set of debuggers.
     const dbgs = new Set();
     for (const dbg of wdm.getWorkerDebuggerEnumerator()) {
       if (matchWorkerDebugger(dbg, this._options)) {
         dbgs.add(dbg);
       }
     }
@@ -196,17 +154,21 @@ WorkerTargetActorList.prototype = {
   },
 
   onUnregister(dbg) {
     if (matchWorkerDebugger(dbg, this._options)) {
       this._notifyListChanged();
     }
   },
 
-  get workerPauser() {
-    if (!this._workerPauser) {
-      this._workerPauser = new WorkerPauser(this._options);
+  setPauseMatchingWorkers(shouldPause) {
+    if (shouldPause != !!this._pauseMatchingWorkers) {
+      if (shouldPause) {
+        this._pauseMatchingWorkers = new PauseMatchingWorkers(this._options);
+      } else {
+        this._pauseMatchingWorkers.destroy();
+        this._pauseMatchingWorkers = null;
+      }
     }
-    return this._workerPauser;
   },
 };
 
 exports.WorkerTargetActorList = WorkerTargetActorList;
--- a/devtools/shared/fronts/root.js
+++ b/devtools/shared/fronts/root.js
@@ -101,24 +101,18 @@ class RootFront extends FrontClassWithSp
 
     const result = {
       service: [],
       shared: [],
       other: [],
     };
 
     registrations.forEach(front => {
-      const {
-        activeWorker,
-        waitingWorker,
-        installingWorker,
-        evaluatingWorker,
-      } = front;
-      const newestWorker =
-        activeWorker || waitingWorker || installingWorker || evaluatingWorker;
+      const { activeWorker, waitingWorker, installingWorker } = front;
+      const newestWorker = activeWorker || waitingWorker || installingWorker;
 
       // All the information is simply mirrored from the registration front.
       // However since registering workers will fetch similar information from the worker
       // target front and will not have a service worker registration front, consumers
       // should not read meta data directly on the registration front instance.
       result.service.push({
         active: front.active,
         fetch: front.fetch,
@@ -166,20 +160,18 @@ class RootFront extends FrontClassWithSp
             if (!r.newestWorkerId || !isParentInterceptEnabled) {
               return r.scope === front.scope;
             }
 
             return r.newestWorkerId === front.id;
           });
 
           if (registration) {
-            // Before bug 1595964, URLs were not available for registrations
-            // whose worker's main script is being evaluated. Now, URLs are
-            // always available, and this test deals with older servers.
-            // @backward-compatibility: remove in Firefox 75
+            // XXX: Race, sometimes a ServiceWorkerRegistrationInfo doesn't
+            // have a scriptSpec, but its associated WorkerDebugger does.
             if (!registration.url) {
               registration.name = registration.url = front.url;
             }
             registration.workerTargetFront = front;
           } else {
             // If we are missing the registration, augment the worker front with
             // fields expected on service worker registration fronts so that it
             // can be displayed in UIs handling on service worker registrations.
--- a/devtools/shared/fronts/worker/service-worker-registration.js
+++ b/devtools/shared/fronts/worker/service-worker-registration.js
@@ -38,20 +38,16 @@ class ServiceWorkerRegistrationFront ext
   get type() {
     return this._form.type;
   }
 
   get url() {
     return this._form.url;
   }
 
-  get evaluatingWorker() {
-    return this._getServiceWorker("evaluatingWorker");
-  }
-
   get activeWorker() {
     return this._getServiceWorker("activeWorker");
   }
 
   get installingWorker() {
     return this._getServiceWorker("installingWorker");
   }
 
--- a/devtools/shared/specs/targets/content-process.js
+++ b/devtools/shared/specs/targets/content-process.js
@@ -18,23 +18,16 @@ types.addDictType("contentProcessTarget.
 const contentProcessTargetSpec = generateActorSpec({
   typeName: "contentProcessTarget",
 
   methods: {
     listWorkers: {
       request: {},
       response: RetVal("contentProcessTarget.workers"),
     },
-
-    pauseMatchingServiceWorkers: {
-      request: {
-        origin: Option(0, "string"),
-      },
-      response: {},
-    },
   },
 
   events: {
     workerListChanged: {
       type: "workerListChanged",
     },
 
     // The thread actor is no longer emitting newSource event in the name of the target
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -53,19 +53,16 @@ interface nsIServiceWorkerInfo : nsISupp
 
   readonly attribute AString scriptSpec;
   readonly attribute AString cacheName;
 
   readonly attribute unsigned short state;
 
   readonly attribute nsIWorkerDebugger debugger;
 
-  // Return whether the ServiceWorker has a "fetch" event listener. Throws if
-  // this is unknown because the worker's main script hasn't finished executing
-  // (when exposed as evaluatingWorker).
   readonly attribute bool handlesFetchEvents;
 
   readonly attribute PRTime installedTime;
   readonly attribute PRTime activatedTime;
   readonly attribute PRTime redundantTime;
 
   void attachDebugger();
 
@@ -89,17 +86,16 @@ interface nsIServiceWorkerRegistrationIn
   readonly attribute nsIPrincipal principal;
 
   readonly attribute AString scope;
   readonly attribute AString scriptSpec;
   readonly attribute unsigned short updateViaCache;
 
   readonly attribute PRTime lastUpdateTime;
 
-  readonly attribute nsIServiceWorkerInfo evaluatingWorker;
   readonly attribute nsIServiceWorkerInfo installingWorker;
   readonly attribute nsIServiceWorkerInfo waitingWorker;
   readonly attribute nsIServiceWorkerInfo activeWorker;
 
   // Allows to get the related nsIServiceWorkerInfo for a given
   // nsIWorkerDebugger. Over time we shouldn't need this anymore,
   // and instead always control then nsIWorkerDebugger from
   // nsIServiceWorkerInfo and not the other way around.  Returns
--- a/dom/serviceworkers/ServiceWorkerInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerInfo.cpp
@@ -86,21 +86,16 @@ ServiceWorkerInfo::GetDebugger(nsIWorker
 
   return mServiceWorkerPrivate->GetDebugger(aResult);
 }
 
 NS_IMETHODIMP
 ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue) {
   MOZ_ASSERT(aValue);
   MOZ_ASSERT(NS_IsMainThread());
-
-  if (mHandlesFetch == Unknown) {
-    return NS_ERROR_FAILURE;
-  }
-
   *aValue = HandlesFetch();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerInfo::GetInstalledTime(PRTime* _retval) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(_retval);
--- a/dom/serviceworkers/ServiceWorkerOp.cpp
+++ b/dom/serviceworkers/ServiceWorkerOp.cpp
@@ -247,24 +247,23 @@ nsresult DispatchExtendableEventOnWorker
 }
 
 bool DispatchFailed(nsresult aStatus) {
   return NS_FAILED(aStatus) && aStatus != NS_ERROR_XPC_JS_THREW_EXCEPTION;
 }
 
 }  // anonymous namespace
 
-class ServiceWorkerOp::ServiceWorkerOpRunnable : public WorkerDebuggeeRunnable {
+class ServiceWorkerOp::ServiceWorkerOpRunnable : public WorkerRunnable {
  public:
   NS_DECL_ISUPPORTS_INHERITED
 
   ServiceWorkerOpRunnable(RefPtr<ServiceWorkerOp> aOwner,
                           WorkerPrivate* aWorkerPrivate)
-      : WorkerDebuggeeRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
-        mOwner(std::move(aOwner)) {
+      : WorkerRunnable(aWorkerPrivate), mOwner(std::move(aOwner)) {
     AssertIsOnMainThread();
     MOZ_ASSERT(mOwner);
     MOZ_ASSERT(aWorkerPrivate);
   }
 
  private:
   ~ServiceWorkerOpRunnable() = default;
 
--- a/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
@@ -165,17 +165,17 @@ ServiceWorkerRegistrationInfo::GetScope(
   MOZ_ASSERT(NS_IsMainThread());
   CopyUTF8toUTF16(Scope(), aScope);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetScriptSpec(nsAString& aScriptSpec) {
   MOZ_ASSERT(NS_IsMainThread());
-  RefPtr<ServiceWorkerInfo> newest = NewestIncludingEvaluating();
+  RefPtr<ServiceWorkerInfo> newest = Newest();
   if (newest) {
     CopyUTF8toUTF16(newest->ScriptSpec(), aScriptSpec);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetUpdateViaCache(uint16_t* aUpdateViaCache) {
@@ -187,25 +187,16 @@ NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetLastUpdateTime(PRTime* _retval) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(_retval);
   *_retval = mLastUpdateTime;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-ServiceWorkerRegistrationInfo::GetEvaluatingWorker(
-    nsIServiceWorkerInfo** aResult) {
-  MOZ_ASSERT(NS_IsMainThread());
-  RefPtr<ServiceWorkerInfo> info = mEvaluatingWorker;
-  info.forget(aResult);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 ServiceWorkerRegistrationInfo::GetInstallingWorker(
     nsIServiceWorkerInfo** aResult) {
   MOZ_ASSERT(NS_IsMainThread());
   RefPtr<ServiceWorkerInfo> info = mInstallingWorker;
   info.forget(aResult);
   return NS_OK;
 }
 
@@ -534,37 +525,29 @@ void ServiceWorkerRegistrationInfo::SetE
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aServiceWorker);
   MOZ_ASSERT(!mEvaluatingWorker);
   MOZ_ASSERT(!mInstallingWorker);
   MOZ_ASSERT(mWaitingWorker != aServiceWorker);
   MOZ_ASSERT(mActiveWorker != aServiceWorker);
 
   mEvaluatingWorker = aServiceWorker;
-
-  // We don't call UpdateRegistrationState() here because the evaluating worker
-  // is currently not exposed to content on the registration, so calling it here
-  // would produce redundant IPC traffic.
-  NotifyChromeRegistrationListeners();
 }
 
 void ServiceWorkerRegistrationInfo::ClearEvaluating() {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mEvaluatingWorker) {
     return;
   }
 
   mEvaluatingWorker->UpdateState(ServiceWorkerState::Redundant);
   // We don't update the redundant time for the sw here, since we've not expose
   // evalutingWorker yet.
   mEvaluatingWorker = nullptr;
-
-  // As for SetEvaluating, UpdateRegistrationState() does not need to be called.
-  NotifyChromeRegistrationListeners();
 }
 
 void ServiceWorkerRegistrationInfo::ClearInstalling() {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mInstallingWorker) {
     return;
   }
--- a/dom/serviceworkers/ServiceWorkerRegistrationInfo.h
+++ b/dom/serviceworkers/ServiceWorkerRegistrationInfo.h
@@ -99,24 +99,16 @@ class ServiceWorkerRegistrationInfo fina
       newest = mWaitingWorker;
     } else {
       newest = mActiveWorker;
     }
 
     return newest.forget();
   }
 
-  already_AddRefed<ServiceWorkerInfo> NewestIncludingEvaluating() const {
-    if (mEvaluatingWorker) {
-      RefPtr<ServiceWorkerInfo> newest = mEvaluatingWorker;
-      return newest.forget();
-    }
-    return Newest();
-  }
-
   already_AddRefed<ServiceWorkerInfo> GetServiceWorkerInfoById(uint64_t aId);
 
   void StartControllingClient() {
     ++mControlledClientsCounter;
     mDelayMultiplier = 0;
   }
 
   void StopControllingClient() {
--- a/dom/serviceworkers/test/test_devtools_track_serviceworker_time.html
+++ b/dom/serviceworkers/test/test_devtools_track_serviceworker_time.html
@@ -6,17 +6,16 @@
 </head>
 <iframe id="iframe"></iframe>
 <body>
 
 <script type="text/javascript">
 
 const State = {
   BYTECHECK: -1,
-  PARSED: Ci.nsIServiceWorkerInfo.STATE_PARSED,
   INSTALLING: Ci.nsIServiceWorkerInfo.STATE_INSTALLING,
   INSTALLED: Ci.nsIServiceWorkerInfo.STATE_INSTALLED,
   ACTIVATING: Ci.nsIServiceWorkerInfo.STATE_ACTIVATING,
   ACTIVATED: Ci.nsIServiceWorkerInfo.STATE_ACTIVATED,
   REDUNDANT: Ci.nsIServiceWorkerInfo.STATE_REDUNDANT
 };
 let swm = Cc["@mozilla.org/serviceworkers/manager;1"].
           getService(Ci.nsIServiceWorkerManager);
@@ -32,20 +31,16 @@ let astrayServiceWorkerInfo = null;
 let expectedResults = [
   {
     // Speacial state for verifying update since we will do the byte-check
     // first.
     state: State.BYTECHECK, installedTimeRecorded: false,
     activatedTimeRecorded: false, redundantTimeRecorded: false
   },
   {
-    state: State.PARSED, installedTimeRecorded: false,
-    activatedTimeRecorded: false, redundantTimeRecorded: false
-  },
-  {
     state: State.INSTALLING, installedTimeRecorded: false,
     activatedTimeRecorded: false, redundantTimeRecorded: false
   },
   {
     state: State.INSTALLED, installedTimeRecorded: true,
     activatedTimeRecorded: false, redundantTimeRecorded: false
   },
   {
@@ -113,18 +108,17 @@ function register() {
 
 function verifyServiceWorkTime(aSWRInfo, resolve) {
   let expectedResult = expectedResults.shift();
   ok(!!expectedResult, "We should be able to get test from expectedResults");
 
   info("Check the ServiceWorker time in its state is " + expectedResult.state);
 
   // Get serviceWorkerInfo from swrInfo or get the astray one which we hold.
-  let swInfo = aSWRInfo.evaluatingWorker ||
-               aSWRInfo.installingWorker ||
+  let swInfo = aSWRInfo.installingWorker ||
                aSWRInfo.waitingWorker ||
                aSWRInfo.activeWorker ||
                astrayServiceWorkerInfo;
 
   ok(!!aSWRInfo.lastUpdateTime,
      "We should do the byte-check and update the update timeStamp");
 
   if (!swInfo) {
--- a/dom/serviceworkers/test/test_serviceworkerregistrationinfo.xhtml
+++ b/dom/serviceworkers/test/test_serviceworkerregistrationinfo.xhtml
@@ -47,90 +47,79 @@
             return waitForServiceWorkerRegistrationChange(registration, function  () {
               // Got change event for updating (byte-check)
               ok(registration.installingWorker === null);
               ok(registration.waitingWorker === null);
               ok(registration.activeWorker === null);
 
               return waitForServiceWorkerRegistrationChange(registration, function  () {
                 is(registration.scriptSpec, EXAMPLE_URL + "worker.js");
-                ok(registration.evaluatingWorker !== null);
-                ok(registration.installingWorker === null);
+                ok(registration.installingWorker !== null);
+                is(registration.installingWorker.scriptSpec, EXAMPLE_URL + "worker.js");
                 ok(registration.waitingWorker === null);
                 ok(registration.activeWorker === null);
 
-                return waitForServiceWorkerRegistrationChange(registration, function  () {
-                  ok(registration.installingWorker !== null);
-                  is(registration.installingWorker.scriptSpec, EXAMPLE_URL + "worker.js");
-                  ok(registration.waitingWorker === null);
+                return waitForServiceWorkerRegistrationChange(registration, function () {
+                  ok(registration.installingWorker === null);
+                  ok(registration.waitingWorker !== null);
                   ok(registration.activeWorker === null);
 
                   return waitForServiceWorkerRegistrationChange(registration, function () {
+                    // Activating
                     ok(registration.installingWorker === null);
-                    ok(registration.waitingWorker !== null);
-                    ok(registration.activeWorker === null);
+                    ok(registration.waitingWorker === null);
+                    ok(registration.activeWorker !== null);
 
                     return waitForServiceWorkerRegistrationChange(registration, function () {
-                      // Activating
+                      // Activated
                       ok(registration.installingWorker === null);
                       ok(registration.waitingWorker === null);
                       ok(registration.activeWorker !== null);
 
-                      return waitForServiceWorkerRegistrationChange(registration, function () {
-                        // Activated
-                        ok(registration.installingWorker === null);
-                        ok(registration.waitingWorker === null);
-                        ok(registration.activeWorker !== null);
-
-                        return registration;
-                      });
+                      return registration;
                     });
                   });
                 });
               });
             });
           });
           iframe.contentWindow.postMessage("register", "*");
           let registration = await promise;
 
           promise = waitForServiceWorkerRegistrationChange(registration, function () {
             // Got change event for updating (byte-check)
             ok(registration.installingWorker === null);
             ok(registration.waitingWorker === null);
             ok(registration.activeWorker !== null);
 
-            return waitForServiceWorkerRegistrationChange(registration, function  () {
+            return waitForServiceWorkerRegistrationChange(registration, function () {
               is(registration.scriptSpec, EXAMPLE_URL + "worker2.js");
-              ok(registration.evaluatingWorker !== null);
+              ok(registration.installingWorker !== null);
+              is(registration.installingWorker.scriptSpec, EXAMPLE_URL + "worker2.js");
+              ok(registration.waitingWorker === null);
+              ok(registration.activeWorker !== null);
 
               return waitForServiceWorkerRegistrationChange(registration, function () {
-                ok(registration.installingWorker !== null);
-                is(registration.installingWorker.scriptSpec, EXAMPLE_URL + "worker2.js");
-                ok(registration.waitingWorker === null);
+                ok(registration.installingWorker === null);
+                ok(registration.waitingWorker !== null);
                 ok(registration.activeWorker !== null);
 
                 return waitForServiceWorkerRegistrationChange(registration, function () {
+                  // Activating
                   ok(registration.installingWorker === null);
-                  ok(registration.waitingWorker !== null);
+                  ok(registration.waitingWorker === null);
                   ok(registration.activeWorker !== null);
 
                   return waitForServiceWorkerRegistrationChange(registration, function () {
-                    // Activating
+                    // Activated
                     ok(registration.installingWorker === null);
                     ok(registration.waitingWorker === null);
                     ok(registration.activeWorker !== null);
 
-                    return waitForServiceWorkerRegistrationChange(registration, function () {
-                      // Activated
-                      ok(registration.installingWorker === null);
-                      ok(registration.waitingWorker === null);
-                      ok(registration.activeWorker !== null);
-
-                      return registration;
-                    });
+                    return registration;
                   });
                 });
               });
             });
           });
           iframe.contentWindow.postMessage("register", "*");
           await promise;