Merge fx-team to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 10 Aug 2016 16:53:40 -0700
changeset 308975 0502bd9e025edde29777ba1de4280f9b52af4663
parent 308960 dc8f8117d67b5ae9c7b42b72e3567ef5e754b1fa (current diff)
parent 308974 4caf18e4aaca92756f79b2cba666073fe76eabb7 (diff)
child 308976 233ab21b64b5d5e9f2f16ea2d4cfb4c8b293c5c4
child 308985 a2a3d88d28d0875938104b4352817abeaf7974c9
child 309097 c05296c94ec6785752f7a99c53985dd208815a89
child 309210 c50708c38f8119fe16a8235aa067fa4934ea0af0
push id30554
push userkwierso@gmail.com
push dateWed, 10 Aug 2016 23:53:45 +0000
treeherdermozilla-central@0502bd9e025e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.0a1
first release with
nightly linux32
0502bd9e025e / 51.0a1 / 20160811030201 / files
nightly linux64
0502bd9e025e / 51.0a1 / 20160811030201 / files
nightly mac
0502bd9e025e / 51.0a1 / 20160811030201 / files
nightly win32
0502bd9e025e / 51.0a1 / 20160811030201 / files
nightly win64
0502bd9e025e / 51.0a1 / 20160811030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge fx-team to central, a=merge
devtools/client/debugger/new/images/moz.build
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6772,16 +6772,32 @@ var gIdentityHandler = {
     // this is called before the first page load in the window for any reason.
     if (!this._uri) {
       Cu.reportError("Unexpected early call to refreshForInsecureLoginForms.");
       return;
     }
     this.refreshIdentityBlock();
   },
 
+  updateSharingIndicator() {
+    let tab = gBrowser.selectedTab;
+    let sharing = tab.getAttribute("sharing");
+    if (sharing)
+      this._identityBox.setAttribute("sharing", sharing);
+    else
+      this._identityBox.removeAttribute("sharing");
+
+    this._sharingState = tab._sharingState;
+
+    if (this._identityPopup.state == "open") {
+      this.updateSitePermissions();
+      this._identityPopupMultiView.setHeightToFit();
+    }
+  },
+
   /**
    * Attempt to provide proper IDN treatment for host names
    */
   getEffectiveHost: function() {
     if (!this._IDNService)
       this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
                          .getService(Ci.nsIIDNService);
     try {
@@ -7228,48 +7244,99 @@ var gIdentityHandler = {
   },
 
   updateSitePermissions: function () {
     while (this._permissionList.hasChildNodes())
       this._permissionList.removeChild(this._permissionList.lastChild);
 
     let uri = gBrowser.currentURI;
 
-    for (let permission of SitePermissions.getPermissionDetailsByURI(uri)) {
+    let permissions = SitePermissions.getPermissionDetailsByURI(uri);
+    if (this._sharingState) {
+      // If WebRTC device or screen permissions are in use, we need to find
+      // the associated permission item to set the inUse field to true.
+      for (let id of ["camera", "microphone", "screen"]) {
+        if (this._sharingState[id]) {
+          let found = false;
+          for (let permission of permissions) {
+            if (permission.id != id)
+              continue;
+            found = true;
+            permission.inUse = true;
+            break;
+          }
+          if (!found) {
+            // If the permission item we were looking for doesn't exist,
+            // the user has temporarily allowed sharing and we need to add
+            // an item in the permissions array to reflect this.
+            let permission = SitePermissions.getPermissionItem(id);
+            permission.inUse = true;
+            permissions.push(permission);
+          }
+        }
+      }
+    }
+    for (let permission of permissions) {
       let item = this._createPermissionItem(permission);
       this._permissionList.appendChild(item);
     }
   },
 
   _createPermissionItem: function (aPermission) {
     let container = document.createElement("hbox");
     container.setAttribute("class", "identity-popup-permission-item");
     container.setAttribute("align", "center");
 
     let img = document.createElement("image");
-    let isBlocked = (aPermission.state == SitePermissions.BLOCK) ? " blocked" : "";
-    img.setAttribute("class",
-      "identity-popup-permission-icon " + aPermission.id + "-icon" + isBlocked);
+    let classes = "identity-popup-permission-icon " + aPermission.id + "-icon";
+    if (aPermission.state == SitePermissions.BLOCK)
+      classes += " blocked";
+    if (aPermission.inUse)
+      classes += " in-use";
+    img.setAttribute("class", classes);
 
     let nameLabel = document.createElement("label");
     nameLabel.setAttribute("flex", "1");
     nameLabel.setAttribute("class", "identity-popup-permission-label");
     nameLabel.textContent = SitePermissions.getPermissionLabel(aPermission.id);
 
     let stateLabel = document.createElement("label");
     stateLabel.setAttribute("flex", "1");
     stateLabel.setAttribute("class", "identity-popup-permission-state-label");
     stateLabel.textContent = SitePermissions.getStateLabel(
-      aPermission.id, aPermission.state);
+      aPermission.id, aPermission.state, aPermission.inUse || false);
 
     let button = document.createElement("button");
     button.setAttribute("class", "identity-popup-permission-remove-button");
     button.addEventListener("command", () => {
       this._permissionList.removeChild(container);
       this._identityPopupMultiView.setHeightToFit();
+      if (aPermission.inUse &&
+          ["camera", "microphone", "screen"].includes(aPermission.id)) {
+        let windowId = this._sharingState.windowId;
+        if (aPermission.id == "screen") {
+          windowId = "screen:" + windowId;
+        } else {
+          // If we set persistent permissions or the sharing has
+          // started due to existing persistent permissions, we need
+          // to handle removing these even for frames with different hostnames.
+          let uris = gBrowser.selectedBrowser._devicePermissionURIs || [];
+          for (let uri of uris) {
+            // It's not possible to stop sharing one of camera/microphone
+            // without the other.
+            for (let id of ["camera", "microphone"]) {
+              if (this._sharingState[id] &&
+                  SitePermissions.get(uri, id) == SitePermissions.ALLOW)
+                SitePermissions.remove(uri, id);
+            }
+          }
+        }
+        let mm = gBrowser.selectedBrowser.messageManager;
+        mm.sendAsyncMessage("webrtc:StopSharing", windowId);
+      }
       SitePermissions.remove(gBrowser.currentURI, aPermission.id);
     });
 
     container.appendChild(img);
     container.appendChild(nameLabel);
     container.appendChild(stateLabel);
     container.appendChild(button);
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -701,16 +701,17 @@
                    align="center"
                    aria-label="&urlbar.viewSiteInfo.label;"
                    onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
                    onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
                    ondragstart="gIdentityHandler.onDragStart(event);">
                 <image id="identity-icon"
                        consumeanchor="identity-box"
                        onclick="PageProxyClickHandler(event);"/>
+                <image id="sharing-icon" mousethrough="always"/>
                 <box id="blocked-permissions-container" align="center" tooltiptext="">
                   <image data-permission-id="geo" class="notification-anchor-icon geo-icon blocked" role="button"
                          aria-label="&urlbar.geolocationNotificationAnchor.label;"/>
                   <image data-permission-id="desktop-notification" class="notification-anchor-icon desktop-notification-icon blocked" role="button"
                          aria-label="&urlbar.webNotsNotificationAnchor3.label;"/>
                   <image data-permission-id="camera" class="notification-anchor-icon camera-icon blocked" role="button"
                          aria-label="&urlbar.webRTCShareDevicesNotificationAnchor.label;"/>
                   <image data-permission-id="indexedDB" class="notification-anchor-icon indexedDB-icon blocked" role="button"
@@ -741,26 +742,20 @@
                   <image id="password-notification-icon" class="notification-anchor-icon login-icon" role="button"
                          aria-label="&urlbar.passwordNotificationAnchor.label;"/>
                   <image id="plugins-notification-icon" class="notification-anchor-icon plugin-icon" role="button"
                          aria-label="&urlbar.pluginsNotificationAnchor.label;"/>
                   <image id="web-notifications-notification-icon" class="notification-anchor-icon desktop-notification-icon" role="button"
                          aria-label="&urlbar.webNotsNotificationAnchor3.label;"/>
                   <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon camera-icon" role="button"
                          aria-label="&urlbar.webRTCShareDevicesNotificationAnchor.label;"/>
-                  <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon camera-icon in-use" role="button"
-                         aria-label="&urlbar.webRTCSharingDevicesNotificationAnchor.label;"/>
                   <image id="webRTC-shareMicrophone-notification-icon" class="notification-anchor-icon microphone-icon" role="button"
                          aria-label="&urlbar.webRTCShareMicrophoneNotificationAnchor.label;"/>
-                  <image id="webRTC-sharingMicrophone-notification-icon" class="notification-anchor-icon microphone-icon in-use" role="button"
-                         aria-label="&urlbar.webRTCSharingMicrophoneNotificationAnchor.label;"/>
                   <image id="webRTC-shareScreen-notification-icon" class="notification-anchor-icon screen-icon" role="button"
                          aria-label="&urlbar.webRTCShareScreenNotificationAnchor.label;"/>
-                  <image id="webRTC-sharingScreen-notification-icon" class="notification-anchor-icon screen-icon in-use" role="button"
-                         aria-label="&urlbar.webRTCSharingScreenNotificationAnchor.label;"/>
                   <image id="pointerLock-notification-icon" class="notification-anchor-icon pointerLock-icon" role="button"
                          aria-label="&urlbar.pointerLockNotificationAnchor.label;"/>
                   <image id="servicesInstall-notification-icon" class="notification-anchor-icon service-icon" role="button"
                          aria-label="&urlbar.servicesNotificationAnchor.label;"/>
                   <image id="translate-notification-icon" class="notification-anchor-icon translation-icon" role="button"
                          aria-label="&urlbar.translateNotificationAnchor.label;"/>
                   <image id="translated-notification-icon" class="notification-anchor-icon translation-icon in-use" role="button"
                          aria-label="&urlbar.translatedNotificationAnchor.label;"/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1220,16 +1220,17 @@
                 document.activeElement.blur();
               }
 
               if (!gMultiProcessBrowser)
                 this._adjustFocusAfterTabSwitch(this.mCurrentTab);
             }
 
             updateUserContextUIIndicator();
+            gIdentityHandler.updateSharingIndicator();
 
             this.tabContainer._setPositionalAttributes();
 
             if (!gMultiProcessBrowser) {
               let event = new CustomEvent("TabSwitchDone", {
                 bubbles: true,
                 cancelable: true
               });
@@ -1364,27 +1365,42 @@
             }
           });
           aTab.dispatchEvent(event);
         ]]></body>
       </method>
 
       <method name="setBrowserSharing">
         <parameter name="aBrowser"/>
-        <parameter name="aSharingState"/>
+        <parameter name="aState"/>
         <body><![CDATA[
           let tab = this.getTabForBrowser(aBrowser);
           if (!tab)
             return;
 
-          if (aSharingState)
-            tab.setAttribute("sharing", aSharingState);
-          else
+          let sharing;
+          if (aState.screen) {
+            sharing = "screen";
+          } else if (aState.camera) {
+            sharing = "camera";
+          } else if (aState.microphone) {
+            sharing = "microphone";
+          }
+
+          if (sharing) {
+            tab.setAttribute("sharing", sharing);
+            tab._sharingState = aState;
+          } else {
             tab.removeAttribute("sharing");
+            tab._sharingState = null;
+          }
           this._tabAttrModified(tab, ["sharing"]);
+
+          if (aBrowser == this.mCurrentBrowser)
+            gIdentityHandler.updateSharingIndicator();
         ]]></body>
       </method>
 
 
       <method name="setTabTitleLoading">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media.js
@@ -134,31 +134,17 @@ var gTests = [
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "CameraAndMicrophone",
        "expected camera and microphone to be shared");
 
     yield indicator;
     yield checkSharingUI({video: true, audio: true});
 
-    yield promiseNotificationShown(PopupNotifications.getNotification("webRTC-sharingDevices"));
-    activateSecondaryAction(kActionDeny);
-
-    yield promiseObserverCalled("recording-device-events");
-    yield expectObserverCalled("getUserMedia:revoke");
-
-    yield promiseNoPopupNotification("webRTC-sharingDevices");
-    yield expectObserverCalled("recording-window-ended");
-
-    if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
-      todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
-    }
-
-    yield expectNoObserverCalled();
-    yield checkNotSharing();
+    yield stopSharing();
 
     // the stream is already closed, but this will do some cleanup anyway
     yield closeStream(true);
   }
 },
 
 {
   desc: "getUserMedia audio+video: reloading the page removes all gUM UI",
@@ -176,24 +162,21 @@ var gTests = [
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "CameraAndMicrophone",
        "expected camera and microphone to be shared");
 
     yield indicator;
     yield checkSharingUI({video: true, audio: true});
 
-    yield promiseNotificationShown(PopupNotifications.getNotification("webRTC-sharingDevices"));
-
     info("reloading the web page");
     promise = promiseObserverCalled("recording-device-events");
     content.location.reload();
     yield promise;
 
-    yield promiseNoPopupNotification("webRTC-sharingDevices");
     if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
       todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
     }
 
     yield expectObserverCalled("recording-window-ended");
     yield expectNoObserverCalled();
     yield checkNotSharing();
   }
@@ -414,37 +397,17 @@ var gTests = [
       yield promise;
 
       yield expectObserverCalled("getUserMedia:request");
       yield expectObserverCalled("getUserMedia:response:allow");
       yield expectObserverCalled("recording-device-events");
       yield indicator;
       yield checkSharingUI({video: aRequestVideo, audio: aRequestAudio});
 
-      yield promiseNotificationShown(PopupNotifications.getNotification("webRTC-sharingDevices"));
-      let expectedIcon = "webRTC-sharingDevices";
-      if (aRequestAudio && !aRequestVideo)
-        expectedIcon = "webRTC-sharingMicrophone";
-      is(PopupNotifications.getNotification("webRTC-sharingDevices").anchorID,
-         expectedIcon + "-notification-icon", "anchored to correct icon");
-      is(PopupNotifications.panel.firstChild.getAttribute("popupid"), expectedIcon,
-         "panel using correct icon");
-
-      // Stop sharing.
-      activateSecondaryAction(kActionDeny);
-
-      yield promiseObserverCalled("recording-device-events");
-      yield expectObserverCalled("getUserMedia:revoke");
-
-      yield promiseNoPopupNotification("webRTC-sharingDevices");
-      yield expectObserverCalled("recording-window-ended");
-
-      if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
-        todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
-      }
+      yield stopSharing(aRequestVideo ? "camera" : "microphone");
 
       // Check that permissions have been removed as expected.
       let audioPerm = Perms.testExactPermission(uri, "microphone");
       if (aRequestAudio)
         is(audioPerm, Perms.UNKNOWN_ACTION, "microphone permissions removed");
       else
         is(audioPerm, Perms.ALLOW_ACTION, "microphone permissions untouched");
 
@@ -466,18 +429,18 @@ var gTests = [
     info("request audio, stop sharing resets audio only");
     yield stopAndCheckPerm(true, false);
     info("request video, stop sharing resets video only");
     yield stopAndCheckPerm(false, true);
   }
 },
 
 {
-  desc: "test showSharingDoorhanger",
-  run: function checkShowSharingDoorhanger() {
+  desc: "test showControlCenter",
+  run: function checkShowControlCenter() {
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(false, true);
     yield promise;
     yield expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(false, true);
 
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
@@ -485,31 +448,31 @@ var gTests = [
     });
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "Camera", "expected camera to be shared");
 
     yield indicator;
     yield checkSharingUI({video: true});
 
-    yield promisePopupNotificationShown("webRTC-sharingDevices", () => {
-      if ("nsISystemStatusBar" in Ci) {
-        let activeStreams = webrtcUI.getActiveStreams(true, false, false);
-        webrtcUI.showSharingDoorhanger(activeStreams[0], "Devices");
-      }
-      else {
-        let win =
-          Services.wm.getMostRecentWindow("Browser:WebRTCGlobalIndicator");
-        let elt = win.document.getElementById("audioVideoButton");
-        EventUtils.synthesizeMouseAtCenter(elt, {}, win);
-      }
-    });
+    ok(gIdentityHandler._identityPopup.hidden, "control center should be hidden");
+    if ("nsISystemStatusBar" in Ci) {
+      let activeStreams = webrtcUI.getActiveStreams(true, false, false);
+      webrtcUI.showSharingDoorhanger(activeStreams[0], "Devices");
+    }
+    else {
+      let win =
+        Services.wm.getMostRecentWindow("Browser:WebRTCGlobalIndicator");
+      let elt = win.document.getElementById("audioVideoButton");
+      EventUtils.synthesizeMouseAtCenter(elt, {}, win);
+      yield promiseWaitForCondition(() => !gIdentityHandler._identityPopup.hidden);
+    }
+    ok(!gIdentityHandler._identityPopup.hidden, "control center should be open");
 
-    PopupNotifications.panel.firstChild.button.click();
-    ok(!PopupNotifications.isPanelOpen, "notification panel closed");
+    gIdentityHandler._identityPopup.hidden = true;
     yield expectNoObserverCalled();
 
     yield closeStream();
   }
 },
 
 {
   desc: "'Always Allow' ignored and not shown on http pages",
@@ -561,16 +524,18 @@ function test() {
 
   browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
 
   browser.addEventListener("load", function onload() {
     browser.removeEventListener("load", onload, true);
 
     is(PopupNotifications._currentNotifications.length, 0,
        "should start the test without any prior popup notification");
+    ok(gIdentityHandler._identityPopup.hidden,
+       "should start the test with the control center hidden");
 
     Task.spawn(function () {
       yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
 
       for (let test of gTests) {
         info(test.desc);
         yield test.run();
 
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_in_frame.js
@@ -66,31 +66,17 @@ var gTests = [
 
     let Perms = Services.perms;
     let uri = Services.io.newURI("https://example.com/", null, null);
     is(Perms.testExactPermission(uri, "microphone"), Perms.ALLOW_ACTION,
                                  "microphone persistently allowed");
     is(Perms.testExactPermission(uri, "camera"), Perms.ALLOW_ACTION,
                                  "camera persistently allowed");
 
-    yield promiseNotificationShown(PopupNotifications.getNotification("webRTC-sharingDevices"));
-    activateSecondaryAction(kActionDeny);
-
-    yield promiseObserverCalled("recording-device-events");
-    yield expectObserverCalled("getUserMedia:revoke");
-
-    yield promiseNoPopupNotification("webRTC-sharingDevices");
-    yield expectObserverCalled("recording-window-ended");
-
-    if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
-      todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
-    }
-
-    yield expectNoObserverCalled();
-    yield checkNotSharing();
+    yield stopSharing();
 
     // The persistent permissions for the frame should have been removed.
     is(Perms.testExactPermission(uri, "microphone"), Perms.UNKNOWN_ACTION,
                                  "microphone not persistently allowed");
     is(Perms.testExactPermission(uri, "camera"), Perms.UNKNOWN_ACTION,
                                  "camera not persistently allowed");
 
     // the stream is already closed, but this will do some cleanup anyway
@@ -119,17 +105,16 @@ var gTests = [
     yield indicator;
     yield checkSharingUI({video: true, audio: true});
 
     info("reloading the frame");
     promise = promiseObserverCalled("recording-device-events");
     yield promiseReloadFrame("frame1");
     yield promise;
 
-    yield promiseNoPopupNotification("webRTC-sharingDevices");
     if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
       todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
     }
     yield expectObserverCalled("recording-window-ended");
     yield expectNoObserverCalled();
     yield checkNotSharing();
   }
 },
@@ -196,25 +181,24 @@ var gTests = [
     yield checkSharingUI({video: true, audio: true});
     yield expectNoObserverCalled();
 
     info("reloading the second frame");
     promise = promiseObserverCalled("recording-device-events");
     yield promiseReloadFrame("frame2");
     yield promise;
 
+    yield expectObserverCalled("recording-window-ended");
     yield checkSharingUI({video: false, audio: true});
-    yield expectObserverCalled("recording-window-ended");
     if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
       todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
     }
     yield expectNoObserverCalled();
 
     yield closeStream(false, "frame1");
-    yield promiseNoPopupNotification("webRTC-sharingDevices");
     yield expectNoObserverCalled();
     yield checkNotSharing();
   }
 }
 
 ];
 
 function test() {
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -326,49 +326,68 @@ function getMediaCaptureState() {
     let mm = _mm();
     mm.addMessageListener("Test:MediaCaptureState", ({data}) => {
       resolve(data);
     });
     mm.sendAsyncMessage("Test:GetMediaCaptureState");
   });
 }
 
+function* stopSharing(aType = "camera") {
+  let promiseRecordingEvent = promiseObserverCalled("recording-device-events");
+  gIdentityHandler._identityBox.click();
+  let permissions = document.getElementById("identity-popup-permission-list");
+  let cancelButton =
+    permissions.querySelector(".identity-popup-permission-icon." + aType + "-icon ~ " +
+                              ".identity-popup-permission-remove-button");
+  cancelButton.click();
+  gIdentityHandler._identityPopup.hidden = true;
+  yield promiseRecordingEvent;
+  yield expectObserverCalled("getUserMedia:revoke");
+  yield expectObserverCalled("recording-window-ended");
+
+  if ((yield promiseTodoObserverNotCalled("recording-device-events")) == 1) {
+    todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719");
+  }
+
+  yield expectNoObserverCalled();
+  yield* checkNotSharing();
+}
+
 function promiseRequestDevice(aRequestAudio, aRequestVideo, aFrameId, aType) {
   info("requesting devices");
   return ContentTask.spawn(gBrowser.selectedBrowser,
                            {aRequestAudio, aRequestVideo, aFrameId, aType},
                            function*(args) {
     let global = content.wrappedJSObject;
     if (args.aFrameId)
       global = global.document.getElementById(args.aFrameId).contentWindow;
     global.requestDevice(args.aRequestAudio, args.aRequestVideo, args.aType);
   });
 }
 
 function* closeStream(aAlreadyClosed, aFrameId) {
   yield expectNoObserverCalled();
 
-  let promise;
-  if (!aAlreadyClosed)
-    promise = promiseObserverCalled("recording-device-events");
+  let promises;
+  if (!aAlreadyClosed) {
+    promises = [promiseObserverCalled("recording-device-events"),
+                promiseObserverCalled("recording-window-ended")];
+  }
 
   info("closing the stream");
   yield ContentTask.spawn(gBrowser.selectedBrowser, aFrameId, function*(aFrameId) {
     let global = content.wrappedJSObject;
     if (aFrameId)
       global = global.document.getElementById(aFrameId).contentWindow;
     global.closeStream();
   });
 
-  if (!aAlreadyClosed)
-    yield promise;
-
-  yield promiseNoPopupNotification("webRTC-sharingDevices");
-  if (!aAlreadyClosed)
-    yield expectObserverCalled("recording-window-ended");
+  if (promises)
+    yield Promise.all(promises);
 
   yield* assertWebRTCIndicatorStatus(null);
 }
 
 function checkDeviceSelectors(aAudio, aVideo) {
   let micSelector = document.getElementById("webRTC-selectMicrophone");
   if (aAudio)
     ok(!micSelector.hidden, "microphone selector visible");
@@ -378,21 +397,61 @@ function checkDeviceSelectors(aAudio, aV
   let cameraSelector = document.getElementById("webRTC-selectCamera");
   if (aVideo)
     ok(!cameraSelector.hidden, "camera selector visible");
   else
     ok(cameraSelector.hidden, "camera selector hidden");
 }
 
 function* checkSharingUI(aExpected) {
-  yield promisePopupNotification("webRTC-sharingDevices");
+  // First check the icon above the control center (i) icon.
+  let identityBox = document.getElementById("identity-box");
+  ok(identityBox.hasAttribute("sharing"), "sharing attribute is set");
+  let sharing = identityBox.getAttribute("sharing");
+  if (aExpected.video)
+    is(sharing, "camera", "showing camera icon on the control center icon");
+  else if (aExpected.audio)
+    is(sharing, "microphone", "showing mic icon on the control center icon");
 
+  // Then check the sharing indicators inside the control center panel.
+  identityBox.click();
+  let permissions = document.getElementById("identity-popup-permission-list");
+  for (let id of ["microphone", "camera", "screen"]) {
+    let convertId = id => {
+      if (id == "camera")
+        return "video";
+      if (id == "microphone")
+        return "audio";
+      return id;
+    };
+    let expected = aExpected[convertId(id)];
+    is(!!gIdentityHandler._sharingState[id], !!expected,
+       "sharing state for " + id + " as expected");
+    let icon = permissions.querySelectorAll(
+      ".identity-popup-permission-icon." + id + "-icon");
+    if (expected) {
+      is(icon.length, 1, "should show " + id + " icon in control center panel");
+      ok(icon[0].classList.contains("in-use"), "icon should have the in-use class");
+    } else {
+      if (!icon.length) {
+        ok(true, "should not show " + id + " icon in the control center panel");
+      } else {
+        // This will happen if there are persistent permissions set.
+        ok(!icon[0].classList.contains("in-use"),
+           "if shown, the " + id + " icon should not have the in-use class");
+        is(icon.length, 1, "should not show more than 1 " + id + " icon");
+      }
+    }
+  }
+  gIdentityHandler._identityPopup.hidden = true;
+
+  // Check the global indicators.
   yield* assertWebRTCIndicatorStatus(aExpected);
 }
 
 function* checkNotSharing() {
   is((yield getMediaCaptureState()), "none", "expected nothing to be shared");
 
-  ok(!PopupNotifications.getNotification("webRTC-sharingDevices"),
-     "no webRTC-sharingDevices popup notification");
+  ok(!document.getElementById("identity-box").hasAttribute("sharing"),
+     "no sharing indicator on the control center icon");
 
   yield* assertWebRTCIndicatorStatus(null);
 }
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -215,21 +215,18 @@ These should match what Safari and other
 <!ENTITY urlbar.addonsNotificationAnchor.label          "View the add-on install message">
 <!ENTITY urlbar.indexedDBNotificationAnchor.label       "View the app-offline storage message">
 <!ENTITY urlbar.loginFillNotificationAnchor.label       "Manage your login information">
 <!ENTITY urlbar.passwordNotificationAnchor.label        "Check if you want to save your password">
 <!ENTITY urlbar.pluginsNotificationAnchor.label         "Manage plugin usage on this page">
 <!ENTITY urlbar.webNotsNotificationAnchor3.label        "Change whether you can receive notifications from the site">
 
 <!ENTITY urlbar.webRTCShareDevicesNotificationAnchor.label      "Manage sharing your camera and/or microphone with the site">
-<!ENTITY urlbar.webRTCSharingDevicesNotificationAnchor.label    "You are sharing your camera and/or microphone with the site">
 <!ENTITY urlbar.webRTCShareMicrophoneNotificationAnchor.label   "Manage sharing your microphone with the site">
-<!ENTITY urlbar.webRTCSharingMicrophoneNotificationAnchor.label "You are sharing your microphone with the site">
 <!ENTITY urlbar.webRTCShareScreenNotificationAnchor.label       "Manage sharing your windows or screen with the site">
-<!ENTITY urlbar.webRTCSharingScreenNotificationAnchor.label     "You are sharing a window or your screen with the site">
 
 <!ENTITY urlbar.pointerLockNotificationAnchor.label     "Change whether the site can hide the pointer">
 <!ENTITY urlbar.servicesNotificationAnchor.label        "View the service install message">
 <!ENTITY urlbar.translateNotificationAnchor.label       "Translate this page">
 <!ENTITY urlbar.translatedNotificationAnchor.label      "Manage page translation">
 <!ENTITY urlbar.emeNotificationAnchor.label             "Manage use of DRM software">
 
 <!ENTITY urlbar.openHistoryPopup.tooltip                "Show history">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -514,28 +514,16 @@ getUserMedia.shareApplication.label = Sh
 getUserMedia.shareWindow.label = Share Selected Window
 getUserMedia.shareSelectedItems.label = Share Selected Items
 getUserMedia.always.label = Always Share
 getUserMedia.always.accesskey = A
 getUserMedia.denyRequest.label = Don’t Share
 getUserMedia.denyRequest.accesskey = D
 getUserMedia.never.label = Never Share
 getUserMedia.never.accesskey = N
-getUserMedia.sharingCamera.message2 = You are currently sharing your camera with this page.
-getUserMedia.sharingMicrophone.message2 = You are currently sharing your microphone with this page.
-getUserMedia.sharingCameraAndMicrophone.message2 = You are currently sharing your camera and microphone with this page.
-getUserMedia.sharingApplication.message = You are currently sharing an application with this page.
-getUserMedia.sharingScreen.message = You are currently sharing your screen with this page.
-getUserMedia.sharingWindow.message = You are currently sharing a window with this page.
-getUserMedia.sharingBrowser.message = You are currently sharing a tab with this page.
-getUserMedia.sharingAudioCapture.message = You are currently sharing a tab’s audio with this page.
-getUserMedia.continueSharing.label = Continue Sharing
-getUserMedia.continueSharing.accesskey = C
-getUserMedia.stopSharing.label = Stop Sharing
-getUserMedia.stopSharing.accesskey = S
 
 getUserMedia.sharingMenu.label = Tabs sharing devices
 getUserMedia.sharingMenu.accesskey = d
 # LOCALIZATION NOTE (getUserMedia.sharingMenuCamera
 #                    getUserMedia.sharingMenuMicrophone,
 #                    getUserMedia.sharingMenuAudioCapture,
 #                    getUserMedia.sharingMenuApplication,
 #                    getUserMedia.sharingMenuScreen,
--- a/browser/locales/en-US/chrome/browser/sitePermissions.properties
+++ b/browser/locales/en-US/chrome/browser/sitePermissions.properties
@@ -1,18 +1,20 @@
 # 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/.
 
 allow = Allow
 allowForSession = Allow for Session
+allowTemporarily = Allow Temporarily
 block = Block
 alwaysAsk = Always Ask
 
 permission.cookie.label = Set Cookies
 permission.desktop-notification2.label = Receive Notifications
 permission.image.label = Load Images
 permission.camera.label = Use the Camera
 permission.microphone.label = Use the Microphone
+permission.screen.label = Share the Screen
 permission.install.label = Install Add-ons
 permission.popup.label = Open Pop-up Windows
 permission.geo.label = Access Your Location
 permission.indexedDB.label = Maintain Offline Storage
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -42,36 +42,44 @@ this.SitePermissions = {
           state: permission.capability,
         });
       }
     }
 
     return result;
   },
 
-  /* Returns a list of objects representing all permissions that are currently
-   * set for the given URI. Each object contains the following keys:
+  /* Returns an object representing the aId permission. It contains the
+   * following keys:
    * - id: the permissionID of the permission
    * - label: the localized label
-   * - state: a constant representing the current permission state
-   *   (e.g. SitePermissions.ALLOW)
+   * - state: a constant representing the aState permission state
+   *   (e.g. SitePermissions.ALLOW), or the default if aState is omitted
    * - availableStates: an array of all available states for that permission,
    *   represented as objects with the keys:
    *   - id: the state constant
    *   - label: the translated label of that state
    */
