Merge fx-team to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 10 Aug 2016 16:53:40 -0700
changeset 399408 0502bd9e025edde29777ba1de4280f9b52af4663
parent 399392 dc8f8117d67b5ae9c7b42b72e3567ef5e754b1fa (current diff)
parent 399322 4caf18e4aaca92756f79b2cba666073fe76eabb7 (diff)
child 399409 c05296c94ec6785752f7a99c53985dd208815a89
child 399428 1ad0aafcbe6c20cb0e0f8f392016af6b3801c4b7
child 399432 299f74691984cdb9d42fed03f2b59b41d047c7d2
child 399433 d13e7744b9616be697ae36a280b695d6d5cedae5
child 399436 3b2628fc0405650b85e33ecbd8b6dbde1ad38c6f
child 399438 4c93c2309bb2bc9dac10e91513ad0ba933ede5a7
child 399458 219cb729690af81c59c017f784a51306ab0ba911
child 399487 8ba6067aadb735f80aca04a1149d2b31b2f0f07e
child 399491 6847f65155fb32e4a276a1e1c7e402bc13386b9b
child 399493 0a90307ab8c9ca4104aa4ddd0ff8822810d315d3
child 399494 2d5b96b20fa5a209b5c47faf55da19ae0b3730f0
child 399503 2991f912c66c511af60a58dffec5d2c4b2d2aad4
child 399512 9ef089d3a93cb5bf470c244a5f97957de9ad3272
child 399515 e3f5f9b265be8e107e4ab1a55a9c1598ed7c11a1
child 399561 d0af37c375d398062f64f68e773115b91428d567
child 399565 23f587bbd4bb45d878d20e29f006b71132fc6127
child 399568 a838e9b01f4526db62524406e9bf5f963391b671
child 399571 41e34bab1070349816efb4fb8f951bcd8e1a79bf
child 399574 6c1be49ece8a7cdcaa21fed980df63dce574f2b2
child 399575 111e05169271980ca000816eda3d1d71de650225
child 399577 61594da93eb6bacae58253bd3c9fc059349684f4
child 399578 1e75026f6a1aa05ba5efd63b24395a36ada7001d
child 399600 51dcd49ef9841fcbd4dad5ed841c46cf06f80d8e
child 399605 12a5c927de8d9cbb76c389f496aa2b9abe7477e6
child 399608 762a33957fa9ce501b98706e0ab3b538dff6f751
child 399631 c50708c38f8119fe16a8235aa067fa4934ea0af0
child 399643 5696141cefc4ac2371810e22f3e0c496342f4f8f
child 399648 5471c22912c9430093b23e7dc427367771d3ca8c
child 399652 8b29ee81d2fe98bf610008e29a8b50f31e516797
child 399655 82a8a2b567aab7f199f80cab688fbf9018786ac6
child 399656 ff464753edd4880ecbe149c1479b753b334fea98
child 399657 d62db45537f3981c2aa1f9adb1182c7e8a448e36
child 399658 98557bbbfbfa0a64fae9f757570fecfec813cb95
child 399659 5938fefebd2e48e98e49f224528ac6e7c5d02e35
child 399662 96a2935ff3df11e102ce77762e6a6d622046807f
child 399663 b9845af112afa7ae5beb5b17d881a052bc9001bb
child 399666 217e50c1c091ec83f0e4e0f10b8b3bb697ed305e
child 399667 b21e554b9f79a47f1c09dcf1f7e29de51effe1d6
child 399673 34b2552aa6ee19d9bdc22d4fb781beb3d8954ac4
child 399674 b2b642a54926db30e80617b1eda42034ccb19378
child 399684 418a1a2b21f6e2c93050a2072b34398362c74708
child 399686 be725f2f10399d1a6e5bb2af0d035a1bf0c0764c
child 399698 233ab21b64b5d5e9f2f16ea2d4cfb4c8b293c5c4
child 399737 7d1cc6cf827a18fbcb6115df53a4d391308a2072
child 399788 5cb11278e48374c0e21825cf1a181ed347d1643f
child 399789 945daf53d2c286488bd9b9069b5cbc4166df6929
child 399792 54d9eef4d93cae275b95fab60456b61b6a291787
child 399803 f5d03e28046f72d30d3d9c41787b503fd527a64a
child 399861 2aa7c8620505074aeba012de358d56edf0dc2af5
child 399862 ee874164151fa22e4078a1619e0fa75c4fa347f5
child 399881 7338835a6875d4053fddcf8b8d29c541e22ab5ba
child 399884 1ccc01685655faf7970e5b4c448c4290bf761a1b
child 399885 557e5486b49927d226b32ef5b6e54fd5c279c7cb
child 399887 922d8ff39c19d0a028db9fd318821f94ffd86910
child 399940 337814aad1eb5e9107641707cd70e515557728f4
child 399942 d16da27e7cb8ef09117e8215e2e94a4144c95048
child 399958 1ffca6869b20ae6ea91c72cb8710b32640650b1a
child 400048 a2a3d88d28d0875938104b4352817abeaf7974c9
child 400151 55964621d1e9bdbe6eb8263d80057ae3b45681ed
child 400294 60b1386ecc3613ff5af20ca6933253365e85983a
child 400300 74dae42dc37171ab6d81fca4d398acec3b5146c6
child 400311 e93eaefda71d0dc24456a904fea3a6bbef97140c
child 400629 f6df56a203ee873290d007c5867eec1fbc07716c
child 400630 e56eac40b84ca0fbd79815c156f60ef91f9d652e
child 400639 34c59afd603daa9bfcbe4f542f64f4adc56ad1d8
child 400669 cd5ec15e91f4b73cc8d84a25d6564928bbe5bd8b
child 400670 4dd0a38c1c9db42a0df3ebf73e6b2230de913057
child 400674 870faa262988f559aa9e860d108026b030a99498
child 400676 dc72d9f119c3a586d433130113e621c2ec211d5b
child 400707 55978de8962684f94dca34503812ca8c3c9ecd55
child 400711 73e6051ba8cca2e35b1b15ef84a02b1b5473dceb
child 400721 1bd385ad1b2cf8c999ac75f4f48b726f798519ee
child 400919 1f56b949bfc2a671237a9cf63faa32fb35fd6f3a
child 400931 ab17acd6aef20d0f3bb8e1cfa7f41a9315ea4016
child 400932 637396132e205546b323d9effb3a474f54cf4b59
child 401015 fe5366025e46efb2c7e066847821d0985a972d0e
child 403427 3fb483999b3ff45aa254b24eee33ec5e182c605f
child 406416 0348924fe5a59a23763b09596c554de15e694ea6
child 407925 d6fee002f0882ab52249630fee7acd46772a1d58
child 411756 c8d730e49711f8c7d8dbce5a156fecd0186be05e
child 413147 862b78798ffa94941fdd8086f680a212de40b0f9
child 491559 a7603a12587ad1b6bca823508fa693e97a49e6de
push id25823
push usergarndt@mozilla.com
push dateThu, 11 Aug 2016 01:07:02 +0000
reviewersmerge
milestone51.0a1
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)