+  getPermissionItem: function (aId, aState) {
+    let availableStates = this.getAvailableStates(aId).map(state => {
+      return { id: state, label: this.getStateLabel(aId, state) };
+    });
+    if (aState == undefined)
+      aState = this.getDefault(aId);
+    return {id: aId, label: this.getPermissionLabel(aId),
+            state: aState, availableStates};
+  },
+
+  /* Returns a list of objects representing all permissions that are currently
+   * set for the given URI. See getPermissionItem for the content of each object.
+   */
   getPermissionDetailsByURI: function (aURI) {
     let permissions = [];
     for (let {state, id} of this.getAllByURI(aURI)) {
-      let availableStates = this.getAvailableStates(id).map( state => {
-        return { id: state, label: this.getStateLabel(id, state) };
-      });
-      let label = this.getPermissionLabel(id);
-
-      permissions.push({id, label, state, availableStates});
+      permissions.push(this.getPermissionItem(id, state));
     }
 
     return permissions;
   },
 
   /* Checks whether a UI for managing permissions should be exposed for a given
    * URI. This excludes file URIs, for instance, as they don't have a host,
    * even though nsIPermissionManager can still handle them.
@@ -154,19 +162,21 @@ this.SitePermissions = {
   getPermissionLabel: function (aPermissionID) {
     let labelID = gPermissionObject[aPermissionID].labelID || aPermissionID;
     return gStringBundle.GetStringFromName("permission." + labelID + ".label");
   },
 
   /* Returns the localized label for the given permission state, to be used in
    * a UI for managing permissions.
    */
-  getStateLabel: function (aPermissionID, aState) {
+  getStateLabel: function (aPermissionID, aState, aInUse = false) {
     switch (aState) {
       case this.UNKNOWN:
+        if (aInUse)
+          return gStringBundle.GetStringFromName("allowTemporarily");
         return gStringBundle.GetStringFromName("alwaysAsk");
       case this.ALLOW:
         return gStringBundle.GetStringFromName("allow");
       case this.SESSION:
         return gStringBundle.GetStringFromName("allowForSession");
       case this.BLOCK:
         return gStringBundle.GetStringFromName("block");
       default:
@@ -220,16 +230,19 @@ var gPermissionObject = {
 
   "desktop-notification": {
     exactHostMatch: true,
     labelID: "desktop-notification2",
   },
 
   "camera": {},
   "microphone": {},
+  "screen": {
+    states: [ SitePermissions.UNKNOWN, SitePermissions.BLOCK ],
+  },
 
   "popup": {
     getDefault: function () {
       return Services.prefs.getBoolPref("dom.disable_open_during_load") ?
                SitePermissions.BLOCK : SitePermissions.ALLOW;
     }
   },
 
--- a/browser/modules/test/xpcshell/test_SitePermissions.js
+++ b/browser/modules/test/xpcshell/test_SitePermissions.js
@@ -4,17 +4,17 @@
 "use strict";
 
 Components.utils.import("resource:///modules/SitePermissions.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 add_task(function* testPermissionsListing() {
   Assert.deepEqual(SitePermissions.listPermissions().sort(),
     ["camera","cookie","desktop-notification","geo","image",
-     "indexedDB","install","microphone","popup"],
+     "indexedDB","install","microphone","popup", "screen"],
     "Correct list of all permissions");
 });
 
 add_task(function* testGetAllByURI() {
   // check that it returns an empty array on an invalid URI
   // like a file URI, which doesn't support site permissions
   let wrongURI = Services.io.newURI("file:///example.js", null, null)
   Assert.deepEqual(SitePermissions.getAllByURI(wrongURI), []);
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -131,31 +131,29 @@ this.webrtcUI = {
   showSharingDoorhanger: function(aActiveStream, aType) {
     let browserWindow = aActiveStream.browser.ownerGlobal;
     if (aActiveStream.tab) {
       browserWindow.gBrowser.selectedTab = aActiveStream.tab;
     } else {
       aActiveStream.browser.focus();
     }
     browserWindow.focus();
-    let PopupNotifications = browserWindow.PopupNotifications;
-    let notif = PopupNotifications.getNotification("webRTC-sharing" + aType,
-                                                   aActiveStream.browser);
+    let identityBox = browserWindow.document.getElementById("identity-box");
     if (AppConstants.platform == "macosx" && !Services.focus.activeWindow) {
       browserWindow.addEventListener("activate", function onActivate() {
         browserWindow.removeEventListener("activate", onActivate);
         Services.tm.mainThread.dispatch(function() {
-          notif.reshow();
+          identityBox.click();
         }, Ci.nsIThread.DISPATCH_NORMAL);
       });
       Cc["@mozilla.org/widget/macdocksupport;1"].getService(Ci.nsIMacDockSupport)
         .activateApplication(true);
       return;
     }
-    notif.reshow();
+    identityBox.click();
   },
 
   updateMainActionLabel: function(aMenuList) {
     let type = aMenuList.selectedItem.getAttribute("devicetype");
     let document = aMenuList.ownerDocument;
     document.getElementById("webRTC-all-windows-shared").hidden = type != "Screen";
 
     // If we are also requesting audio in addition to screen sharing,
@@ -232,17 +230,19 @@ this.webrtcUI = {
             break;
         }
         // If there's no documentURI, the update is actually a removal of the
         // stream, triggered by the recording-window-ended notification.
         if (!aMessage.data.documentURI && index < webrtcUI._streams.length)
           webrtcUI._streams.splice(index, 1);
         else
           webrtcUI._streams[index] = {browser: aMessage.target, state: aMessage.data};
-        updateBrowserSpecificIndicator(aMessage.target, aMessage.data);
+        let tabbrowser = aMessage.target.ownerGlobal.gBrowser;
+        if (tabbrowser)
+          tabbrowser.setBrowserSharing(aMessage.target, aMessage.data);
         break;
       case "child-process-shutdown":
         webrtcUI.processIndicators.delete(aMessage.target);
         updateIndicators(null, null);
         break;
     }
   }
 };
@@ -861,150 +861,8 @@ function updateIndicators(data, target) 
       gIndicatorWindow = getGlobalIndicator();
     else
       gIndicatorWindow.updateIndicatorState();
   } else if (gIndicatorWindow) {
     gIndicatorWindow.close();
     gIndicatorWindow = null;
   }
 }
-
-function updateBrowserSpecificIndicator(aBrowser, aState) {
-  let chromeWin = aBrowser.ownerGlobal;
-  let tabbrowser = chromeWin.gBrowser;
-  if (tabbrowser) {
-    let sharing;
-    if (aState.screen) {
-      sharing = "screen";
-    } else if (aState.camera) {
-      sharing = "camera";
-    } else if (aState.microphone) {
-      sharing = "microphone";
-    }
-
-    tabbrowser.setBrowserSharing(aBrowser, sharing);
-  }
-
-  let captureState;
-  if (aState.camera && aState.microphone) {
-    captureState = "CameraAndMicrophone";
-  } else if (aState.camera) {
-    captureState = "Camera";
-  } else if (aState.microphone) {
-    captureState = "Microphone";
-  }
-
-  let stringBundle = chromeWin.gNavigatorBundle;
-
-  let windowId = aState.windowId;
-  let notification; // Used by action callbacks.
-  let mainAction = {
-    label: stringBundle.getString("getUserMedia.continueSharing.label"),
-    accessKey: stringBundle.getString("getUserMedia.continueSharing.accesskey"),
-    callback: function () {},
-    dismiss: true
-  };
-  let secondaryActions = [{
-    label: stringBundle.getString("getUserMedia.stopSharing.label"),
-    accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
-    callback: function () {
-      let uris = aBrowser._devicePermissionURIs || [];
-      uris = uris.concat(Services.io.newURI(aState.documentURI, null, null));
-      let perms = Services.perms;
-      for (let uri of uris) {
-        if (aState.camera &&
-            perms.testExactPermission(uri, "camera") == perms.ALLOW_ACTION)
-          perms.remove(uri, "camera");
-        if (aState.microphone &&
-            perms.testExactPermission(uri, "microphone") == perms.ALLOW_ACTION)
-          perms.remove(uri, "microphone");
-      }
-      let mm = notification.browser.messageManager;
-      mm.sendAsyncMessage("webrtc:StopSharing", windowId);
-    }
-  }];
-  let options = {
-    hideNotNow: true,
-    dismissed: true,
-    eventCallback: function(aTopic, aNewBrowser) {
-      if (aTopic == "shown") {
-        let popupId = captureState == "Microphone" ? "Microphone" : "Devices";
-        this.browser.ownerDocument
-            .getElementById("webRTC-sharingDevices-notification")
-            .setAttribute("popupid", "webRTC-sharing" + popupId);
-      }
-
-      if (aTopic == "swapping") {
-        webrtcUI.swapBrowserForNotification(this.browser, aNewBrowser);
-        return true;
-      }
-
-      return false;
-    }
-  };
-  if (captureState) {
-    let anchorId = captureState == "Microphone" ? "webRTC-sharingMicrophone-notification-icon"
-                                                : "webRTC-sharingDevices-notification-icon";
-    let message = stringBundle.getString("getUserMedia.sharing" + captureState + ".message2");
-    notification =
-      chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingDevices", message,
-                                        anchorId, mainAction, secondaryActions, options);
-  }
-  else {
-    removeBrowserNotification(aBrowser, "webRTC-sharingDevices");
-    aBrowser._devicePermissionURIs = null;
-  }
-
-  // Now handle the screen sharing indicator.
-  if (!aState.screen) {
-    removeBrowserNotification(aBrowser, "webRTC-sharingScreen");
-    return;
-  }
-
-  let screenSharingNotif; // Used by action callbacks.
-  let isBrowserSharing = aState.screen == "Browser";
-  options = {
-    hideNotNow: !isBrowserSharing,
-    dismissed: true,
-    eventCallback: function(aTopic, aNewBrowser) {
-      if (aTopic == "shown") {
-        this.browser.ownerDocument
-            .getElementById("webRTC-sharingScreen-notification")
-            .setAttribute("popupid", "webRTC-sharingScreen");
-      }
-
-      if (aTopic == "swapping") {
-        webrtcUI.swapBrowserForNotification(this.browser, aNewBrowser);
-        return true;
-      }
-
-      return false;
-    }
-  };
-  secondaryActions = [{
-    label: stringBundle.getString("getUserMedia.stopSharing.label"),
-    accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
-    callback: function () {
-      let mm = screenSharingNotif.browser.messageManager;
-      mm.sendAsyncMessage("webrtc:StopSharing", "screen:" + windowId);
-    }
-  }];
-
-  // Ending browser-sharing from the gUM doorhanger is not supported at the moment.
-  // See bug 1142091.
-  if (isBrowserSharing)
-    mainAction = secondaryActions = null;
-  // If we are sharing both a window and the screen, we show 'Screen'.
-  let stringId = "getUserMedia.sharing" + aState.screen;
-  screenSharingNotif =
-    chromeWin.PopupNotifications.show(aBrowser, "webRTC-sharingScreen",
-                                      stringBundle.getString(stringId + ".message"),
-                                      "webRTC-sharingScreen-notification-icon",
-                                      mainAction, secondaryActions, options);
-}
-
-function removeBrowserNotification(aBrowser, aNotificationId) {
-  let win = aBrowser.ownerGlobal;
-  let notification =
-    win.PopupNotifications.getNotification(aNotificationId, aBrowser);
-  if (notification)
-    win.PopupNotifications.remove(notification);
-}
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -376,16 +376,25 @@ description#identity-popup-content-verif
   display: none;
 }
 
 .identity-popup-permission-icon {
   width: 16px;
   height: 16px;
 }
 
+.identity-popup-permission-icon.in-use {
+  fill: rgb(224, 41, 29);
+  animation: 1.5s ease in-use-blink infinite;
+}
+
+@keyframes in-use-blink {
+  50% { opacity: 0; }
+}
+
 .identity-popup-permission-label {
   margin-inline-start: 1em;
 }
 
 .identity-popup-permission-state-label {
   margin-inline-end: 5px;
   text-align: end;
   opacity: 0.6;
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -89,16 +89,59 @@
 #urlbar[actiontype="searchengine"] > #identity-box > #identity-icon {
   -moz-image-region: inherit;
   list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
   width: 16px;
   height: 16px;
   opacity: 1;
 }
 
+/* SHARING ICON */
+
+#sharing-icon {
+  width: 16px;
+  height: 16px;
+  margin-inline-start: -16px;
+  position: relative;
+  display: none;
+}
+
+#identity-box[sharing="camera"] > #sharing-icon {
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#camera");
+}
+
+#identity-box[sharing="microphone"] > #sharing-icon {
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#microphone");
+}
+
+#identity-box[sharing="screen"] > #sharing-icon {
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#screen");
+}
+
+#identity-box[sharing] > #sharing-icon {
+  display: -moz-box;
+  filter: url("chrome://browser/skin/filters.svg#fill");
+  fill: rgb(224, 41, 29);
+  animation-delay: -1.5s;
+}
+
+#identity-box[sharing] > #identity-icon,
+#sharing-icon {
+  animation: 3s linear pulse infinite;
+}
+
+@keyframes pulse {
+  0%, 16.66%, 83.33%, 100% {
+    opacity: 0;
+  }
+  33.33%, 66.66% {
+    opacity: 1;
+  }
+}
+
 /* TRACKING PROTECTION ICON */
 
 #tracking-protection-icon {
   width: 16px;
   height: 16px;
   margin-inline-start: 2px;
   margin-inline-end: 0;
   list-style-image: url(chrome://browser/skin/tracking-protection-16.svg);
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -36,26 +36,22 @@
 }
 
 .popup-notification-icon {
   width: 64px;
   height: 64px;
   margin-inline-end: 10px;
 }
 
-#notification-popup-box > .notification-anchor-icon:not(.in-use):hover {
+#notification-popup-box > .notification-anchor-icon:hover {
   fill: #606060;
 }
 
 /* INDIVIDUAL NOTIFICATIONS */
 
-/* For the moment we apply the color filter only on the icons listed here.
-   The first two selectors are used by socialchat.xml (bug 1275558). */
-.webRTC-sharingDevices-notification-icon,
-.webRTC-sharingMicrophone-notification-icon,
 .camera-icon,
 .geo-icon,
 .indexedDB-icon,
 .install-icon,
 .login-icon,
 .microphone-icon,
 .plugin-icon,
 .pointerLock-icon,
@@ -64,32 +60,21 @@
 .desktop-notification-icon,
 .popup-notification-icon[popupid="geolocation"],
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .popup-notification-icon[popupid="password"],
 .popup-notification-icon[popupid="pointerLock"],
 .popup-notification-icon[popupid="webRTC-shareDevices"],
 .popup-notification-icon[popupid="webRTC-shareMicrophone"],
 .popup-notification-icon[popupid="webRTC-shareScreen"],
-.popup-notification-icon[popupid="webRTC-sharingDevices"],
-.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
-.popup-notification-icon[popupid="webRTC-sharingScreen"],
 .popup-notification-icon[popupid="web-notifications"] {
   filter: url(chrome://browser/skin/filters.svg#fill);
   fill: #999;
 }
 
-/* The first two selectors are used by socialchat.xml (bug 1275558). The
-   notifications in the chat window are only shown when they are in use. */
-.webRTC-sharingDevices-notification-icon,
-.webRTC-sharingMicrophone-notification-icon,
-.in-use {
-  fill: #fea01b;
-}
-
 .popup-notification-icon[popupid="web-notifications"],
 .desktop-notification-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification);
 }
 
 .desktop-notification-icon.blocked {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification-blocked);
 }
@@ -141,45 +126,38 @@
   list-style-image: url(chrome://browser/skin/notification-icons.svg#login-detailed);
 }
 
 #login-fill-notification-icon {
   /* Temporary solution until the capture and fill doorhangers are unified. */
   transform: scaleX(-1);
 }
 
-/* The first selector is used by socialchat.xml (bug 1275558). */
-.webRTC-sharingDevices-notification-icon,
 .camera-icon,
-.popup-notification-icon[popupid="webRTC-shareDevices"],
-.popup-notification-icon[popupid="webRTC-sharingDevices"] {
+.popup-notification-icon[popupid="webRTC-shareDevices"] {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#camera);
 }
 
 .camera-icon.blocked {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#camera-blocked);
 }
 
-/* The first selector is used by socialchat.xml (bug 1275558). */
-.webRTC-sharingMicrophone-notification-icon,
 .microphone-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone);
 }
 
 .microphone-icon.blocked {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-blocked);
 }
 
-.popup-notification-icon[popupid="webRTC-shareMicrophone"],
-.popup-notification-icon[popupid="webRTC-sharingMicrophone"] {
+.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-detailed);
 }
 
 .popup-notification-icon[popupid="webRTC-shareScreen"],
-.popup-notification-icon[popupid="webRTC-sharingScreen"],
 .screen-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#screen);
 }
 
 .screen-icon.blocked {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#screen-blocked);
 }
 
deleted file mode 100644
--- a/devtools/client/debugger/new/images/moz.build
+++ /dev/null
@@ -1,23 +0,0 @@
-DevToolsModules(
-    'angle-brackets.svg',
-    'arrow.svg',
-    'blackBox.svg',
-    'breakpoint.svg',
-    'close.svg',
-    'disableBreakpoints.svg',
-    'domain.svg',
-    'file.svg',
-    'folder.svg',
-    'globe.svg',
-    'pause-circle.svg',
-    'pause.svg',
-    'play.svg',
-    'prettyPrint.svg',
-    'resume.svg',
-    'settings.svg',
-    'stepIn.svg',
-    'stepOut.svg',
-    'stepOver.svg',
-    'subSettings.svg',
-    'worker.svg'
-)
\ No newline at end of file
--- a/devtools/client/debugger/new/moz.build
+++ b/devtools/client/debugger/new/moz.build
@@ -1,10 +1,12 @@
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'bundle.js',
     'panel.js',
+    'pretty-print-worker.js',
+    'source-map-worker.js',
     'styles.css'
 )
--- a/devtools/client/inspector/inspector-panel.js
+++ b/devtools/client/inspector/inspector-panel.js
@@ -208,17 +208,17 @@ InspectorPanel.prototype = {
 
     if (this.target.isLocalTab) {
       // Show a warning when the debugger is paused.
       // We show the warning only when the inspector
       // is selected.
       this.updateDebuggerPausedWarning = () => {
         let notificationBox = this._toolbox.getNotificationBox();
         let notification =
-            notificationBox.getNotificationWithValue("inspector-script-paused");
+          notificationBox.getNotificationWithValue("inspector-script-paused");
         if (!notification && this._toolbox.currentToolId == "inspector" &&
             this._toolbox.threadClient.paused) {
           let message = strings.GetStringFromName("debuggerPausedWarning.message");
           notificationBox.appendNotification(message,
             "inspector-script-paused", "", notificationBox.PRIORITY_WARNING_HIGH);
         }
 
         if (notification && this._toolbox.currentToolId != "inspector") {
@@ -348,19 +348,20 @@ InspectorPanel.prototype = {
     this.isDirty = true;
   },
 
   /**
    * Hooks the searchbar to show result and auto completion suggestions.
    */
   setupSearchBox: function () {
     this.searchBox = this.panelDoc.getElementById("inspector-searchbox");
+    this.searchClearButton = this.panelDoc.getElementById("inspector-searchinput-clear");
     this.searchResultsLabel = this.panelDoc.getElementById("inspector-searchlabel");
 
-    this.search = new InspectorSearch(this, this.searchBox);
+    this.search = new InspectorSearch(this, this.searchBox, this.searchClearButton);
     this.search.on("search-cleared", this._updateSearchResultsLabel);
     this.search.on("search-result", this._updateSearchResultsLabel);
 
     let shortcuts = new KeyShortcuts({
       window: this.panelDoc.defaultView,
     });
     let key = strings.GetStringFromName("inspector.searchHTML.key");
     shortcuts.on(key, (name, event) => {
@@ -1450,17 +1451,18 @@ InspectorPanel.prototype = {
     let node = this.selection.nodeFront;
     return this.markup.getNodeInnerHTML(node).then(oldContent => {
       this.markup.updateNodeInnerHTML(node, content, oldContent);
     });
   },
 
   /**
    * Paste the contents of the clipboard as adjacent HTML to the selected Node.
-   * @param position The position as specified for Element.insertAdjacentHTML
+   * @param position
+   *        The position as specified for Element.insertAdjacentHTML
    *        (i.e. "beforeBegin", "afterBegin", "beforeEnd", "afterEnd").
    */
   pasteAdjacentHTML: function (position) {
     let content = this._getClipboardContentForPaste();
     if (!content) {
       return promise.reject("No clipboard content for paste");
     }
 
@@ -1510,31 +1512,31 @@ InspectorPanel.prototype = {
     if (container && container.isPreviewable()) {
       container.copyImageDataUri();
     }
   },
 
   /**
    * Copy the content of a longString (via a promise resolving a
    * LongStringActor) to the clipboard
-   * @param  {Promise} longStringActorPromise promise expected to
-   *         resolve a LongStringActor instance
+   * @param  {Promise} longStringActorPromise
+   *         promise expected to resolve a LongStringActor instance
    * @return {Promise} promise resolving (with no argument) when the
    *         string is sent to the clipboard
    */
   _copyLongString: function (longStringActorPromise) {
     return this._getLongString(longStringActorPromise).then(string => {
       clipboardHelper.copyString(string);
     }).catch(e => console.error(e));
   },
 
   /**
    * Retrieve the content of a longString (via a promise resolving a LongStringActor)
-   * @param  {Promise} longStringActorPromise promise expected to
-   *         resolve a LongStringActor instance
+   * @param  {Promise} longStringActorPromise
+   *         promise expected to resolve a LongStringActor instance
    * @return {Promise} promise resolving with the retrieved string as argument
    */
   _getLongString: function (longStringActorPromise) {
     return longStringActorPromise.then(longStringActor => {
       return longStringActor.string().then(string => {
         longStringActor.release().catch(e => console.error(e));
         return string;
       });
--- a/devtools/client/inspector/inspector-search.js
+++ b/devtools/client/inspector/inspector-search.js
@@ -1,48 +1,54 @@
 /* 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";
 
-/* eslint-disable mozilla/reject-some-requires */
-const {Ci} = require("chrome");
-/* eslint-enable mozilla/reject-some-requires */
 const promise = require("promise");
 const {Task} = require("devtools/shared/task");
 
 const system = require("devtools/shared/system");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {AutocompletePopup} = require("devtools/client/shared/autocomplete-popup");
 
 // Maximum number of selector suggestions shown in the panel.
 const MAX_SUGGESTIONS = 15;
 
 /**
  * Converts any input field into a document search box.
  *
- * @param {InspectorPanel} inspector The InspectorPanel whose `walker` attribute
- * should be used for document traversal.
- * @param {DOMNode} input The input element to which the panel will be attached
- * and from where search input will be taken.
+ * @param {InspectorPanel} inspector
+ *        The InspectorPanel whose `walker` attribute should be used for
+ *        document traversal.
+ * @param {DOMNode} input
+ *        The input element to which the panel will be attached and from where
+ *        search input will be taken.
+ * @param {DOMNode} clearBtn
+ *        The clear button in the input field that will clear the input value.
  *
  * Emits the following events:
  * - search-cleared: when the search box is emptied
  * - search-result: when a search is made and a result is selected
  */
-function InspectorSearch(inspector, input) {
+function InspectorSearch(inspector, input, clearBtn) {
   this.inspector = inspector;
   this.searchBox = input;
+  this.searchClearButton = clearBtn;
   this._lastSearched = null;
 
+  this.searchClearButton.hidden = true;
+
   this._onKeyDown = this._onKeyDown.bind(this);
-  this._onCommand = this._onCommand.bind(this);
+  this._onInput = this._onInput.bind(this);
+  this._onClearSearch = this._onClearSearch.bind(this);
   this.searchBox.addEventListener("keydown", this._onKeyDown, true);
-  this.searchBox.addEventListener("command", this._onCommand, true);
+  this.searchBox.addEventListener("input", this._onInput, true);
+  this.searchClearButton.addEventListener("click", this._onClearSearch);
 
   // For testing, we need to be able to wait for the most recent node request
   // to finish.  Tests can watch this promise for that.
   this._lastQuery = promise.resolve(null);
 
   this.autocompleter = new SelectorAutocompleter(inspector, input);
   EventEmitter.decorate(this);
 }
@@ -51,18 +57,20 @@ exports.InspectorSearch = InspectorSearc
 
 InspectorSearch.prototype = {
   get walker() {
     return this.inspector.walker;
   },
 
   destroy: function () {
     this.searchBox.removeEventListener("keydown", this._onKeyDown, true);
-    this.searchBox.removeEventListener("command", this._onCommand, true);
+    this.searchBox.removeEventListener("input", this._onInput, true);
+    this.searchClearButton.removeEventListener("click", this._onClearSearch);
     this.searchBox = null;
+    this.searchClearButton = null;
     this.autocompleter.destroy();
   },
 
   _onSearch: function (reverse = false) {
     this.doFullTextSearch(this.searchBox.value, reverse)
         .catch(e => console.error(e));
   },
 
@@ -92,38 +100,45 @@ InspectorSearch.prototype = {
       res.query = query;
       this.emit("search-result", res);
     } else {
       this.searchBox.classList.add("devtools-style-searchbox-no-match");
       this.emit("search-result");
     }
   }),
 
-  _onCommand: function () {
+  _onInput: function () {
     if (this.searchBox.value.length === 0) {
       this._onSearch();
     }
   },
 
   _onKeyDown: function (event) {
     if (this.searchBox.value.length === 0) {
+      this.searchClearButton.hidden = true;
       this.searchBox.removeAttribute("filled");
     } else {
+      this.searchClearButton.hidden = false;
       this.searchBox.setAttribute("filled", true);
     }
     if (event.keyCode === event.DOM_VK_RETURN) {
       this._onSearch(event.shiftKey);
     }
 
     const modifierKey = system.constants.platform === "macosx"
                         ? event.metaKey : event.ctrlKey;
-    if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_G && modifierKey) {
+    if (event.keyCode === event.DOM_VK_G && modifierKey) {
       this._onSearch(event.shiftKey);
       event.preventDefault();
     }
+  },
+
+  _onClearSearch: function () {
+    this.searchBox.value = "";
+    this.searchClearButton.hidden = true;
   }
 };
 
 /**
  * Converts any input box on a page to a CSS selector search and suggestion box.
  *
  * Emits 'processing-done' event when it is done processing the current
  * keypress, search request or selection from the list, whether that led to a
--- a/devtools/client/inspector/inspector.xul
+++ b/devtools/client/inspector/inspector.xul
@@ -35,24 +35,25 @@
       <html:div id="inspector-toolbar"
         class="devtools-toolbar"
         nowindowdrag="true">
         <html:button id="inspector-element-add-button"
           title="&inspectorAddNode.label;"
           class="devtools-button" />
         <html:div class="devtools-toolbar-spacer" />
         <html:span id="inspector-searchlabel" />
-        <textbox id="inspector-searchbox"
-          type="search"
-          timeout="50"
-          class="devtools-searchinput"
-          placeholder="&inspectorSearchHTML.label3;"/>
+        <html:div id="inspector-search" class="devtools-searchbox">
+          <html:input id="inspector-searchbox" class="devtools-searchinput"
+                      type="search"
+                      placeholder="&inspectorSearchHTML.label3;"/>
+          <html:button id="inspector-searchinput-clear" class="devtools-searchinput-clear" tabindex="-1"></html:button>
+        </html:div>
         <html:button id="inspector-eyedropper-toggle"
-          title="&inspectorEyeDropper.label;"
-          class="devtools-button command-button-invertable" />
+                     title="&inspectorEyeDropper.label;"
+                     class="devtools-button command-button-invertable" />
         <div xmlns="http://www.w3.org/1999/xhtml"
           id="inspector-sidebar-toggle-box" />
       </html:div>
       <vbox flex="1" id="markup-box">
       </vbox>
       <html:div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
         <html:div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
                   role="group" aria-label="&inspectorBreadcrumbsGroup;" tabindex="0" />
--- a/devtools/client/inspector/markup/test/actor_events_form.js
+++ b/devtools/client/inspector/markup/test/actor_events_form.js
@@ -3,52 +3,59 @@
 
 "use strict";
 
 // This test actor is used for testing the addition of custom form data
 // on NodeActor. Custom form property is set when 'form' event is sent
 // by NodeActor actor (see 'onNodeActorForm' method).
 
 const Events = require("sdk/event/core");
-const {ActorClass, Actor, FrontClass, Front, method} =
+const {ActorClass, Actor, FrontClass, Front, generateActorSpec} =
   require("devtools/shared/protocol");
 
 const {NodeActor} = require("devtools/server/actors/inspector");
 
-var EventsFormActor = ActorClass({
+var eventsSpec = generateActorSpec({
   typeName: "eventsFormActor",
 
+  methods: {
+    attach: {
+      request: {},
+      response: {}
+    },
+    detach: {
+      request: {},
+      response: {}
+    }
+  }
+});
+
+var EventsFormActor = ActorClass(eventsSpec, {
   initialize: function () {
     Actor.prototype.initialize.apply(this, arguments);
   },
 
-  attach: method(function () {
+  attach: function () {
     Events.on(NodeActor, "form", this.onNodeActorForm);
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
-  detach: method(function () {
+  detach: function () {
     Events.off(NodeActor, "form", this.onNodeActorForm);
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   onNodeActorForm: function (event) {
     let nodeActor = event.target;
     if (nodeActor.rawNode.id == "container") {
       let form = event.data;
       form.setFormProperty("test-property", "test-value");
     }
   }
 });
 
-var EventsFormFront = FrontClass(EventsFormActor, {
+var EventsFormFront = FrontClass(eventsSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.apply(this, arguments);
 
     this.actorID = form[EventsFormActor.prototype.typeName];
     this.manage(this);
   }
 });
 
--- a/devtools/client/inspector/test/browser_inspector_search-02.js
+++ b/devtools/client/inspector/test/browser_inspector_search-02.js
@@ -136,17 +136,17 @@ add_task(function* () {
   let searchBox = inspector.searchBox;
   let popup = inspector.searchSuggestions.searchPopup;
 
   yield focusSearchBoxUsingShortcut(inspector.panelWin);
 
   for (let { key, suggestions } of TEST_DATA) {
     info("Pressing " + key + " to get " + formatSuggestions(suggestions));
 
-    let command = once(searchBox, "command");
+    let command = once(searchBox, "input");
     EventUtils.synthesizeKey(key, {}, inspector.panelWin);
     yield command;
 
     info("Waiting for search query to complete");
     yield inspector.searchSuggestions._lastQuery;
 
     info("Query completed. Performing checks for input '" + searchBox.value +
       "' - key pressed: " + key);
--- a/devtools/client/inspector/test/browser_inspector_search-03.js
+++ b/devtools/client/inspector/test/browser_inspector_search-03.js
@@ -217,17 +217,17 @@ add_task(function* () {
   let searchBox = inspector.searchBox;
   let popup = inspector.searchSuggestions.searchPopup;
 
   yield focusSearchBoxUsingShortcut(inspector.panelWin);
 
   for (let { key, suggestions } of TEST_DATA) {
     info("Pressing " + key + " to get " + formatSuggestions(suggestions));
 
-    let command = once(searchBox, "command");
+    let command = once(searchBox, "input");
     EventUtils.synthesizeKey(key, {}, inspector.panelWin);
     yield command;
 
     info("Waiting for search query to complete");
     yield inspector.searchSuggestions._lastQuery;
 
     info("Query completed. Performing checks for input '" +
          searchBox.value + "'");
--- a/devtools/client/inspector/test/browser_inspector_search-04.js
+++ b/devtools/client/inspector/test/browser_inspector_search-04.js
@@ -79,17 +79,17 @@ add_task(function* () {
   let searchBox = inspector.searchBox;
   let popup = inspector.searchSuggestions.searchPopup;
 
   yield focusSearchBoxUsingShortcut(inspector.panelWin);
 
   for (let {key, suggestions} of TEST_DATA) {
     info("Pressing " + key + " to get " + formatSuggestions(suggestions));
 
-    let command = once(searchBox, "command");
+    let command = once(searchBox, "input");
     EventUtils.synthesizeKey(key, {}, inspector.panelWin);
     yield command;
 
     info("Waiting for search query to complete");
     yield inspector.searchSuggestions._lastQuery;
 
     info("Query completed. Performing checks for input '" +
          searchBox.value + "'");
--- a/devtools/client/inspector/test/browser_inspector_search-07.js
+++ b/devtools/client/inspector/test/browser_inspector_search-07.js
@@ -1,49 +1,49 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-// Test that searching for classes on SVG elements does work (see bug 1219920).
-
-const TEST_URL = URL_ROOT + "doc_inspector_search-svg.html";
-
-// An array of (key, suggestions) pairs where key is a key to press and
-// suggestions is an array of suggestions that should be shown in the popup.
-const TEST_DATA = [{
-  key: "c",
-  suggestions: ["circle", "clipPath", ".class1", ".class2"]
-}, {
-  key: "VK_BACK_SPACE",
-  suggestions: []
-}, {
-  key: ".",
-  suggestions: [".class1", ".class2"]
-}];
-
-add_task(function* () {
-  let {inspector} = yield openInspectorForURL(TEST_URL);
-  let {searchBox} = inspector;
-  let popup = inspector.searchSuggestions.searchPopup;
-
-  yield focusSearchBoxUsingShortcut(inspector.panelWin);
-
-  for (let {key, suggestions} of TEST_DATA) {
-    info("Pressing " + key + " to get " + suggestions);
-
-    let command = once(searchBox, "command");
-    EventUtils.synthesizeKey(key, {}, inspector.panelWin);
-    yield command;
-
-    info("Waiting for search query to complete and getting the suggestions");
-    yield inspector.searchSuggestions._lastQuery;
-    let actualSuggestions = popup.getItems().reverse();
-
-    is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
-       "There are expected number of suggestions.");
-
-    for (let i = 0; i < suggestions.length; i++) {
-      is(actualSuggestions[i].label, suggestions[i],
-         "The suggestion at " + i + "th index is correct.");
-    }
-  }
-});
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that searching for classes on SVG elements does work (see bug 1219920).
+
+const TEST_URL = URL_ROOT + "doc_inspector_search-svg.html";
+
+// An array of (key, suggestions) pairs where key is a key to press and
+// suggestions is an array of suggestions that should be shown in the popup.
+const TEST_DATA = [{
+  key: "c",
+  suggestions: ["circle", "clipPath", ".class1", ".class2"]
+}, {
+  key: "VK_BACK_SPACE",
+  suggestions: []
+}, {
+  key: ".",
+  suggestions: [".class1", ".class2"]
+}];
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL(TEST_URL);
+  let {searchBox} = inspector;
+  let popup = inspector.searchSuggestions.searchPopup;
+
+  yield focusSearchBoxUsingShortcut(inspector.panelWin);
+
+  for (let {key, suggestions} of TEST_DATA) {
+    info("Pressing " + key + " to get " + suggestions);
+
+    let command = once(searchBox, "input");
+    EventUtils.synthesizeKey(key, {}, inspector.panelWin);
+    yield command;
+
+    info("Waiting for search query to complete and getting the suggestions");
+    yield inspector.searchSuggestions._lastQuery;
+    let actualSuggestions = popup.getItems().reverse();
+
+    is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
+       "There are expected number of suggestions.");
+
+    for (let i = 0; i < suggestions.length; i++) {
+      is(actualSuggestions[i].label, suggestions[i],
+         "The suggestion at " + i + "th index is correct.");
+    }
+  }
+});
--- a/devtools/client/inspector/test/browser_inspector_search-08.js
+++ b/devtools/client/inspector/test/browser_inspector_search-08.js
@@ -1,64 +1,64 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-// Test that searching for namespaced elements does work.
-
-const XHTML = `
-  <!DOCTYPE html>
-  <html xmlns="http://www.w3.org/1999/xhtml"
-        xmlns:svg="http://www.w3.org/2000/svg">
-    <body>
-      <svg:svg width="100" height="100">
-        <svg:clipPath>
-          <svg:rect x="0" y="0" width="10" height="5"></svg:rect>
-        </svg:clipPath>
-        <svg:circle cx="0" cy="0" r="5"></svg:circle>
-      </svg:svg>
-    </body>
-  </html>
-`;
-
-const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
-
-// An array of (key, suggestions) pairs where key is a key to press and
-// suggestions is an array of suggestions that should be shown in the popup.
-const TEST_DATA = [{
-  key: "c",
-  suggestions: ["circle", "clipPath"]
-}, {
-  key: "VK_BACK_SPACE",
-  suggestions: []
-}, {
-  key: "s",
-  suggestions: ["svg"]
-}];
-
-add_task(function* () {
-  let {inspector} = yield openInspectorForURL(TEST_URI);
-  let {searchBox} = inspector;
-  let popup = inspector.searchSuggestions.searchPopup;
-
-  yield focusSearchBoxUsingShortcut(inspector.panelWin);
-
-  for (let {key, suggestions} of TEST_DATA) {
-    info("Pressing " + key + " to get " + suggestions.join(", "));
-
-    let command = once(searchBox, "command");
-    EventUtils.synthesizeKey(key, {}, inspector.panelWin);
-    yield command;
-
-    info("Waiting for search query to complete and getting the suggestions");
-    yield inspector.searchSuggestions._lastQuery;
-    let actualSuggestions = popup.getItems().reverse();
-
-    is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
-       "There are expected number of suggestions.");
-
-    for (let i = 0; i < suggestions.length; i++) {
-      is(actualSuggestions[i].label, suggestions[i],
-         "The suggestion at " + i + "th index is correct.");
-    }
-  }
-});
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Test that searching for namespaced elements does work.
+
+const XHTML = `
+  <!DOCTYPE html>
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:svg="http://www.w3.org/2000/svg">
+    <body>
+      <svg:svg width="100" height="100">
+        <svg:clipPath>
+          <svg:rect x="0" y="0" width="10" height="5"></svg:rect>
+        </svg:clipPath>
+        <svg:circle cx="0" cy="0" r="5"></svg:circle>
+      </svg:svg>
+    </body>
+  </html>
+`;
+
+const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
+
+// An array of (key, suggestions) pairs where key is a key to press and
+// suggestions is an array of suggestions that should be shown in the popup.
+const TEST_DATA = [{
+  key: "c",
+  suggestions: ["circle", "clipPath"]
+}, {
+  key: "VK_BACK_SPACE",
+  suggestions: []
+}, {
+  key: "s",
+  suggestions: ["svg"]
+}];
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL(TEST_URI);
+  let {searchBox} = inspector;
+  let popup = inspector.searchSuggestions.searchPopup;
+
+  yield focusSearchBoxUsingShortcut(inspector.panelWin);
+
+  for (let {key, suggestions} of TEST_DATA) {
+    info("Pressing " + key + " to get " + suggestions.join(", "));
+
+    let command = once(searchBox, "input");
+    EventUtils.synthesizeKey(key, {}, inspector.panelWin);
+    yield command;
+
+    info("Waiting for search query to complete and getting the suggestions");
+    yield inspector.searchSuggestions._lastQuery;
+    let actualSuggestions = popup.getItems().reverse();
+
+    is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
+       "There are expected number of suggestions.");
+
+    for (let i = 0; i < suggestions.length; i++) {
+      is(actualSuggestions[i].label, suggestions[i],
+         "The suggestion at " + i + "th index is correct.");
+    }
+  }
+});
--- a/devtools/client/inspector/test/browser_inspector_search-reserved.js
+++ b/devtools/client/inspector/test/browser_inspector_search-reserved.js
@@ -99,17 +99,17 @@ add_task(function* () {
   let searchBox = inspector.searchBox;
   let popup = inspector.searchSuggestions.searchPopup;
 
   yield focusSearchBoxUsingShortcut(inspector.panelWin);
 
   for (let { key, suggestions } of TEST_DATA) {
     info("Pressing " + key + " to get " + formatSuggestions(suggestions));
 
-    let command = once(searchBox, "command");
+    let command = once(searchBox, "input");
     EventUtils.synthesizeKey(key, {}, inspector.panelWin);
     yield command;
 
     info("Waiting for search query to complete");
     yield inspector.searchSuggestions._lastQuery;
 
     info("Query completed. Performing checks for input '" +
          searchBox.value + "'");
--- a/devtools/client/inspector/test/browser_inspector_search-suggests-ids-and-classes.js
+++ b/devtools/client/inspector/test/browser_inspector_search-suggests-ids-and-classes.js
@@ -57,17 +57,17 @@ add_task(function* () {
   let popup = inspector.searchSuggestions.searchPopup;
 
   yield focusSearchBoxUsingShortcut(inspector.panelWin);
 
   for (let [key, expectedSuggestions] of KEY_STATES) {
     info("pressing key " + key + " to get suggestions " +
          JSON.stringify(expectedSuggestions));
 
-    let onCommand = once(searchBox, "command", true);
+    let onCommand = once(searchBox, "input", true);
     EventUtils.synthesizeKey(key, {}, inspector.panelWin);
     yield onCommand;
 
     info("Waiting for the suggestions to be retrieved");
     yield inspector.searchSuggestions._lastQuery;
 
     let actualSuggestions = popup.getItems();
     is(popup.isOpen ? actualSuggestions.length : 0, expectedSuggestions.length,
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -41,19 +41,235 @@ var dumpn = msg => {
  */
 function getHighlighterCanvasFrameHelper(conn, actorID) {
   let actor = conn.getActor(actorID);
   if (actor && actor._highlighter) {
     return actor._highlighter.markup;
   }
 }
 
-var TestActor = exports.TestActor = protocol.ActorClass({
+var testSpec = protocol.generateActorSpec({
   typeName: "testActor",
 
+  methods: {
+    getNumberOfElementMatches: {
+      request: {
+        selector: Arg(0, "string"),
+      },
+      response: {
+        value: RetVal("number")
+      }
+    },
+    getHighlighterAttribute: {
+      request: {
+        nodeID: Arg(0, "string"),
+        name: Arg(1, "string"),
+        actorID: Arg(2, "string")
+      },
+      response: {
+        value: RetVal("string")
+      }
+    },
+    getHighlighterNodeTextContent: {
+      request: {
+        nodeID: Arg(0, "string"),
+        actorID: Arg(1, "string")
+      },
+      response: {
+        value: RetVal("string")
+      }
+    },
+    getSelectorHighlighterBoxNb: {
+      request: {
+        highlighter: Arg(0, "string"),
+      },
+      response: {
+        value: RetVal("number")
+      }
+    },
+    changeHighlightedNodeWaitForUpdate: {
+      request: {
+        name: Arg(0, "string"),
+        value: Arg(1, "string"),
+        actorID: Arg(2, "string")
+      },
+      response: {}
+    },
+    waitForHighlighterEvent: {
+      request: {
+        event: Arg(0, "string"),
+        actorID: Arg(1, "string")
+      },
+      response: {}
+    },
+    waitForEventOnNode: {
+      request: {
+        eventName: Arg(0, "string"),
+        selector: Arg(1, "nullable:string")
+      },
+      response: {}
+    },
+    changeZoomLevel: {
+      request: {
+        level: Arg(0, "string"),
+        actorID: Arg(1, "string"),
+      },
+      response: {}
+    },
+    assertElementAtPoint: {
+      request: {
+        x: Arg(0, "number"),
+        y: Arg(1, "number"),
+        selector: Arg(2, "string")
+      },
+      response: {
+        value: RetVal("boolean")
+      }
+    },
+    getAllAdjustedQuads: {
+      request: {
+        selector: Arg(0, "string")
+      },
+      response: {
+        value: RetVal("json")
+      }
+    },
+    synthesizeMouse: {
+      request: {
+        object: Arg(0, "json")
+      },
+      response: {}
+    },
+    synthesizeKey: {
+      request: {
+        args: Arg(0, "json")
+      },
+      response: {}
+    },
+    hasPseudoClassLock: {
+      request: {
+        selector: Arg(0, "string"),
+        pseudo: Arg(1, "string")
+      },
+      response: {
+        value: RetVal("boolean")
+      }
+    },
+    loadAndWaitForCustomEvent: {
+      request: {
+        url: Arg(0, "string")
+      },
+      response: {}
+    },
+    hasNode: {
+      request: {
+        selector: Arg(0, "string")
+      },
+      response: {
+        value: RetVal("boolean")
+      }
+    },
+    getBoundingClientRect: {
+      request: {
+        selector: Arg(0, "string"),
+      },
+      response: {
+        value: RetVal("json")
+      }
+    },
+    setProperty: {
+      request: {
+        selector: Arg(0, "string"),
+        property: Arg(1, "string"),
+        value: Arg(2, "string")
+      },
+      response: {}
+    },
+    getProperty: {
+      request: {
+        selector: Arg(0, "string"),
+        property: Arg(1, "string")
+      },
+      response: {
+        value: RetVal("string")
+      }
+    },
+    getAttribute: {
+      request: {
+        selector: Arg(0, "string"),
+        property: Arg(1, "string")
+      },
+      response: {
+        value: RetVal("string")
+      }
+    },
+    setAttribute: {
+      request: {
+        selector: Arg(0, "string"),
+        property: Arg(1, "string"),
+        value: Arg(2, "string")
+      },
+      response: {}
+    },
+    removeAttribute: {
+      request: {
+        selector: Arg(0, "string"),
+        property: Arg(1, "string")
+      },
+      response: {}
+    },
+    reload: {
+      request: {},
+      response: {}
+    },
+    reloadFrame: {
+      request: {
+        selector: Arg(0, "string"),
+      },
+      response: {}
+    },
+    eval: {
+      request: {
+        js: Arg(0, "string")
+      },
+      response: {
+        value: RetVal("nullable:json")
+      }
+    },
+    scrollWindow: {
+      request: {
+        x: Arg(0, "number"),
+        y: Arg(1, "number"),
+        relative: Arg(2, "nullable:boolean"),
+      },
+      response: {
+        value: RetVal("json")
+      }
+    },
+    reflow: {},
+    getNodeRect: {
+      request: {
+        selector: Arg(0, "string")
+      },
+      response: {
+        value: RetVal("json")
+      }
+    },
+    getNodeInfo: {
+      request: {
+        selector: Arg(0, "string")
+      },
+      response: {
+        value: RetVal("json")
+      }
+    }
+  }
+});
+
+var TestActor = exports.TestActor = protocol.ActorClass(testSpec, {
   initialize: function (conn, tabActor, options) {
     this.conn = conn;
     this.tabActor = tabActor;
   },
 
   get content() {
     return this.tabActor.window;
   },
@@ -89,178 +305,127 @@ var TestActor = exports.TestActor = prot
       throw new Error("Unable to find element with selector \"" + selector + "\"");
     }
     return node;
   },
   /**
    * Helper to get the number of elements matching a selector
    * @param {string} CSS selector.
    */
-  getNumberOfElementMatches: protocol.method(function (selector,
-                                                       root = this.content.document) {
+  getNumberOfElementMatches: function (selector, root = this.content.document) {
     return root.querySelectorAll(selector).length;
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-    },
-    response: {
-      value: RetVal("number")
-    }
-  }),
+  },
 
   /**
    * Get a value for a given attribute name, on one of the elements of the box
    * model highlighter, given its ID.
    * @param {Object} msg The msg.data part expects the following properties
    * - {String} nodeID The full ID of the element to get the attribute for
    * - {String} name The name of the attribute to get
    * - {String} actorID The highlighter actor ID
    * @return {String} The value, if found, null otherwise
    */
-  getHighlighterAttribute: protocol.method(function (nodeID, name, actorID) {
+  getHighlighterAttribute: function (nodeID, name, actorID) {
     let helper = getHighlighterCanvasFrameHelper(this.conn, actorID);
     if (helper) {
       return helper.getAttributeForElement(nodeID, name);
     }
-  }, {
-    request: {
-      nodeID: Arg(0, "string"),
-      name: Arg(1, "string"),
-      actorID: Arg(2, "string")
-    },
-    response: {
-      value: RetVal("string")
-    }
-  }),
+  },
 
   /**
    * Get the textcontent of one of the elements of the box model highlighter,
    * given its ID.
    * @param {String} nodeID The full ID of the element to get the attribute for
    * @param {String} actorID The highlighter actor ID
    * @return {String} The textcontent value
    */
-  getHighlighterNodeTextContent: protocol.method(function (nodeID, actorID) {
+  getHighlighterNodeTextContent: function (nodeID, actorID) {
     let value;
     let helper = getHighlighterCanvasFrameHelper(this.conn, actorID);
     if (helper) {
       value = helper.getTextContentForElement(nodeID);
     }
     return value;
-  }, {
-    request: {
-      nodeID: Arg(0, "string"),
-      actorID: Arg(1, "string")
-    },
-    response: {
-      value: RetVal("string")
-    }
-  }),
+  },
 
   /**
    * Get the number of box-model highlighters created by the SelectorHighlighter
    * @param {String} actorID The highlighter actor ID
    * @return {Number} The number of box-model highlighters created, or null if the
    * SelectorHighlighter was not found.
    */
-  getSelectorHighlighterBoxNb: protocol.method(function (actorID) {
+  getSelectorHighlighterBoxNb: function (actorID) {
     let highlighter = this.conn.getActor(actorID);
     let {_highlighter: h} = highlighter;
     if (!h || !h._highlighters) {
       return null;
     } else {
       return h._highlighters.length;
     }
-  }, {
-    request: {
-      highlighter: Arg(0, "string"),
-    },
-    response: {
-      value: RetVal("number")
-    }
-  }),
+  },
 
   /**
    * Subscribe to the box-model highlighter's update event, modify an attribute of
    * the currently highlighted node and send a message when the highlighter has
    * updated.
    * @param {String} the name of the attribute to be changed
    * @param {String} the new value for the attribute
    * @param {String} actorID The highlighter actor ID
    */
-  changeHighlightedNodeWaitForUpdate: protocol.method(function (name, value, actorID) {
+  changeHighlightedNodeWaitForUpdate: function (name, value, actorID) {
     let deferred = defer();
 
     let highlighter = this.conn.getActor(actorID);
     let {_highlighter: h} = highlighter;
 
     h.once("updated", () => {
       deferred.resolve();
     });
 
     h.currentNode.setAttribute(name, value);
 
     return deferred.promise;
-  }, {
-    request: {
-      name: Arg(0, "string"),
-      value: Arg(1, "string"),
-      actorID: Arg(2, "string")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Subscribe to a given highlighter event and respond when the event is received.
    * @param {String} event The name of the highlighter event to listen to
    * @param {String} actorID The highlighter actor ID
    */
-  waitForHighlighterEvent: protocol.method(function (event, actorID) {
+  waitForHighlighterEvent: function (event, actorID) {
     let highlighter = this.conn.getActor(actorID);
     let {_highlighter: h} = highlighter;
 
     return h.once(event);
-  }, {
-    request: {
-      event: Arg(0, "string"),
-      actorID: Arg(1, "string")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Wait for a specific event on a node matching the provided selector.
    * @param {String} eventName The name of the event to listen to
    * @param {String} selector Optional:  css selector of the node which should
    *        trigger the event. If ommitted, target will be the content window
    */
-  waitForEventOnNode: protocol.method(function (eventName, selector) {
+  waitForEventOnNode: function (eventName, selector) {
     return new Promise(resolve => {
       let node = selector ? this._querySelector(selector) : this.content;
       node.addEventListener(eventName, function onEvent() {
         node.removeEventListener(eventName, onEvent);
         resolve();
       });
     });
-  }, {
-    request: {
-      eventName: Arg(0, "string"),
-      selector: Arg(1, "nullable:string")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Change the zoom level of the page.
    * Optionally subscribe to the box-model highlighter's update event and waiting
    * for it to refresh before responding.
    * @param {Number} level The new zoom level
    * @param {String} actorID Optional. The highlighter actor ID
    */
-  changeZoomLevel: protocol.method(function (level, actorID) {
+  changeZoomLevel: function (level, actorID) {
     dumpn("Zooming page to " + level);
     let deferred = defer();
 
     if (actorID) {
       let actor = this.conn.getActor(actorID);
       let {_highlighter: h} = actor;
       h.once("updated", () => {
         deferred.resolve();
@@ -270,399 +435,272 @@ var TestActor = exports.TestActor = prot
     }
 
     let docShell = this.content.QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsIDocShell);
     docShell.contentViewer.fullZoom = level;
 
     return deferred.promise;
-  }, {
-    request: {
-      level: Arg(0, "string"),
-      actorID: Arg(1, "string"),
-    },
-    response: {}
-  }),
+  },
 
-  assertElementAtPoint: protocol.method(function (x, y, selector) {
+  assertElementAtPoint: function (x, y, selector) {
     let elementAtPoint = getElementFromPoint(this.content.document, x, y);
     if (!elementAtPoint) {
       throw new Error("Unable to find element at (" + x + ", " + y + ")");
     }
     let node = this._querySelector(selector);
     return node == elementAtPoint;
-  }, {
-    request: {
-      x: Arg(0, "number"),
-      y: Arg(1, "number"),
-      selector: Arg(2, "string")
-    },
-    response: {
-      value: RetVal("boolean")
-    }
-  }),
-
+  },
 
   /**
    * Get all box-model regions' adjusted boxquads for the given element
    * @param {String} selector The node selector to target a given element
    * @return {Object} An object with each property being a box-model region, each
    * of them being an object with the p1/p2/p3/p4 properties
    */
-  getAllAdjustedQuads: protocol.method(function (selector) {
+  getAllAdjustedQuads: function (selector) {
     let regions = {};
     let node = this._querySelector(selector);
     for (let boxType of ["content", "padding", "border", "margin"]) {
       regions[boxType] = getAdjustedQuads(this.content, node, boxType);
     }
 
     return regions;
-  }, {
-    request: {
-      selector: Arg(0, "string")
-    },
-    response: {
-      value: RetVal("json")
-    }
-  }),
+  },
 
   /**
    * Synthesize a mouse event on an element, after ensuring that it is visible
    * in the viewport. This handler doesn't send a message back. Consumers
    * should listen to specific events on the inspector/highlighter to know when
    * the event got synthesized.
    * @param {String} selector The node selector to get the node target for the event
    * @param {Number} x
    * @param {Number} y
    * @param {Boolean} center If set to true, x/y will be ignored and
    *                  synthesizeMouseAtCenter will be used instead
    * @param {Object} options Other event options
    */
-  synthesizeMouse: protocol.method(function ({ selector, x, y, center, options }) {
+  synthesizeMouse: function ({ selector, x, y, center, options }) {
     let node = this._querySelector(selector);
     node.scrollIntoView();
     if (center) {
       EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView);
     } else {
       EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView);
     }
-  }, {
-    request: {
-      object: Arg(0, "json")
-    },
-    response: {}
-  }),
+  },
 
   /**
   * Synthesize a key event for an element. This handler doesn't send a message
   * back. Consumers should listen to specific events on the inspector/highlighter
   * to know when the event got synthesized.
   */
-  synthesizeKey: protocol.method(function ({key, options, content}) {
+  synthesizeKey: function ({key, options, content}) {
     EventUtils.synthesizeKey(key, options, this.content);
-  }, {
-    request: {
-      args: Arg(0, "json")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Check that an element currently has a pseudo-class lock.
    * @param {String} selector The node selector to get the pseudo-class from
    * @param {String} pseudo The pseudoclass to check for
    * @return {Boolean}
    */
-  hasPseudoClassLock: protocol.method(function (selector, pseudo) {
+  hasPseudoClassLock: function (selector, pseudo) {
     let node = this._querySelector(selector);
     return DOMUtils.hasPseudoClassLock(node, pseudo);
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-      pseudo: Arg(1, "string")
-    },
-    response: {
-      value: RetVal("boolean")
-    }
-  }),
+  },
 
-  loadAndWaitForCustomEvent: protocol.method(function (url) {
+  loadAndWaitForCustomEvent: function (url) {
     let deferred = defer();
     let self = this;
     // Wait for DOMWindowCreated first, as listening on the current outerwindow
     // doesn't allow receiving test-page-processing-done.
     this.tabActor.chromeEventHandler.addEventListener("DOMWindowCreated", function onWindowCreated() {
       self.tabActor.chromeEventHandler.removeEventListener("DOMWindowCreated", onWindowCreated);
       self.content.addEventListener("test-page-processing-done", function onEvent() {
         self.content.removeEventListener("test-page-processing-done", onEvent);
         deferred.resolve();
       });
     });
 
     this.content.location = url;
     return deferred.promise;
-  }, {
-    request: {
-      url: Arg(0, "string")
-    },
-    response: {}
-  }),
+  },
 
-  hasNode: protocol.method(function (selector) {
+  hasNode: function (selector) {
     try {
       // _querySelector throws if the node doesn't exists
       this._querySelector(selector);
       return true;
     } catch (e) {
       return false;
     }
-  }, {
-    request: {
-      selector: Arg(0, "string")
-    },
-    response: {
-      value: RetVal("boolean")
-    }
-  }),
+  },
 
   /**
    * Get the bounding rect for a given DOM node once.
    * @param {String} selector selector identifier to select the DOM node
    * @return {json} the bounding rect info
    */
-  getBoundingClientRect: protocol.method(function (selector) {
+  getBoundingClientRect: function (selector) {
     let node = this._querySelector(selector);
     return node.getBoundingClientRect();
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-    },
-    response: {
-      value: RetVal("json")
-    }
-  }),
+  },
 
   /**
    * Set a JS property on a DOM Node.
    * @param {String} selector The node selector
    * @param {String} property The property name
    * @param {String} value The attribute value
    */
-  setProperty: protocol.method(function (selector, property, value) {
+  setProperty: function (selector, property, value) {
     let node = this._querySelector(selector);
     node[property] = value;
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-      property: Arg(1, "string"),
-      value: Arg(2, "string")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Get a JS property on a DOM Node.
    * @param {String} selector The node selector
    * @param {String} property The property name
    * @return {String} value The attribute value
    */
-  getProperty: protocol.method(function (selector, property) {
+  getProperty: function (selector, property) {
     let node = this._querySelector(selector);
     return node[property];
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-      property: Arg(1, "string")
-    },
-    response: {
-      value: RetVal("string")
-    }
-  }),
+  },
 
   /**
    * Get an attribute on a DOM Node.
    * @param {String} selector The node selector
    * @param {String} attribute The attribute name
    * @return {String} value The attribute value
    */
-  getAttribute: protocol.method(function (selector, attribute) {
+  getAttribute: function (selector, attribute) {
     let node = this._querySelector(selector);
     return node.getAttribute(attribute);
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-      property: Arg(1, "string")
-    },
-    response: {
-      value: RetVal("string")
-    }
-  }),
+  },
 
   /**
    * Set an attribute on a DOM Node.
    * @param {String} selector The node selector
    * @param {String} attribute The attribute name
    * @param {String} value The attribute value
    */
-  setAttribute: protocol.method(function (selector, attribute, value) {
+  setAttribute: function (selector, attribute, value) {
     let node = this._querySelector(selector);
     node.setAttribute(attribute, value);
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-      property: Arg(1, "string"),
-      value: Arg(2, "string")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Remove an attribute from a DOM Node.
    * @param {String} selector The node selector
    * @param {String} attribute The attribute name
    */
-  removeAttribute: protocol.method(function (selector, attribute) {
+  removeAttribute: function (selector, attribute) {
     let node = this._querySelector(selector);
     node.removeAttribute(attribute);
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-      property: Arg(1, "string")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Reload the content window.
    */
-  reload: protocol.method(function () {
+  reload: function () {
     this.content.location.reload();
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Reload an iframe and wait for its load event.
    * @param {String} selector The node selector
    */
-  reloadFrame: protocol.method(function (selector) {
+  reloadFrame: function (selector) {
     let node = this._querySelector(selector);
 
     let deferred = defer();
 
     let onLoad = function () {
       node.removeEventListener("load", onLoad);
       deferred.resolve();
     };
     node.addEventListener("load", onLoad);
 
     node.contentWindow.location.reload();
     return deferred.promise;
-  }, {
-    request: {
-      selector: Arg(0, "string"),
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Evaluate a JS string in the context of the content document.
    * @param {String} js JS string to evaluate
    * @return {json} The evaluation result
    */
-  eval: protocol.method(function (js) {
+  eval: function (js) {
     // We have to use a sandbox, as CSP prevent us from using eval on apps...
     let sb = Cu.Sandbox(this.content, { sandboxPrototype: this.content });
     return Cu.evalInSandbox(js, sb);
-  }, {
-    request: {
-      js: Arg(0, "string")
-    },
-    response: {
-      value: RetVal("nullable:json")
-    }
-  }),
+  },
 
   /**
    * Scrolls the window to a particular set of coordinates in the document, or
    * by the given amount if `relative` is set to `true`.
    *
    * @param {Number} x
    * @param {Number} y
    * @param {Boolean} relative
    *
    * @return {Object} An object with x / y properties, representing the number
    * of pixels that the document has been scrolled horizontally and vertically.
    */
-  scrollWindow: protocol.method(function (x, y, relative) {
+  scrollWindow: function (x, y, relative) {
     if (isNaN(x) || isNaN(y)) {
       return {};
     }
 
     let deferred = defer();
     this.content.addEventListener("scroll", function onScroll(event) {
       this.removeEventListener("scroll", onScroll);
 
       let data = {x: this.content.scrollX, y: this.content.scrollY};
       deferred.resolve(data);
     });
 
     this.content[relative ? "scrollBy" : "scrollTo"](x, y);
 
     return deferred.promise;
-  }, {
-    request: {
-      x: Arg(0, "number"),
-      y: Arg(1, "number"),
-      relative: Arg(2, "nullable:boolean"),
-    },
-    response: {
-      value: RetVal("json")
-    }
-  }),
+  },
 
   /**
    * Forces the reflow and waits for the next repaint.
    */
-  reflow: protocol.method(function () {
+  reflow: function () {
     let deferred = defer();
     this.content.document.documentElement.offsetWidth;
     this.content.requestAnimationFrame(deferred.resolve);
 
     return deferred.promise;
-  }),
+  },
 
-  getNodeRect: protocol.method(Task.async(function* (selector) {
+  getNodeRect: Task.async(function* (selector) {
     let node = this._querySelector(selector);
     return getRect(this.content, node, this.content);
-  }), {
-    request: {
-      selector: Arg(0, "string")
-    },
-    response: {
-      value: RetVal("json")
-    }
   }),
 
   /**
    * Get information about a DOM element, identified by a selector.
    * @param {String} selector The CSS selector to get the node (can be an array
    * of selectors to get elements in an iframe).
    * @return {Object} data Null if selector didn't match any node, otherwise:
    * - {String} tagName.
    * - {String} namespaceURI.
    * - {Number} numChildren The number of children in the element.
    * - {Array} attributes An array of {name, value, namespaceURI} objects.
    * - {String} outerHTML.
    * - {String} innerHTML.
    * - {String} textContent.
    */
-  getNodeInfo: protocol.method(function (selector) {
+  getNodeInfo: function (selector) {
     let node = this._querySelector(selector);
     let info = null;
 
     if (node) {
       info = {
         tagName: node.tagName,
         namespaceURI: node.namespaceURI,
         numChildren: node.children.length,
@@ -671,27 +709,20 @@ var TestActor = exports.TestActor = prot
         }),
         outerHTML: node.outerHTML,
         innerHTML: node.innerHTML,
         textContent: node.textContent
       };
     }
 
     return info;
-  }, {
-    request: {
-      selector: Arg(0, "string")
-    },
-    response: {
-      value: RetVal("json")
-    }
-  })
+  }
 });
 
-var TestActorFront = exports.TestActorFront = protocol.FrontClass(TestActor, {
+var TestActorFront = exports.TestActorFront = protocol.FrontClass(testSpec, {
   initialize: function (client, { testActor }, toolbox) {
     protocol.Front.prototype.initialize.call(this, client, { actor: testActor });
     this.manage(this);
     this.toolbox = toolbox;
   },
 
   /**
    * Zoom the current page to a given level.
--- a/devtools/client/themes/inspector.css
+++ b/devtools/client/themes/inspector.css
@@ -22,16 +22,28 @@
 
 #inspector-toolbar.devtools-toolbar .devtools-toolbar-spacer {
   flex-grow: 1;
   display: inline-block;
 }
 
 #inspector-searchlabel {
   overflow: hidden;
+  margin-inline-end: 2px;
+}
+
+#inspector-search {
+  flex: unset;
+}
+
+/* TODO: bug 1265759: should apply to .devtools-searchinput once all searchbox
+   is converted to html*/
+#inspector-searchbox {
+  flex: 1;
+  width: 100%;
 }
 
 /* Make sure the text is vertically centered in Inspector's
    search box. This can be removed when the search box is
    switched to HTML.
    See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1265759 */
 .theme-dark #inspector-searchbox,
 .theme-light #inspector-searchbox {
--- a/devtools/client/webconsole/test/browser_webconsole_split_focus.js
+++ b/devtools/client/webconsole/test/browser_webconsole_split_focus.js
@@ -21,38 +21,34 @@
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(!toolbox.splitConsole, "Split console is hidden by default");
 
     info("Focusing the search box before opening the split console");
     let inspector = toolbox.getPanel("inspector");
     inspector.searchBox.focus();
 
-    // Use the binding element since inspector.searchBox is a XUL element.
     let activeElement = getActiveElement(inspector.panelDoc);
-    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
     is(activeElement, inspector.searchBox, "Search box is focused");
 
     yield toolbox.openSplitConsole();
 
     ok(toolbox.splitConsole, "Split console is now visible");
 
     // Use the binding element since jsterm.inputNode is a XUL textarea element.
     activeElement = getActiveElement(toolbox.doc);
     activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
     let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
     is(activeElement, inputNode, "Split console input is focused by default");
 
     yield toolbox.closeSplitConsole();
 
     info("Making sure that the search box is refocused after closing the " +
          "split console");
-    // Use the binding element since inspector.searchBox is a XUL element.
     activeElement = getActiveElement(inspector.panelDoc);
-    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
     is(activeElement, inspector.searchBox, "Search box is focused");
 
     yield toolbox.destroy();
   }
 
   function getActiveElement(doc) {
     let activeElement = doc.activeElement;
     while (activeElement && activeElement.contentDocument) {
--- a/devtools/server/actors/actor-registry.js
+++ b/devtools/server/actors/actor-registry.js
@@ -12,33 +12,33 @@ const Services = require("Services");
 const { DebuggerServer } = require("devtools/server/main");
 const { registerActor, unregisterActor } = require("devtools/server/actors/utils/actor-registry-utils");
 const { actorActorSpec, actorRegistrySpec } = require("devtools/shared/specs/actor-registry");
 
 /**
  * The ActorActor gives you a handle to an actor you've dynamically
  * registered and allows you to unregister it.
  */
-const ActorActor = protocol.ActorClassWithSpec(actorActorSpec, {
+const ActorActor = protocol.ActorClass(actorActorSpec, {
   initialize: function (conn, options) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this.options = options;
   },
 
   unregister: function () {
     unregisterActor(this.options);
   }
 });
 
 /*
  * The ActorRegistryActor allows clients to define new actors on the
  * server. This is particularly useful for addons.
  */
-const ActorRegistryActor = protocol.ActorClassWithSpec(actorRegistrySpec, {
+const ActorRegistryActor = protocol.ActorClass(actorRegistrySpec, {
   initialize: function (conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
   },
 
   registerActor: function (sourceText, fileName, options) {
     return registerActor(sourceText, fileName, options).then(() => {
       let { constructor, type } = options;
 
--- a/devtools/server/actors/addons.js
+++ b/devtools/server/actors/addons.js
@@ -5,17 +5,17 @@
 "use strict";
 
 const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");
 const protocol = require("devtools/shared/protocol");
 const {FileUtils} = require("resource://gre/modules/FileUtils.jsm");
 const {Task} = require("devtools/shared/task");
 const {addonsSpec} = require("devtools/shared/specs/addons");
 
-const AddonsActor = protocol.ActorClassWithSpec(addonsSpec, {
+const AddonsActor = protocol.ActorClass(addonsSpec, {
 
   initialize: function (conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
   },
 
   installTemporaryAddon: Task.async(function* (addonPath) {
     let addonFile;
     let addon;
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -24,18 +24,17 @@
  * - WebAnimation WebIDL files:
  *   /dom/webidl/Animation*.webidl
  */
 
 const {Cu} = require("chrome");
 const promise = require("promise");
 const {Task} = require("devtools/shared/task");
 const protocol = require("devtools/shared/protocol");
-const {ActorClass, Actor, FrontClass, Front,
-       Arg, method, RetVal, types} = protocol;
+const {Actor, ActorClass} = protocol;
 const {animationPlayerSpec, animationsSpec} = require("devtools/shared/specs/animation");
 const events = require("sdk/event/core");
 
 // Types of animations.
 const ANIMATION_TYPES = {
   CSS_ANIMATION: "cssanimation",
   CSS_TRANSITION: "csstransition",
   SCRIPT_ANIMATION: "scriptanimation",
@@ -47,17 +46,17 @@ exports.ANIMATION_TYPES = ANIMATION_TYPE
  * The AnimationPlayerActor provides information about a given animation: its
  * startTime, currentTime, current state, etc.
  *
  * Since the state of a player changes as the animation progresses it is often
  * useful to call getCurrentState at regular intervals to get the current state.
  *
  * This actor also allows playing, pausing and seeking the animation.
  */
-var AnimationPlayerActor = protocol.ActorClassWithSpec(animationPlayerSpec, {
+var AnimationPlayerActor = protocol.ActorClass(animationPlayerSpec, {
   /**
    * @param {AnimationsActor} The main AnimationsActor instance
    * @param {AnimationPlayer} The player object returned by getAnimationPlayers
    */
   initialize: function (animationsActor, player) {
     Actor.prototype.initialize.call(this, animationsActor.conn);
 
     this.onAnimationMutation = this.onAnimationMutation.bind(this);
@@ -429,17 +428,17 @@ var AnimationPlayerActor = protocol.Acto
   }
 });
 
 exports.AnimationPlayerActor = AnimationPlayerActor;
 
 /**
  * The Animations actor lists animation players for a given node.
  */
-var AnimationsActor = exports.AnimationsActor = protocol.ActorClassWithSpec(animationsSpec, {
+var AnimationsActor = exports.AnimationsActor = protocol.ActorClass(animationsSpec, {
   initialize: function(conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
 
     this.onWillNavigate = this.onWillNavigate.bind(this);
     this.onNavigate = this.onNavigate.bind(this);
     this.onAnimationMutation = this.onAnimationMutation.bind(this);
 
--- a/devtools/server/actors/breakpoint.js
+++ b/devtools/server/actors/breakpoint.js
@@ -1,17 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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 { ActorClassWithSpec } = require("devtools/shared/protocol");
+const { ActorClass } = require("devtools/shared/protocol");
 const { breakpointSpec } = require("devtools/shared/specs/breakpoint");
 
 /**
  * Set breakpoints on all the given entry points with the given
  * BreakpointActor as the handler.
  *
  * @param BreakpointActor actor
  *        The actor handling the breakpoint hits.
@@ -29,17 +29,17 @@ function setBreakpointAtEntryPoints(acto
 
 exports.setBreakpointAtEntryPoints = setBreakpointAtEntryPoints;
 
 /**
  * BreakpointActors exist for the lifetime of their containing thread and are
  * responsible for deleting breakpoints, handling breakpoint hits and
  * associating breakpoints with scripts.
  */
-let BreakpointActor = ActorClassWithSpec(breakpointSpec, {
+let BreakpointActor = ActorClass(breakpointSpec, {
   /**
    * Create a Breakpoint actor.
    *
    * @param ThreadActor threadActor
    *        The parent thread actor that contains this breakpoint.
    * @param OriginalLocation originalLocation
    *        The original location of the breakpoint.
    */
--- a/devtools/server/actors/call-watcher.js
+++ b/devtools/server/actors/call-watcher.js
@@ -13,17 +13,17 @@ const {method, Arg, Option, RetVal} = pr
 
 const { functionCallSpec, callWatcherSpec } = require("devtools/shared/specs/call-watcher");
 const { CallWatcherFront } = require("devtools/shared/fronts/call-watcher");
 
 /**
  * This actor contains information about a function call, like the function
  * type, name, stack, arguments, returned value etc.
  */
-var FunctionCallActor = protocol.ActorClassWithSpec(functionCallSpec, {
+var FunctionCallActor = protocol.ActorClass(functionCallSpec, {
   /**
    * Creates the function call actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param DOMWindow window
    *        The content window.
    * @param string global
@@ -221,17 +221,17 @@ var FunctionCallActor = protocol.ActorCl
     }
     return data + "";
   }
 });
 
 /**
  * This actor observes function calls on certain objects or globals.
  */
-var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClassWithSpec(callWatcherSpec, {
+var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass(callWatcherSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._onGlobalCreated = this._onGlobalCreated.bind(this);
     this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
     this._onContentFunctionCall = this._onContentFunctionCall.bind(this);
     on(this.tabActor, "window-ready", this._onGlobalCreated);
     on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
--- a/devtools/server/actors/canvas.js
+++ b/devtools/server/actors/canvas.js
@@ -25,17 +25,17 @@ const {CanvasFront} = require("devtools/
 const {on, once, off, emit} = events;
 const {method, custom, Arg, Option, RetVal} = protocol;
 
 /**
  * This actor represents a recorded animation frame snapshot, along with
  * all the corresponding canvas' context methods invoked in that frame,
  * thumbnails for each draw call and a screenshot of the end result.
  */
-var FrameSnapshotActor = protocol.ActorClassWithSpec(frameSnapshotSpec, {
+var FrameSnapshotActor = protocol.ActorClass(frameSnapshotSpec, {
   /**
    * Creates the frame snapshot call actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param HTMLCanvasElement canvas
    *        A reference to the content canvas.
    * @param array calls
@@ -115,17 +115,17 @@ var FrameSnapshotActor = protocol.ActorC
   }
 });
 
 /**
  * This Canvas Actor handles simple instrumentation of all the methods
  * of a 2D or WebGL context, to provide information regarding all the calls
  * made when drawing frame inside an animation loop.
  */
-var CanvasActor = exports.CanvasActor = protocol.ActorClassWithSpec(canvasSpec, {
+var CanvasActor = exports.CanvasActor = protocol.ActorClass(canvasSpec, {
   // Reset for each recording, boolean indicating whether or not
   // any draw calls were called for a recording.
   _animationContainsDrawCall: false,
 
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._webGLPrimitiveCounter = new WebGLPrimitiveCounter(tabActor);
--- a/devtools/server/actors/common.js
+++ b/devtools/server/actors/common.js
@@ -506,16 +506,16 @@ function actorBridge(methodName, definit
   return method(function () {
     return this.bridge[methodName].apply(this.bridge, arguments);
   }, definition);
 }
 exports.actorBridge = actorBridge;
 
 /**
  * Like `actorBridge`, but without a spec definition, for when the actor is
- * created with `ActorClassWithSpec` rather than vanilla `ActorClass`.
+ * created with `ActorClass` rather than vanilla `ActorClass`.
  */
 function actorBridgeWithSpec (methodName) {
   return method(function () {
     return this.bridge[methodName].apply(this.bridge, arguments);
   });
 }
 exports.actorBridgeWithSpec = actorBridgeWithSpec;
--- a/devtools/server/actors/css-properties.js
+++ b/devtools/server/actors/css-properties.js
@@ -10,22 +10,22 @@ loader.lazyGetter(this, "DOMUtils", () =
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
 
 loader.lazyGetter(this, "appInfo", () => {
   return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
 });
 
 const protocol = require("devtools/shared/protocol");
-const { ActorClassWithSpec, Actor } = protocol;
+const { ActorClass, Actor } = protocol;
 const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
 const { CSS_PROPERTIES, CSS_TYPES } = require("devtools/shared/css-properties-db");
 const { cssColors } = require("devtools/shared/css-color-db");
 
-exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
+exports.CssPropertiesActor = ActorClass(cssPropertiesSpec, {
   typeName: "cssProperties",
 
   initialize(conn, parent) {
     Actor.prototype.initialize.call(this, conn);
     this.parent = parent;
   },
 
   destroy() {
--- a/devtools/server/actors/csscoverage.js
+++ b/devtools/server/actors/csscoverage.js
@@ -62,17 +62,17 @@ const l10n = exports.l10n = {
  *         cssText: "p.quote { color: red; }",
  *         isUsed: true,
  *         presentOn: Set([ "http://eg.com/page1.html", ... ]),
  *         preLoadOn: Set([ "http://eg.com/page1.html" ]),
  *         isError: false,
  *       }, ...
  *     });
  */
-var CSSUsageActor = protocol.ActorClassWithSpec(cssUsageSpec, {
+var CSSUsageActor = protocol.ActorClass(cssUsageSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this._tabActor = tabActor;
     this._running = false;
 
     this._onTabLoad = this._onTabLoad.bind(this);
     this._onChange = this._onChange.bind(this);
--- a/devtools/server/actors/device.js
+++ b/devtools/server/actors/device.js
@@ -10,17 +10,17 @@ const protocol = require("devtools/share
 const promise = require("promise");
 const {LongStringActor} = require("devtools/server/actors/string");
 const {DebuggerServer} = require("devtools/server/main");
 const {getSystemInfo, getSetting} = require("devtools/shared/system");
 const {deviceSpec} = require("devtools/shared/specs/device");
 const FileReader = require("FileReader");
 const {PermissionsTable} = require("resource://gre/modules/PermissionsTable.jsm");
 
-var DeviceActor = exports.DeviceActor = protocol.ActorClassWithSpec(deviceSpec, {
+var DeviceActor = exports.DeviceActor = protocol.ActorClass(deviceSpec, {
   _desc: null,
 
   getDescription: function () {
     return getSystemInfo();
   },
 
   getWallpaper: function () {
     let deferred = promise.defer();
--- a/devtools/server/actors/director-manager.js
+++ b/devtools/server/actors/director-manager.js
@@ -33,17 +33,17 @@ const ERR_MESSAGEPORT_FINALIZED = "messa
 
 const ERR_DIRECTOR_UNKNOWN_SCRIPTID = "unkown director-script id";
 const ERR_DIRECTOR_UNINSTALLED_SCRIPTID = "uninstalled director-script id";
 
 /**
  * A MessagePort Actor allowing communication through messageport events
  * over the remote debugging protocol.
  */
-var MessagePortActor = exports.MessagePortActor = protocol.ActorClassWithSpec(messagePortSpec, {
+var MessagePortActor = exports.MessagePortActor = protocol.ActorClass(messagePortSpec, {
   /**
    * Create a MessagePort actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param MessagePort port
    *        The wrapped MessagePort.
    */
@@ -144,17 +144,17 @@ var MessagePortActor = exports.MessagePo
  *
  * After retrieving an instance of this actor (from the tab director actor), you'll need to set it up
  * by calling setup().
  *
  * After the setup, this actor will automatically attach/detach the content script (and optionally a
  * directly connect the debugger client and the content script using a MessageChannel) on tab
  * navigation.
  */
-var DirectorScriptActor = exports.DirectorScriptActor = protocol.ActorClassWithSpec(directorScriptSpec, {
+var DirectorScriptActor = exports.DirectorScriptActor = protocol.ActorClass(directorScriptSpec, {
   /**
    * Creates the director script actor
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param Actor tabActor
    *        The tab (or root) actor.
    * @param String scriptId
@@ -332,17 +332,17 @@ var DirectorScriptActor = exports.Direct
       port: this._messagePortActor
     });
   }
 });
 
 /**
  * The DirectorManager Actor is a tab actor which manages enabling/disabling director scripts.
  */
-const DirectorManagerActor = exports.DirectorManagerActor = protocol.ActorClassWithSpec(directorManagerSpec, {
+const DirectorManagerActor = exports.DirectorManagerActor = protocol.ActorClass(directorManagerSpec, {
   /* init & destroy methods */
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._directorScriptActorsMap = new Map();
   },
   destroy: function (conn) {
     protocol.Actor.prototype.destroy.call(this, conn);
--- a/devtools/server/actors/director-registry.js
+++ b/devtools/server/actors/director-registry.js
@@ -150,17 +150,17 @@ exports.setupParentProcess = function se
     }
   }
 };
 
 /**
  * The DirectorRegistry Actor is a global actor which manages install/uninstall of
  * director scripts definitions.
  */
-const DirectorRegistryActor = exports.DirectorRegistryActor = protocol.ActorClassWithSpec(directorRegistrySpec, {
+const DirectorRegistryActor = exports.DirectorRegistryActor = protocol.ActorClass(directorRegistrySpec, {
   /* init & destroy methods */
   initialize: function (conn, parentActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.maybeSetupChildProcess(conn);
   },
   destroy: function (conn) {
     protocol.Actor.prototype.destroy.call(this, conn);
     this.finalize();
--- a/devtools/server/actors/environment.js
+++ b/devtools/server/actors/environment.js
@@ -1,30 +1,30 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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 { ActorClassWithSpec } = require("devtools/shared/protocol");
+const { ActorClass } = require("devtools/shared/protocol");
 const { createValueGrip } = require("devtools/server/actors/object");
 const { environmentSpec } = require("devtools/shared/specs/environment");
 
 /**
  * Creates an EnvironmentActor. EnvironmentActors are responsible for listing
  * the bindings introduced by a lexical environment and assigning new values to
  * those identifier bindings.
  *
  * @param Debugger.Environment aEnvironment
  *        The lexical environment that will be used to create the actor.
  * @param ThreadActor aThreadActor
  *        The parent thread actor that contains this environment.
  */
-let EnvironmentActor = ActorClassWithSpec(environmentSpec, {
+let EnvironmentActor = ActorClass(environmentSpec, {
   initialize: function (environment, threadActor) {
     this.obj = environment;
     this.threadActor = threadActor;
   },
 
   /**
    * Return an environment form for use in a protocol message.
    */
--- a/devtools/server/actors/eventlooplag.js
+++ b/devtools/server/actors/eventlooplag.js
@@ -8,21 +8,21 @@
  * The eventLoopLag actor emits "event-loop-lag" events when the event
  * loop gets unresponsive. The event comes with a "time" property (the
  * duration of the lag in milliseconds).
  */
 
 const {Ci} = require("chrome");
 const Services = require("Services");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
-const {Actor, ActorClassWithSpec} = require("devtools/shared/protocol");
+const {Actor, ActorClass} = require("devtools/shared/protocol");
 const events = require("sdk/event/core");
 const {eventLoopLagSpec} = require("devtools/shared/specs/eventlooplag");
 
-var EventLoopLagActor = exports.EventLoopLagActor = ActorClassWithSpec(eventLoopLagSpec, {
+var EventLoopLagActor = exports.EventLoopLagActor = ActorClass(eventLoopLagSpec, {
   _observerAdded: false,
 
   /**
    * Start tracking the event loop lags.
    */
   start: function () {
     if (!this._observerAdded) {
       Services.obs.addObserver(this, "event-loop-lag", false);
--- a/devtools/server/actors/frame.js
+++ b/devtools/server/actors/frame.js
@@ -3,23 +3,23 @@
 /* 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 { ActorPool } = require("devtools/server/actors/common");
 const { createValueGrip } = require("devtools/server/actors/object");
-const { ActorClassWithSpec } = require("devtools/shared/protocol");
+const { ActorClass } = require("devtools/shared/protocol");
 const { frameSpec } = require("devtools/shared/specs/frame");
 
 /**
  * An actor for a specified stack frame.
  */
-let FrameActor = ActorClassWithSpec(frameSpec, {
+let FrameActor = ActorClass(frameSpec, {
   /**
    * Creates the Frame actor.
    *
    * @param frame Debugger.Frame
    *        The debuggee frame.
    * @param threadActor ThreadActor
    *        The parent thread actor for this frame.
    */
--- a/devtools/server/actors/framerate.js
+++ b/devtools/server/actors/framerate.js
@@ -1,26 +1,26 @@
 /* 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 { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
+const { Actor, ActorClass } = require("devtools/shared/protocol");
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { on, once, off, emit } = require("sdk/event/core");
 const { Framerate } = require("devtools/server/performance/framerate");
 const { framerateSpec } = require("devtools/shared/specs/framerate");
 
 /**
  * An actor wrapper around Framerate. Uses exposed
  * methods via bridge and provides RDP definitions.
  *
  * @see devtools/server/performance/framerate.js for documentation.
  */
-var FramerateActor = exports.FramerateActor = ActorClassWithSpec(framerateSpec, {
+var FramerateActor = exports.FramerateActor = ActorClass(framerateSpec, {
   initialize: function (conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.bridge = new Framerate(tabActor);
   },
   destroy: function (conn) {
     Actor.prototype.destroy.call(this, conn);
     this.bridge.destroy();
   },
--- a/devtools/server/actors/gcli.js
+++ b/devtools/server/actors/gcli.js
@@ -1,26 +1,26 @@
 /* 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 { Task } = require("devtools/shared/task");
 const {
-  method, Arg, Option, RetVal, Actor, ActorClassWithSpec
+  method, Arg, Option, RetVal, Actor, ActorClass
 } = require("devtools/shared/protocol");
 const { gcliSpec } = require("devtools/shared/specs/gcli");
 const events = require("sdk/event/core");
 const { createSystem } = require("gcli/system");
 
 /**
  * Manage remote connections that want to talk to GCLI
  */
-const GcliActor = ActorClassWithSpec(gcliSpec, {
+const GcliActor = ActorClass(gcliSpec, {
   initialize: function (conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
 
     this._commandsChanged = this._commandsChanged.bind(this);
 
     this._tabActor = tabActor;
     this._requisitionPromise = undefined; // see _getRequisition()
   },
--- a/devtools/server/actors/heap-snapshot-file.js
+++ b/devtools/server/actors/heap-snapshot-file.js
@@ -18,17 +18,17 @@ loader.lazyRequireGetter(this, "HeapSnap
                          "devtools/shared/heapsnapshot/HeapSnapshotFileUtils");
 
 /**
  * The HeapSnapshotFileActor handles transferring heap snapshot files from the
  * server to the client. This has to be a global actor in the parent process
  * because child processes are sandboxed and do not have access to the file
  * system.
  */
-exports.HeapSnapshotFileActor = protocol.ActorClassWithSpec(heapSnapshotFileSpec, {
+exports.HeapSnapshotFileActor = protocol.ActorClass(heapSnapshotFileSpec, {
   initialize: function (conn, parent) {
     if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
       const err = new Error("Attempt to create a HeapSnapshotFileActor in a " +
                             "child process! The HeapSnapshotFileActor *MUST* " +
                             "be in the parent process!");
       DevToolsUtils.reportException(
         "HeapSnapshotFileActor.prototype.initialize", err);
       return;
--- a/devtools/server/actors/highlighters.js
+++ b/devtools/server/actors/highlighters.js
@@ -77,17 +77,17 @@ exports.register = register;
  *
  * Other types of highlighter actors exist and can be accessed via the
  * InspectorActor's 'getHighlighterByType' method.
  */
 
 /**
  * The HighlighterActor class
  */
-var HighlighterActor = exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
+var HighlighterActor = exports.HighlighterActor = protocol.ActorClass(highlighterSpec, {
   initialize: function (inspector, autohide) {
     protocol.Actor.prototype.initialize.call(this, null);
 
     this._autohide = autohide;
     this._inspector = inspector;
     this._walker = this._inspector.walker;
     this._tabActor = this._inspector.tabActor;
     this._highlighterEnv = new HighlighterEnvironment();
@@ -402,17 +402,17 @@ var HighlighterActor = exports.Highlight
     }
   }
 });
 
 /**
  * A generic highlighter actor class that instantiate a highlighter given its
  * type name and allows to show/hide it.
  */
-var CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClassWithSpec(customHighlighterSpec, {
+var CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClass(customHighlighterSpec, {
   /**
    * Create a highlighter instance given its typename
    * The typename must be one of HIGHLIGHTER_CLASSES and the class must
    * implement constructor(tabActor), show(node), hide(), destroy()
    */
   initialize: function (inspector, typeName) {
     protocol.Actor.prototype.initialize.call(this, null);
 
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -192,17 +192,17 @@ exports.setInspectingNode = function (va
 const getNodeDisplayName = function (rawNode) {
   return (rawNode.prefix ? rawNode.prefix + ":" : "") + rawNode.localName;
 };
 exports.getNodeDisplayName = getNodeDisplayName;
 
 /**
  * Server side of the node actor.
  */
-var NodeActor = exports.NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
+var NodeActor = exports.NodeActor = protocol.ActorClass(nodeSpec, {
   initialize: function (walker, node) {
     protocol.Actor.prototype.initialize.call(this, null);
     this.walker = walker;
     this.rawNode = node;
     this._eventParsers = new EventParsers().parsers;
 
     // Storing the original display of the node, to track changes when reflows
     // occur
@@ -703,17 +703,17 @@ var NodeActor = exports.NodeActor = prot
 
     return { data: LongStringActor(this.conn, dataURL), size: size };
   }
 });
 
 /**
  * Server side of a node list as returned by querySelectorAll()
  */
-var NodeListActor = exports.NodeListActor = protocol.ActorClassWithSpec(nodeListSpec, {
+var NodeListActor = exports.NodeListActor = protocol.ActorClass(nodeListSpec, {
   typeName: "domnodelist",
 
   initialize: function (walker, nodeList) {
     protocol.Actor.prototype.initialize.call(this);
     this.walker = walker;
     this.nodeList = nodeList || [];
   },
 
@@ -761,17 +761,17 @@ var NodeListActor = exports.NodeListActo
   },
 
   release: function () {}
 });
 
 /**
  * Server side of the DOM walker.
  */
-var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
+var WalkerActor = protocol.ActorClass(walkerSpec, {
   /**
    * Create the WalkerActor
    * @param DebuggerServerConnection conn
    *    The server connection.
    */
   initialize: function (conn, tabActor, options) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
@@ -2573,17 +2573,17 @@ var WalkerActor = protocol.ActorClassWit
     return this.attachElement(obj);
   },
 });
 
 /**
  * Server side of the inspector actor, which is used to create
  * inspector-related actors, including the walker.
  */
-exports.InspectorActor = protocol.ActorClassWithSpec(inspectorSpec, {
+exports.InspectorActor = protocol.ActorClass(inspectorSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
 
     this._onColorPicked = this._onColorPicked.bind(this);
     this._onColorPickCanceled = this._onColorPickCanceled.bind(this);
     this.destroyEyeDropper = this.destroyEyeDropper.bind(this);
   },
--- a/devtools/server/actors/layout.js
+++ b/devtools/server/actors/layout.js
@@ -31,17 +31,17 @@ const {method, Arg} = protocol;
 const events = require("sdk/event/core");
 const Heritage = require("sdk/core/heritage");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {reflowSpec} = require("devtools/shared/specs/layout");
 
 /**
  * The reflow actor tracks reflows and emits events about them.
  */
-var ReflowActor = exports.ReflowActor = protocol.ActorClassWithSpec(reflowSpec, {
+var ReflowActor = exports.ReflowActor = protocol.ActorClass(reflowSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this.tabActor = tabActor;
     this._onReflow = this._onReflow.bind(this);
     this.observer = getLayoutChangesObserver(tabActor);
     this._isStarted = false;
   },
--- a/devtools/server/actors/memory.js
+++ b/devtools/server/actors/memory.js
@@ -18,17 +18,17 @@ loader.lazyRequireGetter(this, "StackFra
  * parent tab. A global-scoped instance however, will measure the memory
  * footprint of the chrome window referenced by the root actor.
  *
  * This actor wraps the Memory module at devtools/server/performance/memory.js
  * and provides RDP definitions.
  *
  * @see devtools/server/performance/memory.js for documentation.
  */
-exports.MemoryActor = protocol.ActorClassWithSpec(memorySpec, {
+exports.MemoryActor = protocol.ActorClass(memorySpec, {
   initialize: function (conn, parent, frameCache = new StackFrameCache()) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this._onGarbageCollection = this._onGarbageCollection.bind(this);
     this._onAllocations = this._onAllocations.bind(this);
     this.bridge = new Memory(parent, frameCache);
     this.bridge.on("garbage-collection", this._onGarbageCollection);
     this.bridge.on("allocations", this._onAllocations);
--- a/devtools/server/actors/performance-entries.js
+++ b/devtools/server/actors/performance-entries.js
@@ -4,60 +4,48 @@
 
 /**
  * The performanceEntries actor emits events corresponding to performance
  * entries. It receives `performanceentry` events containing the performance
  * entry details and emits an event containing the name, type, origin, and
  * epoch of the performance entry.
  */
 
-const {
-  method, Arg, Option, RetVal, Front, FrontClass, Actor, ActorClass
-} = require("devtools/shared/protocol");
+const { Actor, ActorClass } = require("devtools/shared/protocol");
+const performanceSpec = require("devtools/shared/specs/performance-entries");
 const events = require("sdk/event/core");
 
-var PerformanceEntriesActor = exports.PerformanceEntriesActor = ActorClass({
-
-  typeName: "performanceEntries",
-
+var PerformanceEntriesActor = ActorClass(performanceSpec, {
   listenerAdded: false,
 
-  events: {
-    "entry" : {
-      type: "entry",
-      detail: Arg(0, "json") // object containing performance entry name, type,
-                             // origin, and epoch.
-    }
-  },
-
   initialize: function (conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.window = tabActor.window;
   },
 
   /**
    * Start tracking the user timings.
    */
-  start: method(function () {
+  start: function () {
     if (!this.listenerAdded) {
       this.onPerformanceEntry = this.onPerformanceEntry.bind(this);
       this.window.addEventListener("performanceentry", this.onPerformanceEntry, true);
       this.listenerAdded = true;
     }
-  }),
+  },
 
   /**
    * Stop tracking the user timings.
    */
-  stop: method(function () {
+  stop: function () {
     if (this.listenerAdded) {
       this.window.removeEventListener("performanceentry", this.onPerformanceEntry, true);
       this.listenerAdded = false;
     }
-  }),
+  },
 
   disconnect: function () {
     this.destroy();
   },
 
   destroy: function () {
     this.stop();
     Actor.prototype.destroy.call(this);
@@ -69,15 +57,9 @@ var PerformanceEntriesActor = exports.Pe
       name: e.name,
       origin: e.origin,
       epoch: e.epoch
     };
     events.emit(this, "entry", emitDetail);
   }
 });
 
-exports.PerformanceEntriesFront = FrontClass(PerformanceEntriesActor, {
-  initialize: function (client, form) {
-    Front.prototype.initialize.call(this, client);
-    this.actorID = form.performanceEntriesActor;
-    this.manage(this);
-  },
-});
+exports.PerformanceEntriesActor = PerformanceEntriesActor;
--- a/devtools/server/actors/performance-recording.js
+++ b/devtools/server/actors/performance-recording.js
@@ -1,31 +1,31 @@
 /* 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 { Cu } = require("chrome");
-const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
+const { Actor, ActorClass } = require("devtools/shared/protocol");
 const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
 
 loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/shared/performance/recording-utils");
 loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
   "devtools/shared/performance/recording-common", true);
 
 /**
  * This actor wraps the Performance module at devtools/shared/shared/performance.js
  * and provides RDP definitions.
  *
  * @see devtools/shared/shared/performance.js for documentation.
  */
-const PerformanceRecordingActor = ActorClassWithSpec(performanceRecordingSpec, merge({
+const PerformanceRecordingActor = ActorClass(performanceRecordingSpec, merge({
   form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     let form = {
       actor: this.actorID,  // actorID is set when this is added to a pool
       configuration: this._configuration,
--- a/devtools/server/actors/performance.js
+++ b/devtools/server/actors/performance.js
@@ -1,17 +1,17 @@
 /* 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 { Cu } = require("chrome");
 const { Task } = require("devtools/shared/task");
-const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
+const { Actor, ActorClass } = require("devtools/shared/protocol");
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { performanceSpec } = require("devtools/shared/specs/performance");
 
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
 
 loader.lazyRequireGetter(this, "PerformanceRecorder",
   "devtools/server/performance/recorder", true);
@@ -28,17 +28,17 @@ const RECORDING_STATE_CHANGE_EVENTS = ne
 ]);
 
 /**
  * This actor wraps the Performance module at devtools/shared/shared/performance.js
  * and provides RDP definitions.
  *
  * @see devtools/shared/shared/performance.js for documentation.
  */
-var PerformanceActor = ActorClassWithSpec(performanceSpec, {
+var PerformanceActor = ActorClass(performanceSpec, {
   traits: {
     features: {
       withMarkers: true,
       withTicks: true,
       withMemory: true,
       withFrames: true,
       withGCEvents: true,
       withDocLoadingEvents: true,
--- a/devtools/server/actors/preference.js
+++ b/devtools/server/actors/preference.js
@@ -10,17 +10,17 @@ const {preferenceSpec} = require("devtoo
 
 exports.register = function (handle) {
   handle.addGlobalActor(PreferenceActor, "preferenceActor");
 };
 
 exports.unregister = function (handle) {
 };
 
-var PreferenceActor = exports.PreferenceActor = protocol.ActorClassWithSpec(preferenceSpec, {
+var PreferenceActor = exports.PreferenceActor = protocol.ActorClass(preferenceSpec, {
   typeName: "preference",
 
   getBoolPref: function (name) {
     return Services.prefs.getBoolPref(name);
   },
 
   getCharPref: function (name) {
     return Services.prefs.getCharPref(name);
--- a/devtools/server/actors/profiler.js
+++ b/devtools/server/actors/profiler.js
@@ -1,27 +1,27 @@
 /* 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 { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
+const { Actor, ActorClass } = require("devtools/shared/protocol");
 const { Profiler } = require("devtools/server/performance/profiler");
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { profilerSpec } = require("devtools/shared/specs/profiler");
 
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 
 /**
  * This actor wraps the Profiler module at devtools/server/performance/profiler.js
  * and provides RDP definitions.
  *
  * @see devtools/server/performance/profiler.js for documentation.
  */
-var ProfilerActor = exports.ProfilerActor = ActorClassWithSpec(profilerSpec, {
+var ProfilerActor = exports.ProfilerActor = ActorClass(profilerSpec, {
   initialize: function (conn) {
     Actor.prototype.initialize.call(this, conn);
     this._onProfilerEvent = this._onProfilerEvent.bind(this);
 
     this.bridge = new Profiler();
     events.on(this.bridge, "*", this._onProfilerEvent);
   },
 
--- a/devtools/server/actors/promises.js
+++ b/devtools/server/actors/promises.js
@@ -10,17 +10,17 @@ const { expectState, ActorPool } = requi
 const { ObjectActor, createValueGrip } = require("devtools/server/actors/object");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 
 /**
  * The Promises Actor provides support for getting the list of live promises and
  * observing changes to their settlement state.
  */
-var PromisesActor = protocol.ActorClassWithSpec(promisesSpec, {
+var PromisesActor = protocol.ActorClass(promisesSpec, {
   /**
    * @param conn DebuggerServerConnection.
    * @param parent TabActor|RootActor
    */
   initialize: function (conn, parent) {
     protocol.Actor.prototype.initialize.call(this, conn);
 
     this.conn = conn;
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -10,17 +10,17 @@ const Services = require("Services");
 const { Cc, Ci, Cu, Cr, components, ChromeWorker } = require("chrome");
 const { ActorPool, OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
 const { BreakpointActor, setBreakpointAtEntryPoints } = require("devtools/server/actors/breakpoint");
 const { EnvironmentActor } = require("devtools/server/actors/environment");
 const { FrameActor } = require("devtools/server/actors/frame");
 const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
 const { SourceActor, getSourceURL } = require("devtools/server/actors/source");
 const { DebuggerServer } = require("devtools/server/main");
-const { ActorClassWithSpec } = require("devtools/shared/protocol");
+const { ActorClass } = require("devtools/shared/protocol");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const flags = require("devtools/shared/flags");
 const { assert, dumpn, update, fetch } = DevToolsUtils;
 const promise = require("promise");
 const xpcInspector = require("xpcInspector");
 const { DevToolsWorker } = require("devtools/shared/worker/worker");
 const object = require("sdk/util/object");
 const { threadSpec } = require("devtools/shared/specs/script");
@@ -403,17 +403,17 @@ EventLoop.prototype = {
  *          - preNest: Function called before entering a nested event loop.
  *          - postNest: Function called after exiting a nested event loop.
  *          - makeDebugger: A function that takes no arguments and instantiates
  *            a Debugger that manages its globals on its own.
  * @param aGlobal object [optional]
  *        An optional (for content debugging only) reference to the content
  *        window.
  */
-const ThreadActor = ActorClassWithSpec(threadSpec, {
+const ThreadActor = ActorClass(threadSpec, {
   initialize: function (aParent, aGlobal) {
     this._state = "detached";
     this._frameActors = [];
     this._parent = aParent;
     this._dbg = null;
     this._gripDepth = 0;
     this._threadLifetimePool = null;
     this._tabClosed = false;
--- a/devtools/server/actors/settings.js
+++ b/devtools/server/actors/settings.js
@@ -59,17 +59,17 @@ function loadSettingsFile() {
     }
   }
 
   if (settingsFile.exists()) {
     getDefaultSettings();
   }
 }
 
-var SettingsActor = exports.SettingsActor = protocol.ActorClassWithSpec(settingsSpec, {
+var SettingsActor = exports.SettingsActor = protocol.ActorClass(settingsSpec, {
   _getSettingsService: function () {
     let win = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
     return win.navigator.mozSettings;
   },
 
   getSetting: function (name) {
     let deferred = promise.defer();
     let lock = this._getSettingsService().createLock();
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -6,17 +6,17 @@
 
 "use strict";
 
 const { Cc, Ci } = require("chrome");
 const Services = require("Services");
 const { BreakpointActor, setBreakpointAtEntryPoints } = require("devtools/server/actors/breakpoint");
 const { OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
 const { createValueGrip } = require("devtools/server/actors/object");
-const { ActorClassWithSpec, Arg, RetVal, method } = require("devtools/shared/protocol");
+const { ActorClass, Arg, RetVal, method } = require("devtools/shared/protocol");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { assert, fetch } = DevToolsUtils;
 const { joinURI } = require("devtools/shared/path");
 const promise = require("promise");
 const { defer, resolve, reject, all } = promise;
 const { sourceSpec } = require("devtools/shared/specs/source");
 
 loader.lazyRequireGetter(this, "SourceMapConsumer", "source-map", true);
@@ -136,17 +136,17 @@ function resolveURIToLocalPath(aURI) {
  * @param Debugger.Source generatedSource
  *        Optional, passed in when aSourceMap is also passed in. The generated
  *        source object that introduced this source.
  * @param Boolean isInlineSource
  *        Optional. True if this is an inline source from a HTML or XUL page.
  * @param String contentType
  *        Optional. The content type of this source, if immediately available.
  */
-let SourceActor = ActorClassWithSpec(sourceSpec, {
+let SourceActor = ActorClass(sourceSpec, {
   typeName: "source",
 
   initialize: function ({ source, thread, originalUrl, generatedSource,
                           isInlineSource, contentType }) {
     this._threadActor = thread;
     this._originalUrl = originalUrl;
     this._source = source;
     this._generatedSource = generatedSource;
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -374,17 +374,17 @@ StorageActors.createActor = function (op
     options.typeName,
     options.observationTopic || null
   );
   for (let key in overrides) {
     actorObject[key] = overrides[key];
   }
 
   let actorSpec = specs.childSpecs[options.typeName];
-  let actor = protocol.ActorClassWithSpec(actorSpec, actorObject);
+  let actor = protocol.ActorClass(actorSpec, actorObject);
   storageTypePool.set(actorObject.typeName, actor);
 };
 
 /**
  * The Cookies actor and front.
  */
 StorageActors.createActor({
   typeName: "cookies"
@@ -2164,17 +2164,17 @@ exports.setupParentProcessForIndexedDB =
     mm.removeMessageListener("storage:storage-indexedDB-request-parent",
                              indexedDBHelpers.handleChildRequest);
   }
 };
 
 /**
  * The main Storage Actor.
  */
-let StorageActor = protocol.ActorClassWithSpec(specs.storageSpec, {
+let StorageActor = protocol.ActorClass(specs.storageSpec, {
   typeName: "storage",
 
   get window() {
     return this.parentActor.window;
   },
 
   get document() {
     return this.parentActor.window.document;
--- a/devtools/server/actors/string.js
+++ b/devtools/server/actors/string.js
@@ -6,17 +6,17 @@
 
 var {DebuggerServer} = require("devtools/server/main");
 
 var promise = require("promise");
 
 var protocol = require("devtools/shared/protocol");
 const {longStringSpec} = require("devtools/shared/specs/string");
 
-exports.LongStringActor = protocol.ActorClassWithSpec(longStringSpec, {
+exports.LongStringActor = protocol.ActorClass(longStringSpec, {
   initialize: function (conn, str) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.str = str;
     this.short = (this.str.length < DebuggerServer.LONG_STRING_LENGTH);
   },
 
   destroy: function () {
     this.str = null;
--- a/devtools/server/actors/styleeditor.js
+++ b/devtools/server/actors/styleeditor.js
@@ -23,17 +23,17 @@ var TRANSITION_RULE = "\
 transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
 transition-delay: 0ms !important;\
 transition-timing-function: ease-out !important;\
 transition-property: all !important;\
 }";
 
 var LOAD_ERROR = "error-load";
 
-var OldStyleSheetActor = protocol.ActorClassWithSpec(oldStyleSheetSpec, {
+var OldStyleSheetActor = protocol.ActorClass(oldStyleSheetSpec, {
   toString: function() {
     return "[OldStyleSheetActor " + this.actorID + "]";
   },
 
   /**
    * Window of target
    */
   get window() {
@@ -316,17 +316,17 @@ var OldStyleSheetActor = protocol.ActorC
 });
 
 exports.OldStyleSheetActor = OldStyleSheetActor;
 
 /**
  * Creates a StyleEditorActor. StyleEditorActor provides remote access to the
  * stylesheets of a document.
  */
-var StyleEditorActor = exports.StyleEditorActor = protocol.ActorClassWithSpec(styleEditorSpec, {
+var StyleEditorActor = exports.StyleEditorActor = protocol.ActorClass(styleEditorSpec, {
   /**
    * The window we work with, taken from the parent actor.
    */
   get window() {
     return this.parentActor.window;
   },
 
   /**
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -34,17 +34,17 @@ const NORMAL_FONT_WEIGHT = 400;
 const BOLD_FONT_WEIGHT = 700;
 // Offset (in px) to avoid cutting off text edges of italic fonts.
 const FONT_PREVIEW_OFFSET = 4;
 
 /**
  * The PageStyle actor lets the client look at the styles on a page, as
  * they are applied to a given node.
  */
-var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, {
+var PageStyleActor = protocol.ActorClass(pageStyleSpec, {
   /**
    * Create a PageStyleActor.
    *
    * @param inspector
    *    The InspectorActor that owns this PageStyleActor.
    *
    * @constructor
    */
@@ -920,17 +920,17 @@ exports.PageStyleActor = PageStyleActor;
 /**
  * An actor that represents a CSS style object on the protocol.
  *
  * We slightly flatten the CSSOM for this actor, it represents
  * both the CSSRule and CSSStyle objects in one actor.  For nodes
  * (which have a CSSStyle but no CSSRule) we create a StyleRuleActor
  * with a special rule type (100).
  */
-var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
+var StyleRuleActor = protocol.ActorClass(styleRuleSpec, {
   initialize: function (pageStyle, item) {
     protocol.Actor.prototype.initialize.call(this, null);
     this.pageStyle = pageStyle;
     this.rawStyle = item.style;
     this._parentSheet = null;
     this._onStyleApplied = this._onStyleApplied.bind(this);
 
     if (item instanceof (Ci.nsIDOMCSSRule)) {
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -55,17 +55,17 @@ exports.UPDATE_GENERAL = UPDATE_GENERAL;
 // is used so that navigation by the user will eventually cause the
 // edited text to be collected.
 let modifiedStyleSheets = new WeakMap();
 
 /**
  * Actor representing an original source of a style sheet that was specified
  * in a source map.
  */
-var OriginalSourceActor = protocol.ActorClassWithSpec(originalSourceSpec, {
+var OriginalSourceActor = protocol.ActorClass(originalSourceSpec, {
   initialize: function (aUrl, aSourceMap, aParentActor) {
     protocol.Actor.prototype.initialize.call(this, null);
 
     this.url = aUrl;
     this.sourceMap = aSourceMap;
     this.parentActor = aParentActor;
     this.conn = this.parentActor.conn;
 
@@ -108,17 +108,17 @@ var OriginalSourceActor = protocol.Actor
     });
   }
 });
 
 /**
  * A MediaRuleActor lives on the server and provides access to properties
  * of a DOM @media rule and emits events when it changes.
  */
-var MediaRuleActor = protocol.ActorClassWithSpec(mediaRuleSpec, {
+var MediaRuleActor = protocol.ActorClass(mediaRuleSpec, {
   get window() {
     return this.parentActor.window;
   },
 
   get document() {
     return this.window.document;
   },
 
@@ -178,17 +178,17 @@ var MediaRuleActor = protocol.ActorClass
   _matchesChange: function () {
     events.emit(this, "matches-change", this.matches);
   }
 });
 
 /**
  * A StyleSheetActor represents a stylesheet on the server.
  */
-var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
+var StyleSheetActor = protocol.ActorClass(styleSheetSpec, {
   /* List of original sources that generated this stylesheet */
   _originalSources: null,
 
   toString: function () {
     return "[StyleSheetActor " + this.actorID + "]";
   },
 
   /**
@@ -781,17 +781,17 @@ var StyleSheetActor = protocol.ActorClas
 });
 
 exports.StyleSheetActor = StyleSheetActor;
 
 /**
  * Creates a StyleSheetsActor. StyleSheetsActor provides remote access to the
  * stylesheets of a document.
  */
-var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, {
+var StyleSheetsActor = protocol.ActorClass(styleSheetsSpec, {
   /**
    * The window we work with, taken from the parent actor.
    */
   get window() {
     return this.parentActor.window;
   },
 
   /**
--- a/devtools/server/actors/timeline.js
+++ b/devtools/server/actors/timeline.js
@@ -21,17 +21,17 @@ const { Option, RetVal } = protocol;
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { Timeline } = require("devtools/server/performance/timeline");
 const { timelineSpec } = require("devtools/shared/specs/timeline");
 const events = require("sdk/event/core");
 
 /**
  * The timeline actor pops and forwards timeline markers registered in docshells.
  */
-var TimelineActor = exports.TimelineActor = protocol.ActorClassWithSpec(timelineSpec, {
+var TimelineActor = exports.TimelineActor = protocol.ActorClass(timelineSpec, {
   /**
    * Initializes this actor with the provided connection and tab actor.
    */
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this.bridge = new Timeline(tabActor);
 
--- a/devtools/server/actors/webaudio.js
+++ b/devtools/server/actors/webaudio.js
@@ -33,17 +33,17 @@ const AUTOMATION_GRANULARITY_MAX = 6000;
 const AUDIO_GLOBALS = [
   "AudioContext", "AudioNode", "AudioParam"
 ];
 
 /**
  * An Audio Node actor allowing communication to a specific audio node in the
  * Audio Context graph.
  */
-var AudioNodeActor = exports.AudioNodeActor = protocol.ActorClassWithSpec(audionodeSpec, {
+var AudioNodeActor = exports.AudioNodeActor = protocol.ActorClass(audionodeSpec, {
   form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     return {
       actor: this.actorID, // actorID is set when this is added to a pool
       type: this.type,
@@ -399,17 +399,17 @@ var AudioNodeActor = exports.AudioNodeAc
   }
 });
 
 /**
  * The Web Audio Actor handles simple interaction with an AudioContext
  * high-level methods. After instantiating this actor, you'll need to set it
  * up by calling setup().
  */
-var WebAudioActor = exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
+var WebAudioActor = exports.WebAudioActor = protocol.ActorClass(webAudioSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
 
     this._onContentFunctionCall = this._onContentFunctionCall.bind(this);
 
     // Store ChromeOnly ID (`nativeID` property on AudioNodeActor) mapped
     // to the associated actorID, so we don't have to expose `nativeID`
--- a/devtools/server/actors/webgl.js
+++ b/devtools/server/actors/webgl.js
@@ -23,17 +23,17 @@ const PROGRAM_DEFAULT_TRAITS = 0;
 const PROGRAM_BLACKBOX_TRAIT = 1;
 const PROGRAM_HIGHLIGHT_TRAIT = 2;
 
 /**
  * A WebGL Shader contributing to building a WebGL Program.
  * You can either retrieve, or compile the source of a shader, which will
  * automatically inflict the necessary changes to the WebGL state.
  */
-var ShaderActor = protocol.ActorClassWithSpec(shaderSpec, {
+var ShaderActor = protocol.ActorClass(shaderSpec, {
   /**
    * Create the shader actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param WebGLProgram program
    *        The WebGL program being linked.
    * @param WebGLShader shader
@@ -78,17 +78,17 @@ var ShaderActor = protocol.ActorClassWit
     return undefined;
   }
 });
 
 /**
  * A WebGL program is composed (at the moment, analogue to OpenGL ES 2.0)
  * of two shaders: a vertex shader and a fragment shader.
  */
-var ProgramActor = protocol.ActorClassWithSpec(programSpec, {
+var ProgramActor = protocol.ActorClass(programSpec, {
   /**
    * Create the program actor.
    *
    * @param DebuggerServerConnection conn
    *        The server connection.
    * @param WebGLProgram program
    *        The WebGL program being linked.
    * @param WebGLShader[] shaders
@@ -179,17 +179,17 @@ var ProgramActor = protocol.ActorClassWi
   }
 });
 
 /**
  * The WebGL Actor handles simple interaction with a WebGL context via a few
  * high-level methods. After instantiating this actor, you'll need to set it
  * up by calling setup().
  */
-var WebGLActor = exports.WebGLActor = protocol.ActorClassWithSpec(webGLSpec, {
+var WebGLActor = exports.WebGLActor = protocol.ActorClass(webGLSpec, {
   initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this._onGlobalCreated = this._onGlobalCreated.bind(this);
     this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
     this._onProgramLinked = this._onProgramLinked.bind(this);
   },
   destroy: function (conn) {
--- a/devtools/server/actors/worker.js
+++ b/devtools/server/actors/worker.js
@@ -50,17 +50,17 @@ function matchWorkerDebugger(dbg, option
     if (window !== options.window) {
       return false;
     }
   }
 
   return true;
 }
 
-let WorkerActor = protocol.ActorClassWithSpec(workerSpec, {
+let WorkerActor = protocol.ActorClass(workerSpec, {
   initialize(conn, dbg) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this._dbg = dbg;
     this._attached = false;
     this._threadActor = null;
     this._transport = null;
   },
 
@@ -308,17 +308,17 @@ WorkerActorList.prototype = {
     if (matchWorkerDebugger(dbg, this._options)) {
       this._notifyListChanged();
     }
   }
 };
 
 exports.WorkerActorList = WorkerActorList;
 
-let PushSubscriptionActor = protocol.ActorClassWithSpec(pushSubscriptionSpec, {
+let PushSubscriptionActor = protocol.ActorClass(pushSubscriptionSpec, {
   initialize(conn, subscription) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this._subscription = subscription;
   },
 
   form(detail) {
     if (detail === "actorid") {
       return this.actorID;
@@ -338,17 +338,17 @@ let PushSubscriptionActor = protocol.Act
     this._subscription = null;
   },
 });
 
 // Lazily load the service-worker-child.js process script only once.
 let _serviceWorkerProcessScriptLoaded = false;
 
 let ServiceWorkerRegistrationActor =
-protocol.ActorClassWithSpec(serviceWorkerRegistrationSpec, {
+protocol.ActorClass(serviceWorkerRegistrationSpec, {
   /**
    * Create the ServiceWorkerRegistrationActor
    * @param DebuggerServerConnection conn
    *   The server connection.
    * @param ServiceWorkerRegistrationInfo registration
    *   The registration's information.
    */
   initialize(conn, registration) {
--- a/devtools/server/tests/mochitest/hello-actor.js
+++ b/devtools/server/tests/mochitest/hello-actor.js
@@ -9,17 +9,17 @@ const helloSpec = protocol.generateActor
   methods: {
     count: {
       request: {},
       response: {count: protocol.RetVal("number")}
     }
   }
 });
 
-var HelloActor = protocol.ActorClassWithSpec(helloSpec, {
+var HelloActor = protocol.ActorClass(helloSpec, {
   initialize: function () {
     protocol.Actor.prototype.initialize.apply(this, arguments);
     this.counter = 0;
   },
 
   count: function () {
     return ++this.counter;
   }
--- a/devtools/server/tests/unit/hello-actor.js
+++ b/devtools/server/tests/unit/hello-actor.js
@@ -6,13 +6,13 @@ const protocol = require("devtools/share
 const helloSpec = protocol.generateActorSpec({
   typeName: "helloActor",
 
   methods: {
     hello: {}
   }
 });
 
-var HelloActor = protocol.ActorClassWithSpec(helloSpec, {
+var HelloActor = protocol.ActorClass(helloSpec, {
   hello: function () {
     return;
   }
 });
--- a/devtools/server/tests/unit/registertestactors-03.js
+++ b/devtools/server/tests/unit/registertestactors-03.js
@@ -1,40 +1,40 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-var {method, RetVal, Actor, ActorClassWithSpec, Front, FrontClassWithSpec,
+var {method, RetVal, Actor, ActorClass, Front, FrontClass,
      generateActorSpec} = require("devtools/shared/protocol");
 var Services = require("Services");
 
 const lazySpec = generateActorSpec({
   typeName: "lazy",
 
   methods: {
     hello: {
       response: { str: RetVal("string") }
     }
   }
 });
 
-exports.LazyActor = ActorClassWithSpec(lazySpec, {
+exports.LazyActor = ActorClass(lazySpec, {
   initialize: function (conn, id) {
     Actor.prototype.initialize.call(this, conn);
 
     Services.obs.notifyObservers(null, "actor", "instantiated");
   },
 
   hello: function (str) {
     return "world";
   }
 });
 
 Services.obs.notifyObservers(null, "actor", "loaded");
 
-exports.LazyFront = FrontClassWithSpec(lazySpec, {
+exports.LazyFront = FrontClass(lazySpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client);
     this.actorID = form.lazyActor;
 
     client.addActorPool(this);
     this.manage(this);
   }
 });
--- a/devtools/server/tests/unit/test_protocol_abort.js
+++ b/devtools/server/tests/unit/test_protocol_abort.js
@@ -23,34 +23,34 @@ const rootSpec = protocol.generateActorS
 
   methods: {
     simpleReturn: {
       response: { value: RetVal() }
     }
   }
 });
 
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   typeName: "root",
   initialize: function (conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
     // Root actor owns itself.
     this.manage(this);
     this.actorID = "root";
     this.sequence = 0;
   },
 
   sayHello: simpleHello,
 
   simpleReturn: function () {
     return this.sequence++;
   }
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   initialize: function (client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
     // Root owns itself.
     this.manage(this);
   }
 });
 
--- a/devtools/server/tests/unit/test_protocol_async.js
+++ b/devtools/server/tests/unit/test_protocol_async.js
@@ -34,17 +34,17 @@ const rootSpec = protocol.generateActorS
       response: { value: RetVal("number") }
     },
     promiseThrow: {
       response: { value: RetVal("number") },
     }
   }
 });
 
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   initialize: function (conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
     // Root actor owns itself.
     this.manage(this);
     this.actorID = "root";
     this.sequence = 0;
   },
 
@@ -84,17 +84,17 @@ var RootActor = protocol.ActorClassWithS
     // This should be enough to force a failure if the code is broken.
     do_timeout(150, () => {
       deferred.reject(sequence++);
     });
     return deferred.promise;
   }
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   initialize: function (client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
     // Root owns itself.
     this.manage(this);
   }
 });
 
--- a/devtools/server/tests/unit/test_protocol_children.js
+++ b/devtools/server/tests/unit/test_protocol_children.js
@@ -83,17 +83,17 @@ const childSpec = protocol.generateActor
       response: { value: "correct response" },
     },
     release: {
       release: true
     }
   }
 });
 
-var ChildActor = protocol.ActorClassWithSpec(childSpec, {
+var ChildActor = protocol.ActorClass(childSpec, {
   // Actors returned by this actor should be owned by the root actor.
   marshallPool: function () { return this.parent(); },
 
   toString: function () { return "[ChildActor " + this.childID + "]"; },
 
   initialize: function (conn, id) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.childID = id;
@@ -151,17 +151,17 @@ var ChildActor = protocol.ActorClassWith
     events.emit(this, "named-event", 1, 2, 3);
     events.emit(this, "object-event", this);
     events.emit(this, "array-object-event", [this]);
   },
 
   release: function () { },
 });
 
-var ChildFront = protocol.FrontClassWithSpec(childSpec, {
+var ChildFront = protocol.FrontClass(childSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   },
 
   destroy: function () {
     this.destroyed = true;
     protocol.Front.prototype.destroy.call(this);
   },
@@ -221,17 +221,17 @@ const rootSpec = protocol.generateActorS
       request: { id: Arg(0) },
       response: { child: RetVal("temp:childActor") }
     },
     clearTemporaryChildren: {}
   }
 });
 
 var rootActor = null;
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   toString: function () { return "[root actor]"; },
 
   initialize: function (conn) {
     rootActor = this;
     this.actorID = "root";
     this._children = {};
     protocol.Actor.prototype.initialize.call(this, conn);
     // Root actor owns itself.
@@ -282,17 +282,17 @@ var RootActor = protocol.ActorClassWithS
     if (!this._temporaryHolder) {
       return;
     }
     this._temporaryHolder.destroy();
     delete this._temporaryHolder;
   }
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   toString: function () { return "[root front]"; },
   initialize: function (client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
     // Root actor owns itself.
     this.manage(this);
   },
 
--- a/devtools/server/tests/unit/test_protocol_formtype.js
+++ b/devtools/server/tests/unit/test_protocol_formtype.js
@@ -10,34 +10,34 @@ const childSpec = protocol.generateActor
   methods: {
     getChild: {
       response: RetVal("child")
     }
   }
 });
 
 // The child actor doesn't provide a form description
-var ChildActor = protocol.ActorClassWithSpec(childSpec, {
+var ChildActor = protocol.ActorClass(childSpec, {
   initialize(conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
   },
 
   form(detail) {
     return {
       actor: this.actorID,
       extra: "extra"
     };
   },
 
   getChild: function () {
     return this;
   }
 });
 
-var ChildFront = protocol.FrontClassWithSpec(childSpec, {
+var ChildFront = protocol.FrontClass(childSpec, {
   initialize(client) {
     protocol.Front.prototype.initialize.call(this, client);
   },
 
   form(v, ctx, detail) {
     this.extra = v.extra;
   }
 });
@@ -72,17 +72,17 @@ const rootSpec = protocol.generateActorS
     },
     getUnknownDetail: {
       response: RetVal("root#unknownDetail")
     }
   }
 });
 
 // The root actor does provide a form description.
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   initialize(conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.manage(this);
     this.child = new ChildActor();
   },
 
   sayHello() {
     return {
@@ -120,17 +120,17 @@ var RootActor = protocol.ActorClassWithS
     return this;
   },
 
   getUnknownDetail: function () {
     return this;
   }
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   initialize(client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
 
     // Root owns itself.
     this.manage(this);
   },
 
--- a/devtools/server/tests/unit/test_protocol_longstring.js
+++ b/devtools/server/tests/unit/test_protocol_longstring.js
@@ -44,17 +44,17 @@ const rootSpec = protocol.generateActorS
       oneway: true,
     },
     emitLongString: {
       oneway: true,
     }
   }
 });
 
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   initialize: function (conn) {
     rootActor = this;
     protocol.Actor.prototype.initialize.call(this, conn);
     // Root actor owns itself.
     this.manage(this);
     this.actorID = "root";
   },
 
@@ -72,17 +72,17 @@ var RootActor = protocol.ActorClassWithS
     events.emit(this, "string-event", new LongStringActor(this.conn, SHORT_STR));
   },
 
   emitLongString: function () {
     events.emit(this, "string-event", new LongStringActor(this.conn, LONG_STR));
   },
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   initialize: function (client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
     // Root owns itself.
     this.manage(this);
   }
 });
 
--- a/devtools/server/tests/unit/test_protocol_simple.js
+++ b/devtools/server/tests/unit/test_protocol_simple.js
@@ -96,17 +96,17 @@ const rootSpec = protocol.generateActorS
       oneway: true
     },
     emitFalsyOptions: {
       oneway: true
     }
   }
 });
 
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   initialize: function (conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
     // Root actor owns itself.
     this.manage(this);
     this.actorID = "root";
   },
 
   sayHello: simpleHello,
@@ -159,34 +159,34 @@ var RootActor = protocol.ActorClassWithS
     events.emit(this, "oneway", a);
   },
 
   emitFalsyOptions: function () {
     events.emit(this, "falsyOptions", { zero: 0, farce: false });
   }
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   initialize: function (client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
     // Root owns itself.
     this.manage(this);
   }
 });
 
 function run_test()
 {
   DebuggerServer.createRootActor = (conn => {
     return RootActor(conn);
   });
   DebuggerServer.init();
 
   check_except(() => {
-    let badActor = ActorClassWithSpec({}, {
+    let badActor = ActorClass({}, {
       missing: preEvent("missing-event", function () {
       })
     });
   });
 
   protocol.types.getType("array:array:array:number");
   protocol.types.getType("array:array:array:number");
 
--- a/devtools/server/tests/unit/test_protocol_stack.js
+++ b/devtools/server/tests/unit/test_protocol_stack.js
@@ -27,33 +27,33 @@ const rootSpec = protocol.generateActorS
 
   methods: {
     simpleReturn: {
       response: { value: RetVal() },
     }
   }
 });
 
-var RootActor = protocol.ActorClassWithSpec(rootSpec, {
+var RootActor = protocol.ActorClass(rootSpec, {
   initialize: function (conn) {
     protocol.Actor.prototype.initialize.call(this, conn);
     // Root actor owns itself.
     this.manage(this);
     this.actorID = "root";
     this.sequence = 0;
   },
 
   sayHello: simpleHello,
 
   simpleReturn: function () {
     return this.sequence++;
   }
 });
 
-var RootFront = protocol.FrontClassWithSpec(rootSpec, {
+var RootFront = protocol.FrontClass(rootSpec, {
   initialize: function (client) {
     this.actorID = "root";
     protocol.Front.prototype.initialize.call(this, client);
     // Root owns itself.
     this.manage(this);
   }
 });
 
--- a/devtools/shared/fronts/actor-registry.js
+++ b/devtools/shared/fronts/actor-registry.js
@@ -6,17 +6,17 @@
 const { components } = require("chrome");
 const Services = require("Services");
 const { actorActorSpec, actorRegistrySpec } = require("devtools/shared/specs/actor-registry");
 const protocol = require("devtools/shared/protocol");
 const { custom } = protocol;
 
 loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
 
-const ActorActorFront = protocol.FrontClassWithSpec(actorActorSpec, {
+const ActorActorFront = protocol.FrontClass(actorActorSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   }
 });
 
 exports.ActorActorFront = ActorActorFront;
 
 function request(uri) {
@@ -41,17 +41,17 @@ function request(uri) {
 
       let source = NetUtil.readInputStreamToString(stream, stream.available());
       stream.close();
       resolve(source);
     });
   });
 }
 
-const ActorRegistryFront = protocol.FrontClassWithSpec(actorRegistrySpec, {
+const ActorRegistryFront = protocol.FrontClass(actorRegistrySpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client,
                                              { actor: form.actorRegistryActor });
 
     this.manage(this);
   },
 
   registerActor: custom(function (uri, options) {
--- a/devtools/shared/fronts/addons.js
+++ b/devtools/shared/fronts/addons.js
@@ -1,17 +1,17 @@
 /* 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 {addonsSpec} = require("devtools/shared/specs/addons");
 const protocol = require("devtools/shared/protocol");
 
-const AddonsFront = protocol.FrontClassWithSpec(addonsSpec, {
+const AddonsFront = protocol.FrontClass(addonsSpec, {
   initialize: function (client, {addonsActor}) {
     protocol.Front.prototype.initialize.call(this, client);
     this.actorID = addonsActor;
     this.manage(this);
   }
 });
 
 exports.AddonsFront = AddonsFront;
--- a/devtools/shared/fronts/animation.js
+++ b/devtools/shared/fronts/animation.js
@@ -1,26 +1,26 @@
 /* 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 {
   Front,
-  FrontClassWithSpec,
+  FrontClass,
   custom,
   preEvent
 } = require("devtools/shared/protocol");
 const {
   animationPlayerSpec,
   animationsSpec
 } = require("devtools/shared/specs/animation");
 const { Task } = require("devtools/shared/task");
 
-const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
+const AnimationPlayerFront = FrontClass(animationPlayerSpec, {
   initialize: function (conn, form, detail, ctx) {
     Front.prototype.initialize.call(this, conn, form, detail, ctx);
 
     this.state = {};
   },
 
   form: function (form, detail) {
     if (detail === "actorid") {
@@ -118,17 +118,17 @@ const AnimationPlayerFront = FrontClassW
     }
 
     return {state: data, hasChanged};
   }
 });
 
 exports.AnimationPlayerFront = AnimationPlayerFront;
 
-const AnimationsFront = FrontClassWithSpec(animationsSpec, {
+const AnimationsFront = FrontClass(animationsSpec, {
   initialize: function (client, {animationsActor}) {
     Front.prototype.initialize.call(this, client, {actor: animationsActor});
     this.manage(this);
   },
 
   destroy: function () {
     Front.prototype.destroy.call(this);
   }
--- a/devtools/shared/fronts/call-watcher.js
+++ b/devtools/shared/fronts/call-watcher.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const { functionCallSpec, callWatcherSpec } = require("devtools/shared/specs/call-watcher");
 const protocol = require("devtools/shared/protocol");
 
 /**
  * The corresponding Front object for the FunctionCallActor.
  */
-const FunctionCallFront = protocol.FrontClassWithSpec(functionCallSpec, {
+const FunctionCallFront = protocol.FrontClass(functionCallSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   },
 
   /**
    * Adds some generic information directly to this instance,
    * to avoid extra roundtrips.
    */
@@ -33,17 +33,17 @@ const FunctionCallFront = protocol.Front
 
 exports.FunctionCallFront = FunctionCallFront;
 
 /**
  * The corresponding Front object for the CallWatcherActor.
  */
 var CallWatcherFront =
 exports.CallWatcherFront =
-protocol.FrontClassWithSpec(callWatcherSpec, {
+protocol.FrontClass(callWatcherSpec, {
   initialize: function (client, { callWatcherActor }) {
     protocol.Front.prototype.initialize.call(this, client, { actor: callWatcherActor });
     this.manage(this);
   }
 });
 
 /**
  * Constants.
--- a/devtools/shared/fronts/canvas.js
+++ b/devtools/shared/fronts/canvas.js
@@ -13,17 +13,17 @@ const {
   INTERESTING_CALLS,
 } = require("devtools/shared/specs/canvas");
 const protocol = require("devtools/shared/protocol");
 const promise = require("promise");
 
 /**
  * The corresponding Front object for the FrameSnapshotActor.
  */
-const FrameSnapshotFront = protocol.FrontClassWithSpec(frameSnapshotSpec, {
+const FrameSnapshotFront = protocol.FrontClass(frameSnapshotSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
     this._animationFrameEndScreenshot = null;
     this._cachedScreenshots = new WeakMap();
   },
 
   /**
    * This implementation caches the animation frame end screenshot to optimize
@@ -59,17 +59,17 @@ const FrameSnapshotFront = protocol.Fron
   })
 });
 
 exports.FrameSnapshotFront = FrameSnapshotFront;
 
 /**
  * The corresponding Front object for the CanvasActor.
  */
-const CanvasFront = protocol.FrontClassWithSpec(canvasSpec, {
+const CanvasFront = protocol.FrontClass(canvasSpec, {
   initialize: function (client, { canvasActor }) {
     protocol.Front.prototype.initialize.call(this, client, { actor: canvasActor });
     this.manage(this);
   }
 });
 
 /**
  * Constants.
--- a/devtools/shared/fronts/css-properties.js
+++ b/devtools/shared/fronts/css-properties.js
@@ -1,14 +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 { FrontClassWithSpec, Front } = require("devtools/shared/protocol");
+const { FrontClass, Front } = require("devtools/shared/protocol");
 const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
 const { Task } = require("devtools/shared/task");
 const { CSS_PROPERTIES_DB } = require("devtools/shared/css-properties-db");
 const { cssColors } = require("devtools/shared/css-color-db");
 
 /**
  * Build up a regular expression that matches a CSS variable token. This is an
  * ident token that starts with two dashes "--".
@@ -34,17 +34,17 @@ function isCssVariable(input) {
 var cachedCssProperties = new WeakMap();
 
 /**
  * The CssProperties front provides a mechanism to have a one-time asynchronous
  * load of a CSS properties database. This is then fed into the CssProperties
  * interface that provides synchronous methods for finding out what CSS
  * properties the current server supports.
  */
-const CssPropertiesFront = FrontClassWithSpec(cssPropertiesSpec, {
+const CssPropertiesFront = FrontClass(cssPropertiesSpec, {
   initialize: function (client, { cssPropertiesActor }) {
     Front.prototype.initialize.call(this, client, {actor: cssPropertiesActor});
     this.manage(this);
   }
 });
 
 /**
  * Ask questions to a CSS database. This class does not care how the database
--- a/devtools/shared/fronts/csscoverage.js
+++ b/devtools/shared/fronts/csscoverage.js
@@ -31,17 +31,17 @@ const l10n = exports.l10n = {
 var isRunning = false;
 var notification;
 var target;
 var chromeWindow;
 
 /**
  * Front for CSSUsageActor
  */
-const CSSUsageFront = protocol.FrontClassWithSpec(cssUsageSpec, {
+const CSSUsageFront = protocol.FrontClass(cssUsageSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
     this.actorID = form.cssUsageActor;
     this.manage(this);
   },
 
   _onStateChange: protocol.preEvent("state-change", function (ev) {
     isRunning = ev.isRunning;
--- a/devtools/shared/fronts/device.js
+++ b/devtools/shared/fronts/device.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 const {deviceSpec} = require("devtools/shared/specs/device");
 const protocol = require("devtools/shared/protocol");
 const defer = require("devtools/shared/defer");
 
-const DeviceFront = protocol.FrontClassWithSpec(deviceSpec, {
+const DeviceFront = protocol.FrontClass(deviceSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client);
     this.actorID = form.deviceActor;
     this.manage(this);
   },
 
   screenshotToBlob: function () {
     return this.screenshotToDataURL().then(longstr => {
--- a/devtools/shared/fronts/director-manager.js
+++ b/devtools/shared/fronts/director-manager.js
@@ -8,39 +8,39 @@ const {
   directorScriptSpec,
   directorManagerSpec,
 } = require("devtools/shared/specs/director-manager");
 const protocol = require("devtools/shared/protocol");
 
 /**
  * The corresponding Front object for the MessagePortActor.
  */
-const MessagePortFront = protocol.FrontClassWithSpec(messagePortSpec, {
+const MessagePortFront = protocol.FrontClass(messagePortSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   }
 });
 
 exports.MessagePortFront = MessagePortFront;
 
 /**
  * The corresponding Front object for the DirectorScriptActor.
  */
-const DirectorScriptFront = protocol.FrontClassWithSpec(directorScriptSpec, {
+const DirectorScriptFront = protocol.FrontClass(directorScriptSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   }
 });
 
 exports.DirectorScriptFront = DirectorScriptFront;
 
 /**
  * The corresponding Front object for the DirectorManagerActor.
  */
-const DirectorManagerFront = protocol.FrontClassWithSpec(directorManagerSpec, {
+const DirectorManagerFront = protocol.FrontClass(directorManagerSpec, {
   initialize: function (client, { directorManagerActor }) {
     protocol.Front.prototype.initialize.call(this, client, {
       actor: directorManagerActor
     });
     this.manage(this);
   }
 });
 
--- a/devtools/shared/fronts/director-registry.js
+++ b/devtools/shared/fronts/director-registry.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const {directorRegistrySpec} = require("devtools/shared/specs/director-registry");
 const protocol = require("devtools/shared/protocol");
 
 /**
  * The corresponding Front object for the DirectorRegistryActor.
  */
-const DirectorRegistryFront = protocol.FrontClassWithSpec(directorRegistrySpec, {
+const DirectorRegistryFront = protocol.FrontClass(directorRegistrySpec, {
   initialize: function (client, { directorRegistryActor }) {
     protocol.Front.prototype.initialize.call(this, client, {
       actor: directorRegistryActor
     });
     this.manage(this);
   }
 });
 
--- a/devtools/shared/fronts/eventlooplag.js
+++ b/devtools/shared/fronts/eventlooplag.js
@@ -1,15 +1,15 @@
 /* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
+const { Front, FrontClass } = require("devtools/shared/protocol");
 const { eventLoopLagSpec } = require("devtools/shared/specs/eventlooplag");
 
-exports.EventLoopLagFront = FrontClassWithSpec(eventLoopLagSpec, {
+exports.EventLoopLagFront = FrontClass(eventLoopLagSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client);
     this.actorID = form.eventLoopLagActor;
     this.manage(this);
   },
 });
--- a/devtools/shared/fronts/framerate.js
+++ b/devtools/shared/fronts/framerate.js
@@ -1,19 +1,19 @@
 /* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
+const { Front, FrontClass } = require("devtools/shared/protocol");
 const { framerateSpec } = require("devtools/shared/specs/framerate");
 
 /**
  * The corresponding Front object for the FramerateActor.
  */
-var FramerateFront = exports.FramerateFront = FrontClassWithSpec(framerateSpec, {
+var FramerateFront = exports.FramerateFront = FrontClass(framerateSpec, {
   initialize: function (client, { framerateActor }) {
     Front.prototype.initialize.call(this, client, { actor: framerateActor });
     this.manage(this);
   }
 });
 
 exports.FramerateFront = FramerateFront;
--- a/devtools/shared/fronts/gcli.js
+++ b/devtools/shared/fronts/gcli.js
@@ -1,20 +1,20 @@
 /* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
+const { Front, FrontClass } = require("devtools/shared/protocol");
 const { gcliSpec } = require("devtools/shared/specs/gcli");
 
 /**
  *
  */
-const GcliFront = exports.GcliFront = FrontClassWithSpec(gcliSpec, {
+const GcliFront = exports.GcliFront = FrontClass(gcliSpec, {
   initialize: function (client, tabForm) {
     Front.prototype.initialize.call(this, client);
     this.actorID = tabForm.gcliActor;
 
     // XXX: This is the first actor type in its hierarchy to use the protocol
     // library, so we're going to self-own on the client side for now.
     this.manage(this);
   },
--- a/devtools/shared/fronts/highlighters.js
+++ b/devtools/shared/fronts/highlighters.js
@@ -1,25 +1,25 @@
 /* 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 { FrontClassWithSpec } = require("devtools/shared/protocol");
+const { FrontClass } = require("devtools/shared/protocol");
 const {
   customHighlighterSpec,
   highlighterSpec
 } = require("devtools/shared/specs/highlighters");
 
-const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
+const HighlighterFront = FrontClass(highlighterSpec, {
   // Update the object given a form representation off the wire.
   form: function (json) {
     this.actorID = json.actor;
     // FF42+ HighlighterActors starts exposing custom form, with traits object
     this.traits = json.traits || {};
   }
 });
 
 exports.HighlighterFront = HighlighterFront;
 
-const CustomHighlighterFront = FrontClassWithSpec(customHighlighterSpec, {});
+const CustomHighlighterFront = FrontClass(customHighlighterSpec, {});
 
 exports.CustomHighlighterFront = CustomHighlighterFront;
--- a/devtools/shared/fronts/inspector.js
+++ b/devtools/shared/fronts/inspector.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 require("devtools/shared/fronts/styles");
 require("devtools/shared/fronts/highlighters");
 const { SimpleStringFront } = require("devtools/shared/fronts/string");
 const {
   Front,
-  FrontClassWithSpec,
+  FrontClass,
   custom,
   preEvent,
   types
 } = require("devtools/shared/protocol.js");
 const {
   inspectorSpec,
   nodeSpec,
   nodeListSpec,
@@ -79,17 +79,17 @@ const AttributeModificationList = Class(
  *  - The order of children isn't guaranteed to be the same as the DOM.
  * Children are stored in a doubly-linked list, to make addition/removal
  * and traversal quick.
  *
  * Due to the order/incompleteness of the child list, it is safe to use
  * the parent node from clients, but the `children` request should be used
  * to traverse children.
  */
-const NodeFront = FrontClassWithSpec(nodeSpec, {
+const NodeFront = FrontClass(nodeSpec, {
   initialize: function (conn, form, detail, ctx) {
     // The parent node
     this._parent = null;
     // The first child of this node.
     this._child = null;
     // The next sibling of this node.
     this._next = null;
     // The previous sibling of this node.
@@ -439,17 +439,17 @@ const NodeFront = FrontClassWithSpec(nod
   }
 });
 
 exports.NodeFront = NodeFront;
 
 /**
  * Client side of a node list as returned by querySelectorAll()
  */
-const NodeListFront = FrontClassWithSpec(nodeListSpec, {
+const NodeListFront = FrontClass(nodeListSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
   },
 
   destroy: function () {
     Front.prototype.destroy.call(this);
   },
 
@@ -479,17 +479,17 @@ const NodeListFront = FrontClassWithSpec
   })
 });
 
 exports.NodeListFront = NodeListFront;
 
 /**
  * Client side of the DOM walker.
  */
-const WalkerFront = FrontClassWithSpec(walkerSpec, {
+const WalkerFront = FrontClass(walkerSpec, {
   // Set to true if cleanup should be requested after every mutation list.
   autoCleanup: true,
 
   /**
    * This is kept for backward-compatibility reasons with older remote target.
    * Targets previous to bug 916443
    */
   pick: custom(function () {
@@ -935,17 +935,17 @@ const WalkerFront = FrontClassWithSpec(w
 });
 
 exports.WalkerFront = WalkerFront;
 
 /**
  * Client side of the inspector actor, which is used to create
  * inspector-related actors, including the walker.
  */
-var InspectorFront = FrontClassWithSpec(inspectorSpec, {
+var InspectorFront = FrontClass(inspectorSpec, {
   initialize: function (client, tabForm) {
     Front.prototype.initialize.call(this, client);
     this.actorID = tabForm.inspectorActor;
 
     // XXX: This is the first actor type in its hierarchy to use the protocol
     // library, so we're going to self-own on the client side for now.
     this.manage(this);
   },
--- a/devtools/shared/fronts/layout.js
+++ b/devtools/shared/fronts/layout.js
@@ -9,17 +9,17 @@ const protocol = require("devtools/share
 /**
  * Usage example of the reflow front:
  *
  * let front = ReflowFront(toolbox.target.client, toolbox.target.form);
  * front.on("reflows", this._onReflows);
  * front.start();
  * // now wait for events to come
  */
-const ReflowFront = protocol.FrontClassWithSpec(reflowSpec, {
+const ReflowFront = protocol.FrontClass(reflowSpec, {
   initialize: function (client, {reflowActor}) {
     protocol.Front.prototype.initialize.call(this, client, {actor: reflowActor});
     this.manage(this);
   },
 
   destroy: function () {
     protocol.Front.prototype.destroy.call(this);
   },
--- a/devtools/shared/fronts/memory.js
+++ b/devtools/shared/fronts/memory.js
@@ -7,17 +7,17 @@ const { memorySpec } = require("devtools
 const { Task } = require("devtools/shared/task");
 const protocol = require("devtools/shared/protocol");
 
 loader.lazyRequireGetter(this, "FileUtils",
                          "resource://gre/modules/FileUtils.jsm", true);
 loader.lazyRequireGetter(this, "HeapSnapshotFileUtils",
                          "devtools/shared/heapsnapshot/HeapSnapshotFileUtils");
 
-const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
+const MemoryFront = protocol.FrontClass(memorySpec, {
   initialize: function (client, form, rootForm = null) {
     protocol.Front.prototype.initialize.call(this, client, form);
     this._client = client;
     this.actorID = form.memoryActor;
     this.heapSnapshotFileActorID = rootForm
       ? rootForm.heapSnapshotFileActor
       : null;
     this.manage(this);
--- a/devtools/shared/fronts/moz.build
+++ b/devtools/shared/fronts/moz.build
@@ -17,16 +17,17 @@ DevToolsModules(
     'director-registry.js',
     'eventlooplag.js',
     'framerate.js',
     'gcli.js',
     'highlighters.js',
     'inspector.js',
     'layout.js',
     'memory.js',
+    'performance-entries.js',
     'performance-recording.js',
     'performance.js',
     'preference.js',
     'profiler.js',
     'promises.js',
     'settings.js',
     'storage.js',
     'string.js',
new file mode 100644
--- /dev/null
+++ b/devtools/shared/fronts/performance-entries.js
@@ -0,0 +1,17 @@
+/* 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 { Front, FrontClass } = require("devtools/shared/protocol");
+const performanceSpec = require("devtools/shared/specs/performance-entries");
+
+var PerformanceEntriesFront = FrontClass(performanceSpec, {
+  initialize: function (client, form) {
+    Front.prototype.initialize.call(this, client);
+    this.actorID = form.performanceEntriesActor;
+    this.manage(this);
+  },
+});
+
+exports.PerformanceEntriesFront = PerformanceEntriesFront;
--- a/devtools/shared/fronts/performance-recording.js
+++ b/devtools/shared/fronts/performance-recording.js
@@ -1,29 +1,29 @@
 /* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
+const { Front, FrontClass } = require("devtools/shared/protocol");
 const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
 
 loader.lazyRequireGetter(this, "PerformanceIO",
   "devtools/client/performance/modules/io");
 loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
   "devtools/shared/performance/recording-common", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/shared/performance/recording-utils");
 loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
 
 /**
  * This can be used on older Profiler implementations, but the methods cannot
  * be changed -- you must introduce a new method, and detect the server.
  */
-const PerformanceRecordingFront = FrontClassWithSpec(performanceRecordingSpec, merge({
+const PerformanceRecordingFront = FrontClass(performanceRecordingSpec, merge({
   form: function (form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
     this.actorID = form.actor;
     this._form = form;
     this._configuration = form.configuration;
--- a/devtools/shared/fronts/performance.js
+++ b/devtools/shared/fronts/performance.js
@@ -1,27 +1,27 @@
 /* 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 { Cu } = require("chrome");
-const { Front, FrontClassWithSpec, custom, preEvent } = require("devtools/shared/protocol");
+const { Front, FrontClass, custom, preEvent } = require("devtools/shared/protocol");
 const { PerformanceRecordingFront } = require("devtools/shared/fronts/performance-recording");
 const { performanceSpec } = require("devtools/shared/specs/performance");
 const { Task } = require("devtools/shared/task");
 
 loader.lazyRequireGetter(this, "PerformanceIO",
   "devtools/client/performance/modules/io");
 loader.lazyRequireGetter(this, "LegacyPerformanceFront",
   "devtools/client/performance/legacy/front", true);
 loader.lazyRequireGetter(this, "getSystemInfo",
   "devtools/shared/system", true);
 
-const PerformanceFront = FrontClassWithSpec(performanceSpec, {
+const PerformanceFront = FrontClass(performanceSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
     this.actorID = form.performanceActor;
     this.manage(this);
   },
 
   destroy: function () {
     Front.prototype.destroy.call(this);
--- a/devtools/shared/fronts/preference.js
+++ b/devtools/shared/fronts/preference.js
@@ -1,17 +1,17 @@
 /* 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 {preferenceSpec} = require("devtools/shared/specs/preference");
 const protocol = require("devtools/shared/protocol");
 
-const PreferenceFront = protocol.FrontClassWithSpec(preferenceSpec, {
+const PreferenceFront = protocol.FrontClass(preferenceSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client);
     this.actorID = form.preferenceActor;
     this.manage(this);
   },
 });
 
 const _knownPreferenceFronts = new WeakMap();
--- a/devtools/shared/fronts/profiler.js
+++ b/devtools/shared/fronts/profiler.js
@@ -1,29 +1,29 @@
 /* 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 { Cu } = require("chrome");
 const {
   Front,
-  FrontClassWithSpec,
+  FrontClass,
   custom
 } = require("devtools/shared/protocol");
 const { profilerSpec } = require("devtools/shared/specs/profiler");
 
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
 loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
 
 /**
  * This can be used on older Profiler implementations, but the methods cannot
  * be changed -- you must introduce a new method, and detect the server.
  */
-exports.ProfilerFront = FrontClassWithSpec(profilerSpec, {
+exports.ProfilerFront = FrontClass(profilerSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
     this.actorID = form.profilerActor;
     this.manage(this);
 
     this._onProfilerEvent = this._onProfilerEvent.bind(this);
     events.on(this, "*", this._onProfilerEvent);
   },
--- a/devtools/shared/fronts/promises.js
+++ b/devtools/shared/fronts/promises.js
@@ -1,23 +1,23 @@
 /* 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 {
   Front,
-  FrontClassWithSpec,
+  FrontClass,
 } = require("devtools/shared/protocol");
 const { promisesSpec } = require("devtools/shared/specs/promises");
 
 /**
  * PromisesFront, the front for the PromisesActor.
  */
-const PromisesFront = FrontClassWithSpec(promisesSpec, {
+const PromisesFront = FrontClass(promisesSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
     this.actorID = form.promisesActor;
     this.manage(this);
   },
 
   destroy: function () {
     Front.prototype.destroy.call(this);
--- a/devtools/shared/fronts/settings.js
+++ b/devtools/shared/fronts/settings.js
@@ -1,17 +1,17 @@
 /* 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 {settingsSpec} = require("devtools/shared/specs/settings");
 const protocol = require("devtools/shared/protocol");
 
-const SettingsFront = protocol.FrontClassWithSpec(settingsSpec, {
+const SettingsFront = protocol.FrontClass(settingsSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client);
     this.actorID = form.settingsActor;
     this.manage(this);
   },
 });
 
 const _knownSettingsFronts = new WeakMap();
--- a/devtools/shared/fronts/storage.js
+++ b/devtools/shared/fronts/storage.js
@@ -2,31 +2,31 @@
  * 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 protocol = require("devtools/shared/protocol");
 const specs = require("devtools/shared/specs/storage");
 
 for (let childSpec of Object.values(specs.childSpecs)) {
-  protocol.FrontClassWithSpec(childSpec, {
+  protocol.FrontClass(childSpec, {
     form(form, detail) {
       if (detail === "actorid") {
         this.actorID = form;
         return null;
       }
 
       this.actorID = form.actor;
       this.hosts = form.hosts;
       return null;
     }
   });
 }
 
-const StorageFront = protocol.FrontClassWithSpec(specs.storageSpec, {
+const StorageFront = protocol.FrontClass(specs.storageSpec, {
   initialize(client, tabForm) {
     protocol.Front.prototype.initialize.call(this, client);
     this.actorID = tabForm.storageActor;
     this.manage(this);
   }
 });
 
 exports.StorageFront = StorageFront;
--- a/devtools/shared/fronts/string.js
+++ b/devtools/shared/fronts/string.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const {DebuggerServer} = require("devtools/server/main");
 const promise = require("promise");
 const {Class} = require("sdk/core/heritage");
 const {longStringSpec} = require("devtools/shared/specs/string");
 const protocol = require("devtools/shared/protocol");
 
-const LongStringFront = protocol.FrontClassWithSpec(longStringSpec, {
+const LongStringFront = protocol.FrontClass(longStringSpec, {
   initialize: function (client) {
     protocol.Front.prototype.initialize.call(this, client);
   },
 
   destroy: function () {
     this.initial = null;
     this.length = null;
     this.strPromise = null;
--- a/devtools/shared/fronts/styleeditor.js
+++ b/devtools/shared/fronts/styleeditor.js
@@ -1,27 +1,27 @@
 /* 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 { SimpleStringFront } = require("devtools/shared/fronts/string");
-const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
+const { Front, FrontClass } = require("devtools/shared/protocol");
 const {
   oldStyleSheetSpec,
   styleEditorSpec
 } = require("devtools/shared/specs/styleeditor");
 const promise = require("promise");
 const defer = require("devtools/shared/defer");
 const events = require("sdk/event/core");
 
 /**
  * StyleSheetFront is the client-side counterpart to a StyleSheetActor.
  */
-const OldStyleSheetFront = FrontClassWithSpec(oldStyleSheetSpec, {
+const OldStyleSheetFront = FrontClass(oldStyleSheetSpec, {
   initialize: function (conn, form, ctx, detail) {
     Front.prototype.initialize.call(this, conn, form, ctx, detail);
 
     this._onPropertyChange = this._onPropertyChange.bind(this);
     events.on(this, "property-change", this._onPropertyChange);
   },
 
   destroy: function () {
@@ -82,17 +82,17 @@ const OldStyleSheetFront = FrontClassWit
   }
 });
 
 exports.OldStyleSheetFront = OldStyleSheetFront;
 
 /**
  * The corresponding Front object for the StyleEditorActor.
  */
-const StyleEditorFront = FrontClassWithSpec(styleEditorSpec, {
+const StyleEditorFront = FrontClass(styleEditorSpec, {
   initialize: function (client, tabForm) {
     Front.prototype.initialize.call(this, client);
     this.actorID = tabForm.styleEditorActor;
     this.manage(this);
   },
 
   getStyleSheets: function () {
     let deferred = defer();
--- a/devtools/shared/fronts/styles.js
+++ b/devtools/shared/fronts/styles.js
@@ -1,17 +1,17 @@
 /* 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";
 
 require("devtools/shared/fronts/stylesheets");
 const {
   Front,
-  FrontClassWithSpec,
+  FrontClass,
   custom,
   preEvent
 } = require("devtools/shared/protocol");
 const {
   pageStyleSpec,
   styleRuleSpec
 } = require("devtools/shared/specs/styles");
 const promise = require("promise");
@@ -20,17 +20,17 @@ const { Class } = require("sdk/core/heri
 
 loader.lazyGetter(this, "RuleRewriter", () => {
   return require("devtools/shared/css-parsing-utils").RuleRewriter;
 });
 
 /**
  * PageStyleFront, the front object for the PageStyleActor
  */
-const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
+const PageStyleFront = FrontClass(pageStyleSpec, {
   initialize: function (conn, form, ctx, detail) {
     Front.prototype.initialize.call(this, conn, form, ctx, detail);
     this.inspector = this.parent();
   },
 
   form: function (form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
@@ -88,17 +88,17 @@ const PageStyleFront = FrontClassWithSpe
   })
 });
 
 exports.PageStyleFront = PageStyleFront;
 
 /**
  * StyleRuleFront, the front for the StyleRule actor.
  */
-const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
+const StyleRuleFront = FrontClass(styleRuleSpec, {
   initialize: function (client, form, ctx, detail) {
     Front.prototype.initialize.call(this, client, form, ctx, detail);
   },
 
   destroy: function () {
     Front.prototype.destroy.call(this);
   },
 
--- a/devtools/shared/fronts/stylesheets.js
+++ b/devtools/shared/fronts/stylesheets.js
@@ -1,14 +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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
+const { Front, FrontClass } = require("devtools/shared/protocol");
 const {
   getIndentationFromPrefs,
   getIndentationFromString
 } = require("devtools/shared/indentation");
 const {
   originalSourceSpec,
   mediaRuleSpec,
   styleSheetSpec,
@@ -16,17 +16,17 @@ const {
 } = require("devtools/shared/specs/stylesheets");
 const promise = require("promise");
 const { Task } = require("devtools/shared/task");
 const events = require("sdk/event/core");
 
 /**
  * The client-side counterpart for an OriginalSourceActor.
  */
-const OriginalSourceFront = FrontClassWithSpec(originalSourceSpec, {
+const OriginalSourceFront = FrontClass(originalSourceSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
 
     this.isOriginalSource = true;
   },
 
   form: function (form, detail) {
     if (detail === "actorid") {
@@ -45,17 +45,17 @@ const OriginalSourceFront = FrontClassWi
   }
 });
 
 exports.OriginalSourceFront = OriginalSourceFront;
 
 /**
  * Corresponding client-side front for a MediaRuleActor.
  */
-const MediaRuleFront = FrontClassWithSpec(mediaRuleSpec, {
+const MediaRuleFront = FrontClass(mediaRuleSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
 
     this._onMatchesChange = this._onMatchesChange.bind(this);
     events.on(this, "matches-change", this._onMatchesChange);
   },
 
   _onMatchesChange: function (matches) {
@@ -91,17 +91,17 @@ const MediaRuleFront = FrontClassWithSpe
   }
 });
 
 exports.MediaRuleFront = MediaRuleFront;
 
 /**
  * StyleSheetFront is the client-side counterpart to a StyleSheetActor.
  */
-const StyleSheetFront = FrontClassWithSpec(styleSheetSpec, {
+const StyleSheetFront = FrontClass(styleSheetSpec, {
   initialize: function (conn, form) {
     Front.prototype.initialize.call(this, conn, form);
 
     this._onPropertyChange = this._onPropertyChange.bind(this);
     events.on(this, "property-change", this._onPropertyChange);
   },
 
   destroy: function () {
@@ -168,17 +168,17 @@ const StyleSheetFront = FrontClassWithSp
   }
 });
 
 exports.StyleSheetFront = StyleSheetFront;
 
 /**
  * The corresponding Front object for the StyleSheetsActor.
  */
-const StyleSheetsFront = FrontClassWithSpec(styleSheetsSpec, {
+const StyleSheetsFront = FrontClass(styleSheetsSpec, {
   initialize: function (client, tabForm) {
     Front.prototype.initialize.call(this, client);
     this.actorID = tabForm.styleSheetsActor;
     this.manage(this);
   }
 });
 
 exports.StyleSheetsFront = StyleSheetsFront;
--- a/devtools/shared/fronts/timeline.js
+++ b/devtools/shared/fronts/timeline.js
@@ -1,23 +1,23 @@
 /* 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 {
   Front,
-  FrontClassWithSpec,
+  FrontClass,
 } = require("devtools/shared/protocol");
 const { timelineSpec } = require("devtools/shared/specs/timeline");
 
 /**
  * TimelineFront, the front for the TimelineActor.
  */
-const TimelineFront = FrontClassWithSpec(timelineSpec, {
+const TimelineFront = FrontClass(timelineSpec, {
   initialize: function (client, { timelineActor }) {
     Front.prototype.initialize.call(this, client, { actor: timelineActor });
     this.manage(this);
   },
   destroy: function () {
     Front.prototype.destroy.call(this);
   },
 });
--- a/devtools/shared/fronts/webaudio.js
+++ b/devtools/shared/fronts/webaudio.js
@@ -20,17 +20,17 @@ const AUDIO_NODE_DEFINITION = require("d
  *            The type of audio node, like "OscillatorNode", "MediaElementAudioSourceNode"
  * @attribute {Boolean} source
  *            Boolean indicating if the node is a source node, like BufferSourceNode,
  *            MediaElementAudioSourceNode, OscillatorNode, etc.
  * @attribute {Boolean} bypassable
  *            Boolean indicating if the audio node is bypassable (splitter,
  *            merger and destination nodes, for example, are not)
  */
-const AudioNodeFront = protocol.FrontClassWithSpec(audionodeSpec, {
+const AudioNodeFront = protocol.FrontClass(audionodeSpec, {
   form: function (form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
 
     this.actorID = form.actor;
     this.type = form.type;
@@ -48,17 +48,17 @@ const AudioNodeFront = protocol.FrontCla
   }
 });
 
 exports.AudioNodeFront = AudioNodeFront;
 
 /**
  * The corresponding Front object for the WebAudioActor.
  */
-const WebAudioFront = protocol.FrontClassWithSpec(webAudioSpec, {
+const WebAudioFront = protocol.FrontClass(webAudioSpec, {
   initialize: function (client, { webaudioActor }) {
     protocol.Front.prototype.initialize.call(this, client, { actor: webaudioActor });
     this.manage(this);
   },
 
   /**
    * If connecting to older geckos (<Fx43), where audio node actor's do not
    * contain `type`, `source` and `bypassable` properties, fetch
--- a/devtools/shared/fronts/webgl.js
+++ b/devtools/shared/fronts/webgl.js
@@ -8,38 +8,38 @@ const {
   programSpec,
   webGLSpec,
 } = require("devtools/shared/specs/webgl");
 const protocol = require("devtools/shared/protocol");
 
 /**
  * The corresponding Front object for the ShaderActor.
  */
-const ShaderFront = protocol.FrontClassWithSpec(shaderSpec, {
+const ShaderFront = protocol.FrontClass(shaderSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   }
 });
 
 exports.ShaderFront = ShaderFront;
 
 /**
  * The corresponding Front object for the ProgramActor.
  */
-const ProgramFront = protocol.FrontClassWithSpec(programSpec, {
+const ProgramFront = protocol.FrontClass(programSpec, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   }
 });
 
 exports.ProgramFront = ProgramFront;
 
 /**
  * The corresponding Front object for the WebGLActor.
  */
-const WebGLFront = protocol.FrontClassWithSpec(webGLSpec, {
+const WebGLFront = protocol.FrontClass(webGLSpec, {
   initialize: function (client, { webglActor }) {
     protocol.Front.prototype.initialize.call(this, client, { actor: webglActor });
     this.manage(this);
   }
 });
 
 exports.WebGLFront = WebGLFront;
--- a/devtools/shared/protocol.js
+++ b/devtools/shared/protocol.js
@@ -1086,46 +1086,35 @@ var generateRequestHandlers = function (
   });
 
   actorProto._actorSpec = actorSpec;
 
   return actorProto;
 };
 
 /**
- * Create an actor class for the given actor prototype.
- *
- * @param object actorProto
- *    The actor prototype.  Must have a 'typeName' property,
- *    should have method definitions, can have event definitions.
- */
-exports.ActorClass = function (actorProto) {
-  return ActorClassWithSpec(generateActorSpec(actorProto), actorProto);
-};
-
-/**
  * Create an actor class for the given actor specification and prototype.
  *
  * @param object actorSpec
  *    The actor specification. Must have a 'typeName' property.
  * @param object actorProto
  *    The actor prototype. Should have method definitions, can have event
  *    definitions.
  */
-var ActorClassWithSpec = function (actorSpec, actorProto) {
+var ActorClass = function (actorSpec, actorProto) {
   if (!actorSpec.typeName) {
     throw Error("Actor specification must have a typeName member.");
   }
 
   actorProto.extends = Actor;
   let cls = Class(generateRequestHandlers(actorSpec, actorProto));
 
   return cls;
 };
-exports.ActorClassWithSpec = ActorClassWithSpec;
+exports.ActorClass = ActorClass;
 
 /**
  * Base class for client-side actor fronts.
  */
 var Front = Class({
   extends: Pool,
 
   actorID: null,
@@ -1418,49 +1407,36 @@ var generateRequestMethods = function (a
   }
 
   frontProto._actorSpec = actorSpec;
 
   return frontProto;
 };
 
 /**
- * Create a front class for the given actor class and front prototype.
- *
- * @param ActorClass actorType
- *    The actor class you're creating a front for.
- * @param object frontProto
- *    The front prototype.  Must have a 'typeName' property,
- *    should have method definitions, can have event definitions.
- */
-exports.FrontClass = function (actorType, frontProto) {
-  return FrontClassWithSpec(prototypeOf(actorType)._actorSpec, frontProto);
-};
-
-/**
  * Create a front class for the given actor specification and front prototype.
  *
  * @param object actorSpec
  *    The actor specification you're creating a front for.
  * @param object proto
  *    The object prototype.  Must have a 'typeName' property,
  *    should have method definitions, can have event definitions.
  */
-var FrontClassWithSpec = function (actorSpec, frontProto) {
+var FrontClass = function (actorSpec, frontProto) {
   frontProto.extends = Front;
   let cls = Class(generateRequestMethods(actorSpec, frontProto));
 
   if (!registeredTypes.has(actorSpec.typeName)) {
     types.addActorType(actorSpec.typeName);
   }
   registeredTypes.get(actorSpec.typeName).frontClass = cls;
 
   return cls;
 };
-exports.FrontClassWithSpec = FrontClassWithSpec;
+exports.FrontClass = FrontClass;
 
 exports.dumpActorSpec = function (type) {
   let actorSpec = type.actorSpec;
   let ret = {
     category: "actor",
     typeName: type.name,
     methods: [],
     events: {}
--- a/devtools/shared/specs/moz.build
+++ b/devtools/shared/specs/moz.build
@@ -22,16 +22,17 @@ DevToolsModules(
     'framerate.js',
     'gcli.js',
     'heap-snapshot-file.js',
     'highlighters.js',
     'inspector.js',
     'layout.js',
     'memory.js',
     'node.js',
+    'performance-entries.js',
     'performance-recording.js',
     'performance.js',
     'preference.js',
     'profiler.js',
     'promises.js',
     'script.js',
     'settings.js',
     'source.js',
new file mode 100644
--- /dev/null
+++ b/devtools/shared/specs/performance-entries.js
@@ -0,0 +1,25 @@
+/* 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 { Arg, generateActorSpec } = require("devtools/shared/protocol");
+
+const performanceEntriesSpec = generateActorSpec({
+  typeName: "performanceEntries",
+
+  events: {
+    "entry": {
+      type: "entry",
+      // object containing performance entry name, type, origin, and epoch.
+      detail: Arg(0, "json")
+    }
+  },
+
+  methods: {
+    start: {},
+    stop: {}
+  }
+});
+
+exports.performanceEntriesSpec = performanceEntriesSpec;
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -95,22 +95,16 @@
     "CACHE_SERVICE_LOCK_WAIT_MAINTHREAD_NSOUTPUTSTREAMWRAPPER_LAZYINIT",
     "CACHE_SERVICE_LOCK_WAIT_MAINTHREAD_NSOUTPUTSTREAMWRAPPER_RELEASE",
     "CACHE_SERVICE_LOCK_WAIT_MAINTHREAD_NSPROCESSREQUESTEVENT_RUN",
     "CACHE_SERVICE_LOCK_WAIT_MAINTHREAD_NSSETDISKSMARTSIZECALLBACK_NOTIFY",
     "CANVAS_2D_USED",
     "CANVAS_WEBGL_USED",
     "CERT_CHAIN_KEY_SIZE_STATUS",
     "CERT_CHAIN_SHA1_POLICY_STATUS",
-    "CERT_OCSP_ENABLED",
-    "CERT_OCSP_REQUIRED",
-    "CERT_VALIDATION_HTTP_REQUEST_CANCELED_TIME",
-    "CERT_VALIDATION_HTTP_REQUEST_FAILED_TIME",
-    "CERT_VALIDATION_HTTP_REQUEST_RESULT",
-    "CERT_VALIDATION_HTTP_REQUEST_SUCCEEDED_TIME",
     "CERT_VALIDATION_SUCCESS_BY_CA",
     "CHANGES_OF_DETECTED_LANGUAGE",
     "CHANGES_OF_TARGET_LANGUAGE",
     "CHARSET_OVERRIDE_SITUATION",
     "CHARSET_OVERRIDE_USED",
     "CHECK_ADDONS_MODIFIED_MS",
     "CHECK_JAVA_ENABLED",
     "COMPONENTS_SHIM_ACCESSED_BY_CONTENT",
@@ -138,235 +132,115 @@
     "DECODER_INSTANTIATED_MACHEBREW",
     "DECODER_INSTANTIATED_MACICELANDIC",
     "DECODER_INSTANTIATED_MACROMANIAN",
     "DECODER_INSTANTIATED_MACTURKISH",
     "DEFECTIVE_PERMISSIONS_SQL_REMOVED",
     "DEFERRED_FINALIZE_ASYNC",
     "DENIED_TRANSLATION_OFFERS",
     "DEVICE_RESET_REASON",
-    "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_BOOLEAN",
     "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_BROWSERCONSOLE_OPENED_BOOLEAN",
     "DEVTOOLS_BROWSERCONSOLE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_BROWSERCONSOLE_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN",
     "DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_COMPUTEDVIEW_OPENED_BOOLEAN",
     "DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG",
     "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_CUSTOM_OPENED_BOOLEAN",
     "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
     "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_LOCAL_MS",
     "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_REMOTE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ADDONDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ASSIGN_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_BINDINGS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_BLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_CLIENTEVALUATE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DELETE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DISPLAYSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ENUMPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_EVENTLISTENERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_FRAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_GET_EXECUTABLE_LINES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_INTERRUPT_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTADDONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTPROCESSES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTWORKERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_NAVIGATETO_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_OWNPROPERTYNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PARAMETERNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROPERTY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOCOLDESCRIPTION_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPEANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPESANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELEASEMANY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELEASE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELOAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SCOPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SOURCES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_STARTTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_STOPTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SUBSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADGRIPS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_TRACERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_UNBLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_WORKERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ADDONDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ASSIGN_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_BINDINGS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_BLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_CLIENTEVALUATE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DELETE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DISPLAYSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ENUMPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_EVENTLISTENERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_FRAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_GET_EXECUTABLE_LINES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_INTERRUPT_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTADDONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTPROCESSES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTTABS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTWORKERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_NAVIGATETO_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_OWNPROPERTYNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PARAMETERNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROPERTY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOCOLDESCRIPTION_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPEANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPESANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETAB_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETHREAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELEASEMANY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELEASE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELOAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RESUME_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SCOPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SOURCES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_STARTTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_STOPTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SUBSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_TABDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_THREADDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_THREADGRIPS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_TRACERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_UNBLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_WORKERDETACH_MS",
-    "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN",
     "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_DEVELOPERTOOLBAR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN",
     "DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_FONTINSPECTOR_OPENED_BOOLEAN",
     "DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT",
     "DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT",
-    "DEVTOOLS_INSPECTOR_OPENED_BOOLEAN",
     "DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_BOOLEAN",
     "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_JSBROWSERDEBUGGER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_JSDEBUGGER_OPENED_BOOLEAN",
     "DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_JSPROFILER_OPENED_BOOLEAN",
     "DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_LAYOUTVIEW_OPENED_BOOLEAN",
-    "DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_MEMORY_BREAKDOWN_CENSUS_COUNT",
     "DEVTOOLS_MEMORY_BREAKDOWN_DOMINATOR_TREE_COUNT",
     "DEVTOOLS_MEMORY_DIFF_CENSUS",
     "DEVTOOLS_MEMORY_DOMINATOR_TREE_COUNT",
     "DEVTOOLS_MEMORY_EXPORT_SNAPSHOT_COUNT",
     "DEVTOOLS_MEMORY_FILTER_CENSUS",
     "DEVTOOLS_MEMORY_IMPORT_SNAPSHOT_COUNT",
     "DEVTOOLS_MEMORY_INVERTED_CENSUS",
-    "DEVTOOLS_MEMORY_OPENED_BOOLEAN",
     "DEVTOOLS_MEMORY_OPENED_PER_USER_FLAG",
     "DEVTOOLS_MEMORY_TAKE_SNAPSHOT_COUNT",
     "DEVTOOLS_MEMORY_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_MENU_EYEDROPPER_OPENED_BOOLEAN",
     "DEVTOOLS_MENU_EYEDROPPER_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_NETMONITOR_OPENED_BOOLEAN",
     "DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_OPTIONS_OPENED_BOOLEAN",
     "DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG",
     "DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_OS_ENUMERATED_PER_USER",
     "DEVTOOLS_OS_IS_64_BITS_PER_USER",
-    "DEVTOOLS_PAINTFLASHING_OPENED_BOOLEAN",
     "DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG",
     "DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_PERFTOOLS_CONSOLE_RECORDING_COUNT",
     "DEVTOOLS_PERFTOOLS_RECORDING_COUNT",
     "DEVTOOLS_PERFTOOLS_RECORDING_DURATION_MS",
     "DEVTOOLS_PERFTOOLS_RECORDING_EXPORT_FLAG",
     "DEVTOOLS_PERFTOOLS_RECORDING_FEATURES_USED",
     "DEVTOOLS_PERFTOOLS_RECORDING_IMPORT_FLAG",
     "DEVTOOLS_PERFTOOLS_SELECTED_VIEW_MS",
-    "DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN",
     "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_READ_HEAP_SNAPSHOT_MS",
-    "DEVTOOLS_RESPONSIVE_OPENED_BOOLEAN",
     "DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_RULEVIEW_OPENED_BOOLEAN",
     "DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG",
     "DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS",
-    "DEVTOOLS_SCRATCHPAD_OPENED_BOOLEAN",
     "DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG",
     "DEVTOOLS_SCRATCHPAD_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER",
-    "DEVTOOLS_SHADEREDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_STORAGE_OPENED_BOOLEAN",
     "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_STYLEEDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_TABS_OPEN_AVERAGE_LINEAR",
     "DEVTOOLS_TABS_OPEN_PEAK_LINEAR",
     "DEVTOOLS_TABS_PINNED_AVERAGE_LINEAR",
     "DEVTOOLS_TABS_PINNED_PEAK_LINEAR",
-    "DEVTOOLS_TILT_OPENED_BOOLEAN",
     "DEVTOOLS_TILT_OPENED_PER_USER_FLAG",
     "DEVTOOLS_TILT_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN",
     "DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG",
     "DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_WEBCONSOLE_OPENED_BOOLEAN",
     "DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION",
     "DEVTOOLS_WEBIDE_CONNECTION_DEBUG_USED",
     "DEVTOOLS_WEBIDE_CONNECTION_PLAY_USED",
     "DEVTOOLS_WEBIDE_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS",
-    "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN",
     "DEVTOOLS_WEBIDE_IMPORT_PROJECT_PER_USER_FLAG",
     "DEVTOOLS_WEBIDE_LOCAL_CONNECTION_RESULT",
-    "DEVTOOLS_WEBIDE_NEW_PROJECT_BOOLEAN",
     "DEVTOOLS_WEBIDE_NEW_PROJECT_PER_USER_FLAG",
-    "DEVTOOLS_WEBIDE_OPENED_BOOLEAN",
     "DEVTOOLS_WEBIDE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_WEBIDE_OTHER_CONNECTION_RESULT",
-    "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_BOOLEAN",
     "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_PER_USER_FLAG",
     "DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_WEBIDE_REMOTE_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_SIMULATOR_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_WEBIDE_USB_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_WIFI_CONNECTION_RESULT",
     "DISPLAY_SCALING_LINUX",
@@ -380,23 +254,21 @@
     "DNS_RENEWAL_TIME",
     "DNS_RENEWAL_TIME_FOR_TTL",
     "DNT_USAGE",
     "DWRITEFONT_DELAYEDINITFONTLIST_COLLECT",
     "DWRITEFONT_DELAYEDINITFONTLIST_COUNT",
     "DWRITEFONT_DELAYEDINITFONTLIST_TOTAL",
     "DWRITEFONT_INIT_PROBLEM",
     "E10S_BLOCKED_FROM_RUNNING",
-    "E10S_STILL_ACCEPTED_FROM_PROMPT",
     "E10S_WINDOW",
     "ENABLE_PRIVILEGE_EVER_CALLED",
     "FENNEC_DISTRIBUTION_CODE_CATEGORY",
     "FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS",
     "FENNEC_DISTRIBUTION_REFERRER_INVALID",
-    "FENNEC_GECKOAPP_STARTUP_ACTION",
     "FENNEC_GLOBALHISTORY_ADD_MS",
     "FENNEC_GLOBALHISTORY_UPDATE_MS",
     "FENNEC_GLOBALHISTORY_VISITED_BUILD_MS",
     "FENNEC_HOMEPANELS_CUSTOM",
     "FENNEC_READING_LIST_COUNT",
     "FENNEC_RESTORING_ACTIVITY",
     "FENNEC_SEARCH_LOADER_TIME_MS",
     "FENNEC_STARTUP_TIME_GECKOREADY",
@@ -405,19 +277,16 @@
     "FENNEC_SYNC11_MIGRATIONS_FAILED",
     "FENNEC_SYNC11_MIGRATIONS_SUCCEEDED",
     "FENNEC_SYNC11_MIGRATION_NOTIFICATIONS_OFFERED",
     "FENNEC_SYNC11_MIGRATION_SENTINELS_SEEN",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_COMPLETED",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_FAILED",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_FAILED_BACKOFF",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_STARTED",
-    "FENNEC_TABQUEUE_ENABLED",
-    "FENNEC_TABQUEUE_PROMPT_ENABLE_NO",
-    "FENNEC_TABQUEUE_PROMPT_ENABLE_YES",
     "FENNEC_TABQUEUE_QUEUESIZE",
     "FENNEC_TOPSITES_LOADER_TIME_MS",
     "FENNEC_WAS_KILLED",
     "FETCH_IS_MAINTHREAD",
     "FLASH_PLUGIN_AREA",
     "FLASH_PLUGIN_HEIGHT",
     "FLASH_PLUGIN_INSTANCES_ON_PAGE",
     "FLASH_PLUGIN_STATES",
@@ -541,17 +410,16 @@
     "HTTP_SUB_OPEN_TO_FIRST_FROM_CACHE_V2",
     "HTTP_SUB_OPEN_TO_FIRST_RECEIVED",
     "HTTP_SUB_OPEN_TO_FIRST_SENT",
     "HTTP_SUB_REVALIDATION",
     "HTTP_SUB_TCP_CONNECTION",
     "HTTP_TRANSACTION_IS_SSL",
     "HTTP_TRANSACTION_USE_ALTSVC",
     "HTTP_TRANSACTION_USE_ALTSVC_OE",
-    "IDLE_NOTIFY_IDLE_MS",
     "IMAGE_DECODE_CHUNKS",
     "IMAGE_DECODE_COUNT",
     "IMAGE_DECODE_LATENCY_US",
     "IMAGE_DECODE_ON_DRAW_LATENCY",
     "IMAGE_DECODE_SPEED_GIF",
     "IMAGE_DECODE_SPEED_JPEG",
     "IMAGE_DECODE_SPEED_PNG",
     "IMAGE_DECODE_TIME",
@@ -649,17 +517,16 @@
     "MOZ_SQLITE_WEBAPPS_READ_B",
     "MOZ_SQLITE_WEBAPPS_READ_MAIN_THREAD_MS",
     "MOZ_SQLITE_WEBAPPS_READ_MS",
     "MOZ_SQLITE_WEBAPPS_SYNC_MAIN_THREAD_MS",
     "MOZ_SQLITE_WEBAPPS_SYNC_MS",
     "MOZ_SQLITE_WEBAPPS_WRITE_B",
     "MOZ_SQLITE_WEBAPPS_WRITE_MAIN_THREAD_MS",
     "MOZ_SQLITE_WEBAPPS_WRITE_MS",
-    "NETWORK_AUTODIAL",
     "NETWORK_CACHE_FS_TYPE",
     "NETWORK_CACHE_HASH_STATS",
     "NETWORK_CACHE_HIT_MISS_STAT_PER_CACHE_SIZE",
     "NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE",
     "NETWORK_CACHE_METADATA_FIRST_READ_SIZE",
     "NETWORK_CACHE_METADATA_FIRST_READ_TIME_MS",
     "NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS",
     "NETWORK_CACHE_METADATA_SIZE",
@@ -747,17 +614,16 @@
     "PLUGINS_NOTIFICATION_SHOWN",
     "PLUGINS_NOTIFICATION_USER_ACTION",
     "PLUGIN_CALLED_DIRECTLY",
     "PLUGIN_HANG_TIME",
     "PLUGIN_HANG_UI_DONT_ASK",
     "PLUGIN_HANG_UI_RESPONSE_TIME",
     "PLUGIN_HANG_UI_USER_RESPONSE",
     "PLUGIN_SHUTDOWN_MS",
-    "PLUGIN_STARTUP_MS",
     "PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE",
     "PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE",
     "PRCLOSE_TCP_BLOCKING_TIME_NORMAL",
     "PRCLOSE_TCP_BLOCKING_TIME_OFFLINE",
     "PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN",
     "PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE",
     "PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE",
     "PRCLOSE_UDP_BLOCKING_TIME_NORMAL",
@@ -821,20 +687,18 @@
     "SEARCH_SERVICE_INIT_MS",
     "SECURITY_UI",
     "SERVICE_WORKER_CONTROLLED_DOCUMENTS",
     "SERVICE_WORKER_LIFE_TIME",
     "SERVICE_WORKER_REGISTRATIONS",
     "SERVICE_WORKER_REGISTRATION_LOADING",
     "SERVICE_WORKER_REQUEST_PASSTHROUGH",
     "SERVICE_WORKER_SPAWN_ATTEMPTS",
-    "SERVICE_WORKER_SPAWN_GETS_QUEUED",
     "SERVICE_WORKER_UPDATED",
     "SERVICE_WORKER_WAS_SPAWNED",
-    "SHARED_WORKER_SPAWN_GETS_QUEUED",
     "SHOULD_AUTO_DETECT_LANGUAGE",
     "SHOULD_TRANSLATION_UI_APPEAR",
     "SHUTDOWN_OK",
     "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE",
     "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN",
     "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION",
     "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN",
     "SLOW_ADDON_WARNING_RESPONSE_TIME",
@@ -860,50 +724,16 @@
     "SPDY_SETTINGS_RETRANS",
     "SPDY_SETTINGS_RTT",
     "SPDY_SETTINGS_UL_BW",
     "SPDY_SYN_RATIO",
     "SPDY_SYN_REPLY_RATIO",
     "SPDY_SYN_REPLY_SIZE",
     "SPDY_SYN_SIZE",
     "SPDY_VERSION2",
-    "SSL_AUTH_ALGORITHM_FULL",
-    "SSL_AUTH_ECDSA_CURVE_FULL",
-    "SSL_AUTH_RSA_KEY_SIZE_FULL",
-    "SSL_BYTES_BEFORE_CERT_CALLBACK",
-    "SSL_CERT_ERROR_OVERRIDES",
-    "SSL_CIPHER_SUITE_FULL",
-    "SSL_CIPHER_SUITE_RESUMED",
-    "SSL_HANDSHAKE_TYPE",
-    "SSL_HANDSHAKE_VERSION",
-    "SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX",
-    "SSL_KEA_DHE_KEY_SIZE_FULL",
-    "SSL_KEA_ECDHE_CURVE_FULL",
-    "SSL_KEA_RSA_KEY_SIZE_FULL",
-    "SSL_KEY_EXCHANGE_ALGORITHM_FULL",
-    "SSL_KEY_EXCHANGE_ALGORITHM_RESUMED",
-    "SSL_NPN_TYPE",
-    "SSL_OCSP_MAY_FETCH",
-    "SSL_OCSP_STAPLING",
-    "SSL_REASONS_FOR_NOT_FALSE_STARTING",
-    "SSL_RESUMED_SESSION",
-    "SSL_SERVER_AUTH_EKU",
-    "SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX",
-    "SSL_SYMMETRIC_CIPHER_FULL",
-    "SSL_SYMMETRIC_CIPHER_RESUMED",
-    "SSL_TIME_UNTIL_HANDSHAKE_FINISHED",
-    "SSL_TIME_UNTIL_READY",
-    "SSL_TLS10_INTOLERANCE_REASON_POST",
-    "SSL_TLS10_INTOLERANCE_REASON_PRE",
-    "SSL_TLS11_INTOLERANCE_REASON_POST",
-    "SSL_TLS11_INTOLERANCE_REASON_PRE",
-    "SSL_TLS12_INTOLERANCE_REASON_POST",
-    "SSL_TLS12_INTOLERANCE_REASON_PRE",
-    "SSL_VERSION_FALLBACK_INAPPROPRIATE",
-    "SSL_WEAK_CIPHERS_FALLBACK",
     "STARTUP_CACHE_AGE_HOURS",
     "STARTUP_CRASH_DETECTED",
     "STARTUP_MEASUREMENT_ERRORS",
     "STS_NUMBER_OF_ONSOCKETREADY_CALLS",
     "STS_NUMBER_OF_PENDING_EVENTS",
     "STS_NUMBER_OF_PENDING_EVENTS_IN_THE_LAST_CYCLE",
     "STS_POLL_AND_EVENTS_CYCLE",
     "STS_POLL_AND_EVENT_THE_LAST_CYCLE",
@@ -1172,128 +1002,33 @@
     "DECODER_INSTANTIATED_MACHEBREW",
     "DECODER_INSTANTIATED_MACICELANDIC",
     "DECODER_INSTANTIATED_MACROMANIAN",
     "DECODER_INSTANTIATED_MACTURKISH",
     "DEFECTIVE_PERMISSIONS_SQL_REMOVED",
     "DEFERRED_FINALIZE_ASYNC",
     "DENIED_TRANSLATION_OFFERS",
     "DEVICE_RESET_REASON",
-    "DEVTOOLS_ABOUTDEBUGGING_OPENED_BOOLEAN",
     "DEVTOOLS_ABOUTDEBUGGING_OPENED_PER_USER_FLAG",
     "DEVTOOLS_ABOUTDEBUGGING_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_BOOLEAN",
     "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_BROWSERCONSOLE_OPENED_BOOLEAN",
     "DEVTOOLS_BROWSERCONSOLE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_BROWSERCONSOLE_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_CANVASDEBUGGER_OPENED_BOOLEAN",
     "DEVTOOLS_CANVASDEBUGGER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_CANVASDEBUGGER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_COMPUTEDVIEW_OPENED_BOOLEAN",
     "DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG",
     "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_CUSTOM_OPENED_BOOLEAN",
     "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
     "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_LOCAL_MS",
     "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_REMOTE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ADDONDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ASSIGN_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_BINDINGS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_BLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_CLIENTEVALUATE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DELETE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DISPLAYSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ENUMPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_EVENTLISTENERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_FRAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_GET_EXECUTABLE_LINES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_INTERRUPT_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTADDONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTPROCESSES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTSERVICEWORKERREGISTRATIONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTWORKERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_NAVIGATETO_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_OWNPROPERTYNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PARAMETERNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROPERTY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOCOLDESCRIPTION_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPEANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPESANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELEASEMANY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELEASE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELOAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SCOPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SOURCES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_STARTTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_STOPTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SUBSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADGRIPS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_TRACERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_UNBLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_WORKERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ADDONDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ASSIGN_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_BINDINGS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_BLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_CLIENTEVALUATE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DELETE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DISPLAYSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ENUMPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_EVENTLISTENERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_FRAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_GET_EXECUTABLE_LINES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_INTERRUPT_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTADDONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTPROCESSES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTSERVICEWORKERREGISTRATIONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTTABS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTWORKERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_NAVIGATETO_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_OWNPROPERTYNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PARAMETERNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROPERTY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOCOLDESCRIPTION_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPEANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPESANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETAB_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETHREAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELEASEMANY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELEASE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELOAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RESUME_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SCOPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SOURCES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_STARTTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_STOPTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SUBSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_TABDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_THREADDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_THREADGRIPS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_TRACERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_UNBLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_WORKERDETACH_MS",
-    "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN",
     "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_DEVELOPERTOOLBAR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN",
     "DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_FONTINSPECTOR_OPENED_BOOLEAN",
     "DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT",
     "DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT",
     "DEVTOOLS_HUD_APP_MEMORY_CONTENTINTERACTIVE_V2",
     "DEVTOOLS_HUD_APP_MEMORY_FULLYLOADED_V2",
     "DEVTOOLS_HUD_APP_MEMORY_MEDIAENUMERATED_V2",
     "DEVTOOLS_HUD_APP_MEMORY_NAVIGATIONINTERACTIVE_V2",
@@ -1309,115 +1044,86 @@
     "DEVTOOLS_HUD_APP_STARTUP_TIME_VISUALLYLOADED",
     "DEVTOOLS_HUD_ERRORS",
     "DEVTOOLS_HUD_JANK",
     "DEVTOOLS_HUD_REFLOWS",
     "DEVTOOLS_HUD_REFLOW_DURATION",
     "DEVTOOLS_HUD_SECURITY_CATEGORY",
     "DEVTOOLS_HUD_USS",
     "DEVTOOLS_HUD_WARNINGS",
-    "DEVTOOLS_INSPECTOR_OPENED_BOOLEAN",
     "DEVTOOLS_INSPECTOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_INSPECTOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_BOOLEAN",
     "DEVTOOLS_JSBROWSERDEBUGGER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_JSBROWSERDEBUGGER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_JSDEBUGGER_OPENED_BOOLEAN",
     "DEVTOOLS_JSDEBUGGER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_JSDEBUGGER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_JSPROFILER_OPENED_BOOLEAN",
     "DEVTOOLS_JSPROFILER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_JSPROFILER_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_LAYOUTVIEW_OPENED_BOOLEAN",
-    "DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_MEMORY_OPENED_BOOLEAN",
     "DEVTOOLS_MEMORY_OPENED_PER_USER_FLAG",
     "DEVTOOLS_MEMORY_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_MENU_EYEDROPPER_OPENED_BOOLEAN",
     "DEVTOOLS_MENU_EYEDROPPER_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_NETMONITOR_OPENED_BOOLEAN",
     "DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_OPTIONS_OPENED_BOOLEAN",
     "DEVTOOLS_OPTIONS_OPENED_PER_USER_FLAG",
     "DEVTOOLS_OPTIONS_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_OS_ENUMERATED_PER_USER",
     "DEVTOOLS_OS_IS_64_BITS_PER_USER",
-    "DEVTOOLS_PAINTFLASHING_OPENED_BOOLEAN",
     "DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG",
     "DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_PERFTOOLS_CONSOLE_RECORDING_COUNT",
     "DEVTOOLS_PERFTOOLS_RECORDING_COUNT",
     "DEVTOOLS_PERFTOOLS_RECORDING_DURATION_MS",
     "DEVTOOLS_PERFTOOLS_RECORDING_EXPORT_FLAG",
     "DEVTOOLS_PERFTOOLS_RECORDING_FEATURES_USED",
     "DEVTOOLS_PERFTOOLS_RECORDING_IMPORT_FLAG",
     "DEVTOOLS_PERFTOOLS_SELECTED_VIEW_MS",
-    "DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN",
     "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG",
     "DEVTOOLS_READ_HEAP_SNAPSHOT_MS",
-    "DEVTOOLS_RESPONSIVE_OPENED_BOOLEAN",
     "DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_RULEVIEW_OPENED_BOOLEAN",
     "DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG",
     "DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS",
-    "DEVTOOLS_SCRATCHPAD_OPENED_BOOLEAN",
     "DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG",
     "DEVTOOLS_SCRATCHPAD_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER",
-    "DEVTOOLS_SHADEREDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_SHADEREDITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_SHADEREDITOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_STORAGE_OPENED_BOOLEAN",
     "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_STYLEEDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_STYLEEDITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_STYLEEDITOR_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_TABS_OPEN_AVERAGE_LINEAR",
     "DEVTOOLS_TABS_OPEN_PEAK_LINEAR",
     "DEVTOOLS_TABS_PINNED_AVERAGE_LINEAR",
     "DEVTOOLS_TABS_PINNED_PEAK_LINEAR",
-    "DEVTOOLS_TILT_OPENED_BOOLEAN",
     "DEVTOOLS_TILT_OPENED_PER_USER_FLAG",
     "DEVTOOLS_TILT_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_TOOLBOX_OPENED_BOOLEAN",
     "DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG",
     "DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_WEBAUDIOEDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_WEBAUDIOEDITOR_OPENED_PER_USER_FLAG",
     "DEVTOOLS_WEBAUDIOEDITOR_TIME_ACTIVE_SECONDS",
-    "DEVTOOLS_WEBCONSOLE_OPENED_BOOLEAN",
     "DEVTOOLS_WEBCONSOLE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_WEBCONSOLE_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE",
     "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION",
     "DEVTOOLS_WEBIDE_CONNECTION_DEBUG_USED",
     "DEVTOOLS_WEBIDE_CONNECTION_PLAY_USED",
     "DEVTOOLS_WEBIDE_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS",
-    "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN",
     "DEVTOOLS_WEBIDE_IMPORT_PROJECT_PER_USER_FLAG",
     "DEVTOOLS_WEBIDE_LOCAL_CONNECTION_RESULT",
-    "DEVTOOLS_WEBIDE_NEW_PROJECT_BOOLEAN",
     "DEVTOOLS_WEBIDE_NEW_PROJECT_PER_USER_FLAG",
-    "DEVTOOLS_WEBIDE_OPENED_BOOLEAN",
     "DEVTOOLS_WEBIDE_OPENED_PER_USER_FLAG",
     "DEVTOOLS_WEBIDE_OTHER_CONNECTION_RESULT",
-    "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_BOOLEAN",
     "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_PER_USER_FLAG",
-    "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_BOOLEAN",
     "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_PER_USER_FLAG",
     "DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_WEBIDE_REMOTE_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_SIMULATOR_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS",
     "DEVTOOLS_WEBIDE_USB_CONNECTION_RESULT",
     "DEVTOOLS_WEBIDE_WIFI_CONNECTION_RESULT",
     "DISPLAY_SCALING_LINUX",
@@ -1431,44 +1137,38 @@
     "DNS_RENEWAL_TIME",
     "DNS_RENEWAL_TIME_FOR_TTL",
     "DNT_USAGE",
     "DWRITEFONT_DELAYEDINITFONTLIST_COLLECT",
     "DWRITEFONT_DELAYEDINITFONTLIST_COUNT",
     "DWRITEFONT_DELAYEDINITFONTLIST_TOTAL",
     "DWRITEFONT_INIT_PROBLEM",
     "E10S_BLOCKED_FROM_RUNNING",
-    "E10S_STILL_ACCEPTED_FROM_PROMPT",
     "E10S_WINDOW",
     "ENABLE_PRIVILEGE_EVER_CALLED",
     "FENNEC_DISTRIBUTION_CODE_CATEGORY",
     "FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS",
     "FENNEC_DISTRIBUTION_REFERRER_INVALID",
-    "FENNEC_GECKOAPP_STARTUP_ACTION",
     "FENNEC_GLOBALHISTORY_ADD_MS",
     "FENNEC_GLOBALHISTORY_UPDATE_MS",
     "FENNEC_GLOBALHISTORY_VISITED_BUILD_MS",
-    "FENNEC_READER_VIEW_BUTTON",
     "FENNEC_READING_LIST_COUNT",
     "FENNEC_RESTORING_ACTIVITY",
     "FENNEC_SEARCH_LOADER_TIME_MS",
     "FENNEC_STARTUP_TIME_GECKOREADY",
     "FENNEC_STARTUP_TIME_JAVAUI",
     "FENNEC_SYNC11_MIGRATIONS_COMPLETED",
     "FENNEC_SYNC11_MIGRATIONS_FAILED",
     "FENNEC_SYNC11_MIGRATIONS_SUCCEEDED",
     "FENNEC_SYNC11_MIGRATION_NOTIFICATIONS_OFFERED",
     "FENNEC_SYNC11_MIGRATION_SENTINELS_SEEN",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_COMPLETED",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_FAILED",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_FAILED_BACKOFF",
     "FENNEC_SYNC_NUMBER_OF_SYNCS_STARTED",
-    "FENNEC_TABQUEUE_ENABLED",
-    "FENNEC_TABQUEUE_PROMPT_ENABLE_NO",
-    "FENNEC_TABQUEUE_PROMPT_ENABLE_YES",
     "FENNEC_TABQUEUE_QUEUESIZE",
     "FENNEC_TOPSITES_LOADER_TIME_MS",
     "FENNEC_WAS_KILLED",
     "FETCH_IS_MAINTHREAD",
     "FIND_PLUGINS",
     "FLASH_PLUGIN_AREA",
     "FLASH_PLUGIN_HEIGHT",
     "FLASH_PLUGIN_INSTANCES_ON_PAGE",
@@ -1486,24 +1186,21 @@
     "FX_MIGRATION_ENTRY_POINT",
     "FX_MIGRATION_ERRORS",
     "FX_MIGRATION_HOMEPAGE_IMPORTED",
     "FX_MIGRATION_SOURCE_BROWSER",
     "FX_MIGRATION_USAGE",
     "FX_NEW_WINDOW_MS",
     "FX_PAGE_LOAD_MS",
     "FX_SANITIZE_CACHE",
-    "FX_SANITIZE_COOKIES",
     "FX_SANITIZE_COOKIES_2",
     "FX_SANITIZE_DOWNLOADS",
     "FX_SANITIZE_FORMDATA",
     "FX_SANITIZE_HISTORY",
-    "FX_SANITIZE_OFFLINEAPPS",
     "FX_SANITIZE_OPENWINDOWS",
-    "FX_SANITIZE_PLUGINS",
     "FX_SANITIZE_SESSIONS",
     "FX_SANITIZE_SITESETTINGS",
     "FX_SANITIZE_TOTAL",
     "FX_SESSION_RESTORE_ALL_FILES_CORRUPT",
     "FX_SESSION_RESTORE_AUTO_RESTORE_DURATION_UNTIL_EAGER_TABS_RESTORED_MS",
     "FX_SESSION_RESTORE_COLLECT_ALL_WINDOWS_DATA_MS",
     "FX_SESSION_RESTORE_COLLECT_COOKIES_MS",
     "FX_SESSION_RESTORE_COLLECT_DATA_LONGEST_OP_MS",
@@ -1649,33 +1346,31 @@
     "HTTP_SUB_OPEN_TO_FIRST_FROM_CACHE_V2",
     "HTTP_SUB_OPEN_TO_FIRST_RECEIVED",
     "HTTP_SUB_OPEN_TO_FIRST_SENT",
     "HTTP_SUB_REVALIDATION",
     "HTTP_SUB_TCP_CONNECTION",
     "HTTP_TRANSACTION_IS_SSL",
     "HTTP_TRANSACTION_USE_ALTSVC",
     "HTTP_TRANSACTION_USE_ALTSVC_OE",
-    "IDLE_NOTIFY_IDLE_MS",
     "IMAGE_DECODE_CHUNKS",
     "IMAGE_DECODE_COUNT",
     "IMAGE_DECODE_LATENCY_US",
     "IMAGE_DECODE_ON_DRAW_LATENCY",
     "IMAGE_DECODE_SPEED_GIF",
     "IMAGE_DECODE_SPEED_JPEG",
     "IMAGE_DECODE_SPEED_PNG",
     "IMAGE_DECODE_TIME",
     "INNERWINDOWS_WITH_MUTATION_LISTENERS",
     "IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB",
     "IPC_TRANSACTION_CANCEL",
     "IPV4_AND_IPV6_ADDRESS_CONNECTIVITY",
     "JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS",
     "JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT",
     "JS_TELEMETRY_ADDON_EXCEPTIONS",
-    "KEYGEN_GENERATED_KEY_TYPE",
     "LINK_ICON_SIZES_ATTR_DIMENSION",
     "LINK_ICON_SIZES_ATTR_USAGE",
     "LOCALDOMSTORAGE_CLEAR_BLOCKING_MS",
     "LOCALDOMSTORAGE_GETALLKEYS_BLOCKING_MS",
     "LOCALDOMSTORAGE_GETKEY_BLOCKING_MS",
     "LOCALDOMSTORAGE_GETLENGTH_BLOCKING_MS",
     "LOCALDOMSTORAGE_GETVALUE_BLOCKING_MS",
     "LOCALDOMSTORAGE_PRELOAD_PENDING_ON_FIRST_ACCESS",
@@ -1703,20 +1398,16 @@
     "LOOP_ICE_SUCCESS_RATE",
     "LOOP_ICE_SUCCESS_TIME",
     "LOOP_MAX_AUDIO_RECEIVE_TRACK",
     "LOOP_MAX_AUDIO_SEND_TRACK",
     "LOOP_MAX_VIDEO_RECEIVE_TRACK",
     "LOOP_MAX_VIDEO_SEND_TRACK",
     "LOOP_RENEGOTIATIONS",
     "LOOP_ROOM_CREATE",
-    "LOOP_ROOM_DELETE",
-    "LOOP_ROOM_SESSION_WITHCHAT",
-    "LOOP_SHARING_ROOM_URL",
-    "LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1",
     "LOOP_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS",
     "LOOP_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS",
     "LOOP_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM",
     "LOOP_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL",
     "LOOP_VIDEO_DECODER_FRAMERATE_AVG_PER_CALL",
     "LOOP_VIDEO_DECODE_ERROR_TIME_PERMILLE",
     "LOOP_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS",
     "LOOP_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS",
@@ -1734,17 +1425,16 @@
     "LOW_MEMORY_EVENTS_VIRTUAL",
     "MAC_INITFONTLIST_TOTAL",
     "MASTER_PASSWORD_ENABLED",
     "MEDIA_CODEC_USED",
     "MEDIA_WMF_DECODE_ERROR",
     "MEMORY_FREE_PURGED_PAGES_MS",
     "MEMORY_HEAP_ALLOCATED",
     "MEMORY_HEAP_COMMITTED_UNUSED",
-    "MEMORY_HEAP_COMMITTED_UNUSED_RATIO",
     "MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED",
     "MEMORY_JS_COMPARTMENTS_SYSTEM",
     "MEMORY_JS_COMPARTMENTS_USER",
     "MEMORY_JS_GC_HEAP",
     "MEMORY_STORAGE_SQLITE",
     "MEMORY_VSIZE",
     "MEMORY_VSIZE_MAX_CONTIGUOUS",
     "MIXED_CONTENT_HSTS",
@@ -1784,17 +1474,16 @@
     "MOZ_SQLITE_WEBAPPS_READ_MS",
     "MOZ_SQLITE_WEBAPPS_SYNC_MAIN_THREAD_MS",
     "MOZ_SQLITE_WEBAPPS_SYNC_MS",
     "MOZ_SQLITE_WEBAPPS_WRITE_B",
     "MOZ_SQLITE_WEBAPPS_WRITE_MAIN_THREAD_MS",
     "MOZ_SQLITE_WEBAPPS_WRITE_MS",
     "MOZ_STORAGE_ASYNC_REQUESTS_MS",
     "MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS",
-    "NETWORK_AUTODIAL",
     "NETWORK_CACHE_FS_TYPE",
     "NETWORK_CACHE_HASH_STATS",
     "NETWORK_CACHE_HIT_MISS_STAT_PER_CACHE_SIZE",
     "NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE",
     "NETWORK_CACHE_METADATA_FIRST_READ_SIZE",
     "NETWORK_CACHE_METADATA_FIRST_READ_TIME_MS",
     "NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS",
     "NETWORK_CACHE_METADATA_SIZE",
@@ -1880,29 +1569,24 @@
     "PLACES_TAGGED_BOOKMARKS_PERC",
     "PLACES_TAGS_COUNT",
     "PLUGINS_INFOBAR_ALLOW",
     "PLUGINS_INFOBAR_BLOCK",
     "PLUGINS_INFOBAR_SHOWN",
     "PLUGINS_NOTIFICATION_PLUGIN_COUNT",
     "PLUGINS_NOTIFICATION_SHOWN",
     "PLUGINS_NOTIFICATION_USER_ACTION",
-    "PLUGIN_ACTIVATION_COUNT",
     "PLUGIN_CALLED_DIRECTLY",
     "PLUGIN_HANG_NOTICE_COUNT",
     "PLUGIN_HANG_TIME",
     "PLUGIN_HANG_UI_DONT_ASK",
     "PLUGIN_HANG_UI_RESPONSE_TIME",
     "PLUGIN_HANG_UI_USER_RESPONSE",
     "PLUGIN_LOAD_METADATA",
     "PLUGIN_SHUTDOWN_MS",
-    "PLUGIN_STARTUP_MS",
-    "POPUP_NOTIFICATION_DISMISSAL_MS",
-    "POPUP_NOTIFICATION_MAIN_ACTION_MS",
-    "POPUP_NOTIFICATION_STATS",
     "PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE",
     "PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE",
     "PRCLOSE_TCP_BLOCKING_TIME_NORMAL",
     "PRCLOSE_TCP_BLOCKING_TIME_OFFLINE",
     "PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN",
     "PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE",
     "PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE",
     "PRCLOSE_UDP_BLOCKING_TIME_NORMAL",
@@ -1973,21 +1657,18 @@
     "PWMGR_NUM_PASSWORDS_PER_HOSTNAME",
     "PWMGR_NUM_SAVED_PASSWORDS",
     "PWMGR_PASSWORD_INPUT_IN_FORM",
     "PWMGR_PROMPT_REMEMBER_ACTION",
     "PWMGR_PROMPT_UPDATE_ACTION",
     "PWMGR_SAVING_ENABLED",
     "PWMGR_USERNAME_PRESENT",
     "RANGE_CHECKSUM_ERRORS",
-    "READER_MODE_DOWNLOAD_MS",
     "READER_MODE_DOWNLOAD_RESULT",
     "READER_MODE_PARSE_RESULT",
-    "READER_MODE_SERIALIZE_DOM_MS",
-    "READER_MODE_WORKER_PARSE_MS",
     "REFRESH_DRIVER_TICK",
     "REQUESTS_OF_ORIGINAL_CONTENT",
     "SAFE_MODE_USAGE",
     "SEARCH_COUNTS",
     "SEARCH_SERVICE_COUNTRY_FETCH_CAUSED_SYNC_INIT",
     "SEARCH_SERVICE_COUNTRY_FETCH_RESULT",
     "SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS",
     "SEARCH_SERVICE_COUNTRY_TIMEOUT",
@@ -2001,20 +1682,18 @@
     "SEARCH_SERVICE_US_TIMEZONE_MISMATCHED_COUNTRY",
     "SECURITY_UI",
     "SERVICE_WORKER_CONTROLLED_DOCUMENTS",
     "SERVICE_WORKER_LIFE_TIME",
     "SERVICE_WORKER_REGISTRATIONS",
     "SERVICE_WORKER_REGISTRATION_LOADING",
     "SERVICE_WORKER_REQUEST_PASSTHROUGH",
     "SERVICE_WORKER_SPAWN_ATTEMPTS",
-    "SERVICE_WORKER_SPAWN_GETS_QUEUED",
     "SERVICE_WORKER_UPDATED",
     "SERVICE_WORKER_WAS_SPAWNED",
-    "SHARED_WORKER_SPAWN_GETS_QUEUED",
     "SHOULD_AUTO_DETECT_LANGUAGE",
     "SHOULD_TRANSLATION_UI_APPEAR",
     "SHUTDOWN_OK",
     "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE",
     "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN",
     "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION",
     "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN",
     "SLOW_ADDON_WARNING_RESPONSE_TIME",
@@ -2050,17 +1729,16 @@
     "SSL_AUTH_ECDSA_CURVE_FULL",
     "SSL_AUTH_RSA_KEY_SIZE_FULL",
     "SSL_BYTES_BEFORE_CERT_CALLBACK",
     "SSL_CERT_ERROR_OVERRIDES",
     "SSL_CERT_VERIFICATION_ERRORS",
     "SSL_CIPHER_SUITE_FULL",
     "SSL_CIPHER_SUITE_RESUMED",
     "SSL_HANDSHAKE_TYPE",
-    "SSL_HANDSHAKE_VERSION",
     "SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX",
     "SSL_KEA_DHE_KEY_SIZE_FULL",
     "SSL_KEA_ECDHE_CURVE_FULL",
     "SSL_KEA_RSA_KEY_SIZE_FULL",
     "SSL_KEY_EXCHANGE_ALGORITHM_FULL",
     "SSL_KEY_EXCHANGE_ALGORITHM_RESUMED",
     "SSL_NPN_TYPE",
     "SSL_OBSERVED_END_ENTITY_CERTIFICATE_LIFETIME",
@@ -2366,142 +2044,54 @@
     "UPDATE_STATUS_ERROR_CODE_COMPLETE_STARTUP",
     "UPDATE_STATUS_ERROR_CODE_PARTIAL_STARTUP",
     "UPDATE_STATUS_ERROR_CODE_UNKNOWN_STARTUP",
     "UPDATE_STATUS_ERROR_CODE_COMPLETE_STAGE",
     "UPDATE_STATUS_ERROR_CODE_PARTIAL_STAGE",
     "UPDATE_STATUS_ERROR_CODE_UNKNOWN_STAGE",
     "SECURITY_UI",
     "CRASH_STORE_COMPRESSED_BYTES",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELOAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELOAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_NAVIGATETO_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_NAVIGATETO_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_EVENTLISTENERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_EVENTLISTENERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RESUME_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RESUME_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_INTERRUPT_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_INTERRUPT_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_CLIENTEVALUATE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_CLIENTEVALUATE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELEASEMANY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELEASEMANY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADGRIPS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_THREADGRIPS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SOURCES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SOURCES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_FRAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_FRAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PARAMETERNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PARAMETERNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_OWNPROPERTYNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_OWNPROPERTYNAMES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPEANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPEANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ENUMPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ENUMPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPESANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPESANDPROPERTIES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROPERTY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROPERTY_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOTYPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOTYPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DISPLAYSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DISPLAYSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SUBSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SUBSTRING_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RELEASE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RELEASE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTTABS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTTABS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOCOLDESCRIPTION_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOCOLDESCRIPTION_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTADDONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTADDONS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTWORKERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTWORKERS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTPROCESSES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTPROCESSES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_DELETE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_DELETE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_THREADDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_THREADDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ADDONDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ADDONDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_TABDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_TABDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_WORKERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_WORKERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_LOCAL_MS",
-    "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_REMOTE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETAB_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETHREAD_MS",
     "MEDIA_WMF_DECODE_ERROR",
     "VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG",
     "VIDEO_CANPLAYTYPE_H264_PROFILE",
     "VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG",
     "VIDEO_DECODED_H264_SPS_PROFILE",
-    "WEBRTC_CANDIDATE_TYPES_GIVEN_SUCCESS",
-    "WEBRTC_CANDIDATE_TYPES_GIVEN_FAILURE",
     "WEBRTC_AVSYNC_WHEN_AUDIO_LAGS_VIDEO_MS",
     "WEBRTC_AVSYNC_WHEN_VIDEO_LAGS_AUDIO_MS",
     "WEBRTC_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS",
     "WEBRTC_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS",
     "WEBRTC_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS",
     "WEBRTC_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS",
     "WEBRTC_AUDIO_QUALITY_INBOUND_JITTER",
     "WEBRTC_VIDEO_QUALITY_OUTBOUND_JITTER",
     "WEBRTC_AUDIO_QUALITY_OUTBOUND_JITTER",
     "WEBRTC_VIDEO_ERROR_RECOVERY_MS",
     "WEBRTC_VIDEO_RECOVERY_BEFORE_ERROR_PER_MIN",
     "WEBRTC_VIDEO_RECOVERY_AFTER_ERROR_PER_MIN",
     "WEBRTC_VIDEO_QUALITY_OUTBOUND_RTT",
     "WEBRTC_AUDIO_QUALITY_OUTBOUND_RTT",
     "WEBRTC_CALL_DURATION",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_TRACERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_TRACERDETACH_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_STARTTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_STARTTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_STOPTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_STOPTRACE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_GET_EXECUTABLE_LINES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_GET_EXECUTABLE_LINES_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_BLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_BLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_UNBLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_UNBLACKBOX_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_SCOPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_SCOPE_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_BINDINGS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_BINDINGS_MS",
-    "DEVTOOLS_DEBUGGER_RDP_LOCAL_ASSIGN_MS",
-    "DEVTOOLS_DEBUGGER_RDP_REMOTE_ASSIGN_MS",
+    "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_LOCAL_MS",
+    "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_REMOTE_MS",
     "DEVTOOLS_SAVE_HEAP_SNAPSHOT_MS",
     "DEVTOOLS_READ_HEAP_SNAPSHOT_MS",
     "DEVTOOLS_HEAP_SNAPSHOT_NODE_COUNT",
     "DEVTOOLS_HEAP_SNAPSHOT_EDGE_COUNT",
     "NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE",
     "NETWORK_CACHE_METADATA_FIRST_READ_SIZE",
     "NETWORK_CACHE_METADATA_SIZE",
     "NETWORK_CACHE_HASH_STATS",
     "SSL_CIPHER_SUITE_FULL",
     "SSL_CIPHER_SUITE_RESUMED",
     "SSL_REASONS_FOR_NOT_FALSE_STARTING",
     "SSL_CERT_VERIFICATION_ERRORS",
     "CERT_VALIDATION_SUCCESS_BY_CA",
     "CERT_PINNING_FAILURES_BY_CA",
     "CERT_PINNING_MOZ_RESULTS_BY_HOST",
     "CERT_PINNING_MOZ_TEST_RESULTS_BY_HOST",
-    "LOOP_CANDIDATE_TYPES_GIVEN_SUCCESS",
-    "LOOP_CANDIDATE_TYPES_GIVEN_FAILURE",
     "LOOP_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS",
     "LOOP_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS",
     "LOOP_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS",
     "LOOP_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS",
     "LOOP_VIDEO_ERROR_RECOVERY_MS",
     "LOOP_VIDEO_RECOVERY_BEFORE_ERROR_PER_MIN",
     "LOOP_VIDEO_RECOVERY_AFTER_ERROR_PER_MIN",
     "LOOP_VIDEO_QUALITY_OUTBOUND_RTT",
--- a/toolkit/components/telemetry/histogram_tools.py
+++ b/toolkit/components/telemetry/histogram_tools.py
@@ -1,13 +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/.
 
 import collections
+import itertools
 import json
 import math
 import os
 import re
 import sys
 
 # Constants.
 MAX_LABEL_LENGTH = 20
@@ -290,26 +291,30 @@ associated with the histogram.  Returns 
         if len(invalid) > 0:
             raise ValueError, 'Label values for %s are not matching pattern "%s": %s' % \
                               (name, pattern, ', '.join(invalid))
 
     # Check for the presence of fields that old histograms are whitelisted for.
     def check_whitelistable_fields(self, name, definition):
         # Use counters don't have any mechanism to add the fields checked here,
         # so skip the check for them.
-        if self._is_use_counter:
+        # We also don't need to run any of these checks on the server.
+        if self._is_use_counter or not self._strict_type_checks:
             return
 
         # In the pipeline we don't have whitelists available.
         if whitelists is None:
             return
 
         for field in ['alert_emails', 'bug_numbers']:
             if field not in definition and name not in whitelists[field]:
                 raise KeyError, 'New histogram "%s" must have a %s field.' % (name, field)
+            if field in definition and name in whitelists[field]:
+                msg = 'Should remove histogram "%s" from the whitelist for "%s" in histogram-whitelists.json'
+                raise KeyError, msg % (name, field)
 
     def check_field_types(self, name, definition):
         # Define expected types for the histogram properties.
         type_checked_fields = {
             "n_buckets": int,
             "n_values": int,
             "low": int,
             "high": int,
@@ -485,10 +490,18 @@ the histograms defined in filenames.
                                  enumerate(all_histograms.iterkeys()));
     if use_counter_indices:
         lower_bound = use_counter_indices[0][0]
         upper_bound = use_counter_indices[-1][0]
         n_counters = upper_bound - lower_bound + 1
         if n_counters != len(use_counter_indices):
             raise DefinitionException, "use counter histograms must be defined in a contiguous block"
 
+    # Check that histograms that were removed from Histograms.json etc. are also removed from the whitelists.
+    if whitelists is not None:
+        all_whitelist_entries = itertools.chain.from_iterable(whitelists.itervalues())
+        orphaned = set(all_whitelist_entries) - set(all_histograms.keys())
+        if len(orphaned) > 0:
+            msg = 'The following entries are orphaned and should be removed from histogram-whitelists.json: %s'
+            raise BaseException, msg % (', '.join(sorted(orphaned)))
+
     for (name, definition) in all_histograms.iteritems():
         yield Histogram(name, definition, strict_type_checks=True)