Merge autoland to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 02 Dec 2016 12:26:55 -0800
changeset 325115 919596f62a27dbc3275aea5e04572a9ab026c1da
parent 325095 e756ee86e3ea1225d8cdf38ca0eb8b0ded15dd41 (current diff)
parent 325114 1f7832017dbb5c53ba00aef3012b40c873a5005d (diff)
child 325136 633e960e72dbd3006a2d0325416e50a19a7e1838
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersmerge
milestone53.0a1
Merge autoland to central, a=merge
security/manager/ssl/WeakCryptoOverride.cpp
security/manager/ssl/WeakCryptoOverride.h
security/manager/ssl/nsIWeakCryptoOverride.idl
security/manager/ssl/tests/unit/test_weak_crypto.js
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -1018,18 +1018,27 @@ function* loadBadCertPage(url) {
         }
       }
     };
 
     Services.obs.addObserver(certExceptionDialogObserver,
                              "cert-exception-ui-ready", false);
   });
 
-  yield BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
-  yield promiseErrorPageLoaded(gBrowser.selectedBrowser);
+  // Sometimes clearing the cert override is not immediately picked up,
+  // so we reload until we are on an actual cert error page.
+  yield BrowserTestUtils.waitForCondition(function*() {
+    yield BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
+    yield promiseErrorPageLoaded(gBrowser.selectedBrowser);
+    let isErrorPage = yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
+      return content.document.documentURI.startsWith("about:certerror");
+    });
+    return isErrorPage;
+  }, "Could not load error page", 1000);
+
   yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
     content.document.getElementById("exceptionDialogButton").click();
   });
   yield exceptionDialogResolved;
   yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
 }
 
 // Utility function to get a handle on the certificate exception dialog.
--- a/devtools/client/netmonitor/components/moz.build
+++ b/devtools/client/netmonitor/components/moz.build
@@ -1,12 +1,16 @@
 # 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/.
 
+DIRS += [
+    'shared',
+]
+
 DevToolsModules(
     'clear-button.js',
     'filter-buttons.js',
     'request-list-content.js',
     'request-list-empty.js',
     'request-list-header.js',
     'request-list-item.js',
     'request-list-tooltip.js',
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/components/shared/moz.build
@@ -0,0 +1,7 @@
+# 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(
+    'timings-panel.js',
+)
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/components/shared/timings-panel.js
@@ -0,0 +1,85 @@
+/* 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 { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
+const { L10N } = require("../../l10n");
+const { getSelectedRequest } = require("../../selectors/index");
+
+const { div, span } = DOM;
+const types = ["blocked", "dns", "connect", "send", "wait", "receive"];
+const TIMINGS_END_PADDING = "80px";
+
+/*
+ * Timings panel component
+ * Display timeline bars that shows the total wait time for various stages
+ */
+function TimingsPanel({
+  timings = {},
+  totalTime = 0,
+}) {
+  const timelines = types.map((type, idx) => {
+    // Determine the relative offset for each timings box. For example, the
+    // offset of third timings box will be 0 + blocked offset + dns offset
+    const offset = types
+      .slice(0, idx)
+      .reduce((acc, cur) => (acc + timings[cur] || 0), 0);
+    const offsetScale = offset / totalTime || 0;
+    const timelineScale = timings[type] / totalTime || 0;
+
+    return div({
+      key: type,
+      id: `timings-summary-${type}`,
+      className: "tabpanel-summary-container",
+    },
+      span({ className: "tabpanel-summary-label" },
+        L10N.getStr(`netmonitor.timings.${type}`)
+      ),
+      div({ className: "requests-menu-timings-container" },
+        span({
+          className: "requests-menu-timings-offset",
+          style: {
+            width: `calc(${offsetScale} * (100% - ${TIMINGS_END_PADDING})`,
+          },
+        }),
+        span({
+          className: `requests-menu-timings-box ${type}`,
+          style: {
+            width: `calc(${timelineScale} * (100% - ${TIMINGS_END_PADDING}))`,
+          },
+        }),
+        span({ className: "requests-menu-timings-total" },
+          L10N.getFormatStr("networkMenu.totalMS", timings[type])
+        )
+      ),
+    );
+  });
+
+  return div({}, timelines);
+}
+
+TimingsPanel.displayName = "TimingsPanel";
+
+TimingsPanel.propTypes = {
+  timings: PropTypes.object,
+  totalTime: PropTypes.number,
+};
+
+module.exports = connect(
+  (state) => {
+    const selectedRequest = getSelectedRequest(state);
+
+    if (selectedRequest && selectedRequest.eventTimings) {
+      const { timings, totalTime } = selectedRequest.eventTimings;
+      return {
+        timings,
+        totalTime,
+      };
+    }
+
+    return {};
+  }
+)(TimingsPanel);
--- a/devtools/client/netmonitor/details-view.js
+++ b/devtools/client/netmonitor/details-view.js
@@ -22,16 +22,20 @@ const {
   decodeUnicodeUrl,
   formDataURI,
   getFormDataSections,
   getUrlBaseName,
   getUrlQuery,
   getUrlHost,
   parseQueryString,
 } = require("./request-utils");
+const { createFactory } = require("devtools/client/shared/vendor/react");
+const ReactDOM = require("devtools/client/shared/vendor/react-dom");
+const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
+const TimingsPanel = createFactory(require("./components/shared/timings-panel"));
 
 // 100 KB in bytes
 const SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 102400;
 const HEADERS_SIZE_DECIMALS = 3;
 const CONTENT_MIME_TYPE_MAPPINGS = {
   "/ecmascript": Editor.modes.js,
   "/javascript": Editor.modes.js,
   "/x-javascript": Editor.modes.js,
@@ -81,19 +85,26 @@ DetailsView.prototype = {
     dirty: [],
     // the most recently received attachment data for the request
     latestData: null,
   },
 
   /**
    * Initialization function, called when the network monitor is started.
    */
-  initialize: function () {
+  initialize: function (store) {
     dumpn("Initializing the DetailsView");
 
+    this._timingsPanelNode = $("#react-timings-tabpanel-hook");
+
+    ReactDOM.render(Provider(
+      { store },
+      TimingsPanel()
+    ), this._timingsPanelNode);
+
     this.widget = $("#event-details-pane");
     this.sidebar = new ToolSidebar(this.widget, this, "netmonitor", {
       disableTelemetry: true,
       showAllTabsMenu: true
     });
 
     this._headers = new VariablesView($("#all-headers"),
       Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
@@ -129,16 +140,17 @@ DetailsView.prototype = {
     $("tabpanels", this.widget).addEventListener("select", this._onTabSelect);
   },
 
   /**
    * Destruction function, called when the network monitor is closed.
    */
   destroy: function () {
     dumpn("Destroying the DetailsView");
+    ReactDOM.unmountComponentAtNode(this._timingsPanelNode);
     this.sidebar.destroy();
     $("tabpanels", this.widget).removeEventListener("select",
       this._onTabSelect);
   },
 
   /**
    * Populates this view with the specified data.
    *
@@ -238,20 +250,16 @@ DetailsView.prototype = {
             src.requestHeaders,
             src.requestHeadersFromUploadStream,
             src.requestPostData);
           break;
         // "Response"
         case 3:
           yield view._setResponseBody(src.url, src.responseContent);
           break;
-        // "Timings"
-        case 4:
-          yield view._setTimingsInformation(src.eventTimings);
-          break;
         // "Security"
         case 5:
           yield view._setSecurityInfo(src.securityInfo, src.url);
           break;
         // "Preview"
         case 6:
           yield view._setHtmlPreview(src.responseContent);
           break;
@@ -681,97 +689,16 @@ DetailsView.prototype = {
         }
       }
     }
 
     window.emit(EVENTS.RESPONSE_BODY_DISPLAYED);
   }),
 
   /**
-   * Sets the timings information shown in this view.
-   *
-   * @param object response
-   *        The message received from the server.
-   */
-  _setTimingsInformation: function (response) {
-    if (!response) {
-      return;
-    }
-    let { blocked, dns, connect, send, wait, receive } = response.timings;
-
-    let tabboxWidth = $("#details-pane").getAttribute("width");
-
-    // Other nodes also take some space.
-    let availableWidth = tabboxWidth / 2;
-    let scale = (response.totalTime > 0 ?
-                 Math.max(availableWidth / response.totalTime, 0) :
-                 0);
-
-    $("#timings-summary-blocked .requests-menu-timings-box")
-      .setAttribute("width", blocked * scale);
-    $("#timings-summary-blocked .requests-menu-timings-total")
-      .setAttribute("value", L10N.getFormatStr("networkMenu.totalMS", blocked));
-
-    $("#timings-summary-dns .requests-menu-timings-box")
-      .setAttribute("width", dns * scale);
-    $("#timings-summary-dns .requests-menu-timings-total")
-      .setAttribute("value", L10N.getFormatStr("networkMenu.totalMS", dns));
-
-    $("#timings-summary-connect .requests-menu-timings-box")
-      .setAttribute("width", connect * scale);
-    $("#timings-summary-connect .requests-menu-timings-total")
-      .setAttribute("value", L10N.getFormatStr("networkMenu.totalMS", connect));
-
-    $("#timings-summary-send .requests-menu-timings-box")
-      .setAttribute("width", send * scale);
-    $("#timings-summary-send .requests-menu-timings-total")
-      .setAttribute("value", L10N.getFormatStr("networkMenu.totalMS", send));
-
-    $("#timings-summary-wait .requests-menu-timings-box")
-      .setAttribute("width", wait * scale);
-    $("#timings-summary-wait .requests-menu-timings-total")
-      .setAttribute("value", L10N.getFormatStr("networkMenu.totalMS", wait));
-
-    $("#timings-summary-receive .requests-menu-timings-box")
-      .setAttribute("width", receive * scale);
-    $("#timings-summary-receive .requests-menu-timings-total")
-      .setAttribute("value", L10N.getFormatStr("networkMenu.totalMS", receive));
-
-    $("#timings-summary-dns .requests-menu-timings-box")
-      .style.transform = "translateX(" + (scale * blocked) + "px)";
-    $("#timings-summary-connect .requests-menu-timings-box")
-      .style.transform = "translateX(" + (scale * (blocked + dns)) + "px)";
-    $("#timings-summary-send .requests-menu-timings-box")
-      .style.transform =
-        "translateX(" + (scale * (blocked + dns + connect)) + "px)";
-    $("#timings-summary-wait .requests-menu-timings-box")
-      .style.transform =
-        "translateX(" + (scale * (blocked + dns + connect + send)) + "px)";
-    $("#timings-summary-receive .requests-menu-timings-box")
-      .style.transform =
-        "translateX(" + (scale * (blocked + dns + connect + send + wait)) +
-          "px)";
-
-    $("#timings-summary-dns .requests-menu-timings-total")
-      .style.transform = "translateX(" + (scale * blocked) + "px)";
-    $("#timings-summary-connect .requests-menu-timings-total")
-      .style.transform = "translateX(" + (scale * (blocked + dns)) + "px)";
-    $("#timings-summary-send .requests-menu-timings-total")
-      .style.transform =
-        "translateX(" + (scale * (blocked + dns + connect)) + "px)";
-    $("#timings-summary-wait .requests-menu-timings-total")
-      .style.transform =
-        "translateX(" + (scale * (blocked + dns + connect + send)) + "px)";
-    $("#timings-summary-receive .requests-menu-timings-total")
-      .style.transform =
-        "translateX(" + (scale * (blocked + dns + connect + send + wait)) +
-         "px)";
-  },
-
-  /**
    * Sets the preview for HTML responses shown in this view.
    *
    * @param object response
    *        The message received from the server.
    * @return object
    *        A promise that is resolved when the html preview is rendered.
    */
   _setHtmlPreview: Task.async(function* (response) {
--- a/devtools/client/netmonitor/netmonitor-view.js
+++ b/devtools/client/netmonitor/netmonitor-view.js
@@ -45,17 +45,17 @@ var NetMonitorView = {
   /**
    * Initializes the network monitor view.
    */
   initialize: function () {
     this._initializePanes();
 
     this.Toolbar.initialize(gStore);
     this.RequestsMenu.initialize(gStore);
-    this.NetworkDetails.initialize();
+    this.NetworkDetails.initialize(gStore);
     this.CustomRequest.initialize();
     this.PerformanceStatistics.initialize(gStore);
   },
 
   /**
    * Destroys the network monitor view.
    */
   destroy: function () {
--- a/devtools/client/netmonitor/netmonitor.xul
+++ b/devtools/client/netmonitor/netmonitor.xul
@@ -257,66 +257,18 @@
                              crop="end"
                              flex="1"/>
                     </hbox>
                   </vbox>
                 </vbox>
               </tabpanel>
               <tabpanel id="timings-tabpanel"
                         class="tabpanel-content">
-                <vbox flex="1">
-                  <hbox id="timings-summary-blocked"
-                        class="tabpanel-summary-container"
-                        align="center">
-                    <label class="plain tabpanel-summary-label"
-                           data-localization="content=netmonitor.timings.blocked"/>
-                    <hbox class="requests-menu-timings-box blocked"/>
-                    <label class="plain requests-menu-timings-total"/>
-                  </hbox>
-                  <hbox id="timings-summary-dns"
-                        class="tabpanel-summary-container"
-                        align="center">
-                    <label class="plain tabpanel-summary-label"
-                           data-localization="content=netmonitor.timings.dns"/>
-                    <hbox class="requests-menu-timings-box dns"/>
-                    <label class="plain requests-menu-timings-total"/>
-                  </hbox>
-                  <hbox id="timings-summary-connect"
-                        class="tabpanel-summary-container"
-                        align="center">
-                    <label class="plain tabpanel-summary-label"
-                           data-localization="content=netmonitor.timings.connect"/>
-                    <hbox class="requests-menu-timings-box connect"/>
-                    <label class="plain requests-menu-timings-total"/>
-                  </hbox>
-                  <hbox id="timings-summary-send"
-                        class="tabpanel-summary-container"
-                        align="center">
-                    <label class="plain tabpanel-summary-label"
-                           data-localization="content=netmonitor.timings.send"/>
-                    <hbox class="requests-menu-timings-box send"/>
-                    <label class="plain requests-menu-timings-total"/>
-                  </hbox>
-                  <hbox id="timings-summary-wait"
-                        class="tabpanel-summary-container"
-                        align="center">
-                    <label class="plain tabpanel-summary-label"
-                           data-localization="content=netmonitor.timings.wait"/>
-                    <hbox class="requests-menu-timings-box wait"/>
-                    <label class="plain requests-menu-timings-total"/>
-                  </hbox>
-                  <hbox id="timings-summary-receive"
-                        class="tabpanel-summary-container"
-                        align="center">
-                    <label class="plain tabpanel-summary-label"
-                           data-localization="content=netmonitor.timings.receive"/>
-                    <hbox class="requests-menu-timings-box receive"/>
-                    <label class="plain requests-menu-timings-total"/>
-                  </hbox>
-                </vbox>
+                <html:div xmlns="http://www.w3.org/1999/xhtml"
+                          id="react-timings-tabpanel-hook"/>
               </tabpanel>
               <tabpanel id="security-tabpanel"
                         class="tabpanel-content">
                   <vbox id="security-error"
                         class="tabpanel-summary-container"
                         flex="1">
                     <label class="plain tabpanel-summary-label"
                            data-localization="content=netmonitor.security.error"/>
--- a/devtools/client/themes/netmonitor.css
+++ b/devtools/client/themes/netmonitor.css
@@ -542,25 +542,27 @@
   transform-origin: left center;
 }
 
 .requests-menu-timings-total:-moz-locale-dir(rtl) {
   transform-origin: right center;
 }
 
 .requests-menu-timings-total {
+  display: inline-block;
   padding-inline-start: 4px;
   font-size: 85%;
   font-weight: 600;
   white-space: nowrap;
   /* This node should not be scaled - apply a reversed transformation */
   transform: scaleX(var(--timings-rev-scale));
 }
 
 .requests-menu-timings-box {
+  display: inline-block;
   height: 9px;
 }
 
 .theme-firebug .requests-menu-timings-box {
   background-image: linear-gradient(rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0.2));
   height: 16px;
 }
 
@@ -675,16 +677,17 @@
 
 /* Summary tabpanel */
 
 .tabpanel-summary-container {
   padding: 1px;
 }
 
 .tabpanel-summary-label {
+  display: inline-block;
   padding-inline-start: 4px;
   padding-inline-end: 3px;
   font-weight: 600;
 }
 
 .tabpanel-summary-value {
   color: inherit;
   padding-inline-start: 3px;
@@ -747,28 +750,38 @@
 
 #response-preview {
   display: -moz-box;
   -moz-box-flex: 1;
 }
 
 /* Timings tabpanel */
 
+#timings-tabpanel .tabpanel-summary-container {
+  display: flex;
+}
+
 #timings-tabpanel .tabpanel-summary-label {
   width: 10em;
 }
 
+#timings-tabpanel .requests-menu-timings-container {
+  display: flex;
+  flex: 1;
+  align-items: center;
+}
+
+#timings-tabpanel .requests-menu-timings-offset {
+  transition: width 0.2s ease-out;
+}
+
 #timings-tabpanel .requests-menu-timings-box {
-  transition: transform 0.2s ease-out;
   border: none;
   min-width: 1px;
-}
-
-#timings-tabpanel .requests-menu-timings-total {
-  transition: transform 0.2s ease-out;
+  transition: width 0.2s ease-out;
 }
 
 .theme-firebug #timings-tabpanel .requests-menu-timings-total {
   color: var(--theme-body-color);
 }
 
 /* Security tabpanel */
 .security-info-section {
@@ -1063,8 +1076,18 @@
 }
 
 /* Responsive sidebar */
 @media (max-width: 700px) {
   :root[platform="linux"] .requests-menu-header-button {
     font-size: 85%;
   }
 }
+
+/*
+ * FIXME: normal html block element cannot fill outer XUL element
+ * This workaround should be removed after sidebar is migrated to react
+ */
+#react-timings-tabpanel-hook {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-flex: 1;
+}
--- a/dom/events/KeyNameList.h
+++ b/dom/events/KeyNameList.h
@@ -211,16 +211,17 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Soft4)
  * Multimedia Keys
  *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
 DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
 DEFINE_KEYNAME_WITH_SAME_NAME(Close)
 DEFINE_KEYNAME_WITH_SAME_NAME(MailForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MailReply)
 DEFINE_KEYNAME_WITH_SAME_NAME(MailSend)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaFastForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackNext)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackPrevious)
@@ -395,17 +396,16 @@ DEFINE_KEYNAME_WITH_SAME_NAME(GuidePrevi
 DEFINE_KEYNAME_WITH_SAME_NAME(Info)
 DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
 DEFINE_KEYNAME_WITH_SAME_NAME(Link)
 DEFINE_KEYNAME_WITH_SAME_NAME(ListProgram)
 DEFINE_KEYNAME_WITH_SAME_NAME(LiveContent)
 DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaApps)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaAudioTrack)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaFastForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkipBackward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkipForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaStepBackward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaStepForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(MediaTopMenu)
 DEFINE_KEYNAME_WITH_SAME_NAME(NavigateIn)
 DEFINE_KEYNAME_WITH_SAME_NAME(NavigateNext)
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -639,29 +639,28 @@ DOMMediaStream::RemoveTrack(MediaStreamT
                        this, &aTrack, aTrack.mOwningStream.get(), aTrack.mTrackID));
 
   RefPtr<TrackPort> toRemove = FindPlaybackTrackPort(aTrack);
   if (!toRemove) {
     LOG(LogLevel::Debug, ("DOMMediaStream %p does not contain track %p", this, &aTrack));
     return;
   }
 
+  DebugOnly<bool> removed = mTracks.RemoveElement(toRemove);
+  NS_ASSERTION(removed, "If there's a track port we should be able to remove it");
+
   // If the track comes from a TRACK_ANY input port (i.e., mOwnedPort), we need
   // to block it in the port. Doing this for a locked track is still OK as it
   // will first block the track, then destroy the port. Both cause the track to
   // end.
   // If the track has already ended, it's input port might be gone, so in those
   // cases blocking the underlying track should be avoided.
   if (!aTrack.Ended()) {
     BlockPlaybackTrack(toRemove);
-
-    bool removed = mTracks.RemoveElement(toRemove);
-    if (removed) {
-      NotifyTrackRemoved(&aTrack);
-    }
+    NotifyTrackRemoved(&aTrack);
   }
 
   LOG(LogLevel::Debug, ("DOMMediaStream %p Removed track %p", this, &aTrack));
 }
 
 class ClonedStreamSourceGetter :
   public MediaStreamTrackSourceGetter
 {
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -28,20 +28,19 @@ MediaDecoderReaderWrapper::StartTime() c
 
 RefPtr<MediaDecoderReaderWrapper::MetadataPromise>
 MediaDecoderReaderWrapper::ReadMetadata()
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   MOZ_ASSERT(!mShutdown);
   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
                      &MediaDecoderReader::AsyncReadMetadata)
-         ->Then(mOwnerThread, __func__, this,
-                &MediaDecoderReaderWrapper::OnMetadataRead,
-                &MediaDecoderReaderWrapper::OnMetadataNotRead)
-         ->CompletionPromise();
+         ->ThenPromise(mOwnerThread, __func__, this,
+                       &MediaDecoderReaderWrapper::OnMetadataRead,
+                       &MediaDecoderReaderWrapper::OnMetadataNotRead);
 }
 
 void
 MediaDecoderReaderWrapper::RequestAudioData()
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   MOZ_ASSERT(!mShutdown);
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1651,21 +1651,20 @@ ShutdownState::Enter()
   master->mNextFrameStatus.DisconnectAll();
   master->mCurrentPosition.DisconnectAll();
   master->mPlaybackOffset.DisconnectAll();
   master->mIsAudioDataAudible.DisconnectAll();
 
   // Shut down the watch manager to stop further notifications.
   master->mWatchManager.Shutdown();
 
-  return Reader()->Shutdown()
-    ->Then(OwnerThread(), __func__, master,
-           &MediaDecoderStateMachine::FinishShutdown,
-           &MediaDecoderStateMachine::FinishShutdown)
-    ->CompletionPromise();
+  return Reader()->Shutdown()->ThenPromise(
+    OwnerThread(), __func__, master,
+    &MediaDecoderStateMachine::FinishShutdown,
+    &MediaDecoderStateMachine::FinishShutdown);
 }
 
 #define INIT_WATCHABLE(name, val) \
   name(val, "MediaDecoderStateMachine::" #name)
 #define INIT_MIRROR(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Mirror)")
 #define INIT_CANONICAL(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Canonical)")
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -926,23 +926,23 @@ MediaFormatReader::OnDemuxFailed(TrackTy
 
 void
 MediaFormatReader::DoDemuxVideo()
 {
   auto p = mVideo.mTrackDemuxer->GetSamples(1);
 
   if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
     RefPtr<MediaFormatReader> self = this;
-    p = p->Then(OwnerThread(), __func__,
+    p = p->ThenPromise(OwnerThread(), __func__,
                 [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
                   self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
                 },
                 [self] (const MediaResult& aError) {
                   self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
-                })->CompletionPromise();
+                });
   }
 
   mVideo.mDemuxRequest.Begin(p->Then(OwnerThread(), __func__, this,
                                      &MediaFormatReader::OnVideoDemuxCompleted,
                                      &MediaFormatReader::OnVideoDemuxFailed));
 }
 
 void
@@ -992,23 +992,23 @@ MediaFormatReader::RequestAudioData()
 
 void
 MediaFormatReader::DoDemuxAudio()
 {
   auto p = mAudio.mTrackDemuxer->GetSamples(1);
 
   if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
     RefPtr<MediaFormatReader> self = this;
-    p = p->Then(OwnerThread(), __func__,
+    p = p->ThenPromise(OwnerThread(), __func__,
                 [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
                   self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
                 },
                 [self] (const MediaResult& aError) {
                   self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
-                })->CompletionPromise();
+                });
   }
 
   mAudio.mDemuxRequest.Begin(p->Then(OwnerThread(), __func__, this,
                                      &MediaFormatReader::OnAudioDemuxCompleted,
                                      &MediaFormatReader::OnAudioDemuxFailed));
 }
 
 void
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1902,16 +1902,40 @@ MediaStream::SizeOfExcludingThis(MallocS
 }
 
 size_t
 MediaStream::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
 
+void
+MediaStream::IncrementSuspendCount()
+{
+  ++mSuspendedCount;
+  if (mSuspendedCount == 1) {
+    for (uint32_t i = 0; i < mConsumers.Length(); ++i) {
+      mConsumers[i]->Suspended();
+    }
+  }
+}
+
+void
+MediaStream::DecrementSuspendCount()
+{
+    NS_ASSERTION(mSuspendedCount > 0, "Suspend count underrun");
+    --mSuspendedCount;
+
+  if (mSuspendedCount == 0) {
+    for (uint32_t i = 0; i < mConsumers.Length(); ++i) {
+      mConsumers[i]->Resumed();
+    }
+  }
+}
+
 MediaStreamGraphImpl*
 MediaStream::GraphImpl()
 {
   return mGraph;
 }
 
 MediaStreamGraph*
 MediaStream::Graph()
@@ -3132,16 +3156,28 @@ MediaInputPort::GetNextInputInterval(Gra
   result.mInputIsBlocked = aTime >= mSource->mStartBlocking;
   if (!result.mInputIsBlocked) {
     result.mEnd = std::min(result.mEnd, mSource->mStartBlocking);
   }
   return result;
 }
 
 void
+MediaInputPort::Suspended()
+{
+  mDest->InputSuspended(this);
+}
+
+void
+MediaInputPort::Resumed()
+{
+  mDest->InputResumed(this);
+}
+
+void
 MediaInputPort::Destroy()
 {
   class Message : public ControlMessage {
   public:
     explicit Message(MediaInputPort* aPort)
       : ControlMessage(nullptr), mPort(aPort) {}
     void Run() override
     {
@@ -3305,16 +3341,21 @@ ProcessedMediaStream::SetAutofinish(bool
 }
 
 void
 ProcessedMediaStream::DestroyImpl()
 {
   for (int32_t i = mInputs.Length() - 1; i >= 0; --i) {
     mInputs[i]->Disconnect();
   }
+
+  for (int32_t i = mSuspendedInputs.Length() - 1; i >= 0; --i) {
+    mSuspendedInputs[i]->Disconnect();
+  }
+
   MediaStream::DestroyImpl();
   // The stream order is only important if there are connections, in which
   // case MediaInputPort::Disconnect() called SetStreamOrderDirty().
   // MediaStreamGraphImpl::RemoveStreamGraphThread() will also call
   // SetStreamOrderDirty(), for other reasons.
 }
 
 MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
@@ -3937,16 +3978,39 @@ MediaStreamGraph::StartNonRealtimeProces
                                    aTicksToProcess - 1);
   graph->mNonRealtimeProcessing = true;
   graph->EnsureRunInStableState();
 }
 
 void
 ProcessedMediaStream::AddInput(MediaInputPort* aPort)
 {
+  MediaStream* s = aPort->GetSource();
+  if (!s->IsSuspended()) {
+    mInputs.AppendElement(aPort);
+  } else {
+    mSuspendedInputs.AppendElement(aPort);
+  }
+  GraphImpl()->SetStreamOrderDirty();
+}
+
+void
+ProcessedMediaStream::InputSuspended(MediaInputPort* aPort)
+{
+  GraphImpl()->AssertOnGraphThreadOrNotRunning();
+  mInputs.RemoveElement(aPort);
+  mSuspendedInputs.AppendElement(aPort);
+  GraphImpl()->SetStreamOrderDirty();
+}
+
+void
+ProcessedMediaStream::InputResumed(MediaInputPort* aPort)
+{
+  GraphImpl()->AssertOnGraphThreadOrNotRunning();
+  mSuspendedInputs.RemoveElement(aPort);
   mInputs.AppendElement(aPort);
   GraphImpl()->SetStreamOrderDirty();
 }
 
 void
 MediaStreamGraph::RegisterCaptureStreamForWindow(
     uint64_t aWindowId, ProcessedMediaStream* aCaptureStream)
 {
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -547,22 +547,18 @@ public:
 
   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   void SetAudioChannelType(dom::AudioChannel aType) { mAudioChannelType = aType; }
   dom::AudioChannel AudioChannelType() const { return mAudioChannelType; }
 
   bool IsSuspended() { return mSuspendedCount > 0; }
-  void IncrementSuspendCount() { ++mSuspendedCount; }
-  void DecrementSuspendCount()
-  {
-    NS_ASSERTION(mSuspendedCount > 0, "Suspend count underrun");
-    --mSuspendedCount;
-  }
+  void IncrementSuspendCount();
+  void DecrementSuspendCount();
 
 protected:
   // |AdvanceTimeVaryingValuesToCurrentTime| will be override in SourceMediaStream.
   virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
                                                      GraphTime aBlockedTime)
   {
     mTracksStartTime += aBlockedTime;
     mTracks.ForgetUpTo(aCurrentTime - mTracksStartTime);
@@ -1075,21 +1071,32 @@ public:
   // mDest is not blocked and mSource's blocking status does not change.
   InputInterval GetNextInputInterval(GraphTime aTime);
 
   /**
    * Returns the graph that owns this port.
    */
   MediaStreamGraphImpl* GraphImpl();
   MediaStreamGraph* Graph();
+
   /**
    * Sets the graph that owns this stream.  Should only be called once.
    */
   void SetGraphImpl(MediaStreamGraphImpl* aGraph);
 
+  /**
+   * Notify the port that the source MediaStream has been suspended.
+  */
+  void Suspended();
+
+  /**
+   * Notify the port that the source MediaStream has been resumed.
+  */
+  void Resumed();
+
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   {
     size_t amount = 0;
 
     // Not owned:
     // - mSource
     // - mDest
     // - mGraph
@@ -1177,26 +1184,28 @@ public:
   ProcessedMediaStream* AsProcessedStream() override { return this; }
 
   friend class MediaStreamGraphImpl;
 
   // Do not call these from outside MediaStreamGraph.cpp!
   virtual void AddInput(MediaInputPort* aPort);
   virtual void RemoveInput(MediaInputPort* aPort)
   {
-    mInputs.RemoveElement(aPort);
+    mInputs.RemoveElement(aPort) || mSuspendedInputs.RemoveElement(aPort);
   }
   bool HasInputPort(MediaInputPort* aPort)
   {
-    return mInputs.Contains(aPort);
+    return mInputs.Contains(aPort) || mSuspendedInputs.Contains(aPort);
   }
   uint32_t InputPortCount()
   {
-    return mInputs.Length();
+    return mInputs.Length() + mSuspendedInputs.Length();
   }
+  void InputSuspended(MediaInputPort* aPort);
+  void InputResumed(MediaInputPort* aPort);
   virtual MediaStream* GetInputStreamFor(TrackID aTrackID) { return nullptr; }
   virtual TrackID GetInputTrackIDFor(TrackID aTrackID) { return TRACK_NONE; }
   void DestroyImpl() override;
   /**
    * This gets called after we've computed the blocking states for all
    * streams (mBlocked is up to date up to mStateComputedTime).
    * Also, we've produced output for all streams up to this one. If this stream
    * is not in a cycle, then all its source streams have produced data.
@@ -1222,30 +1231,34 @@ public:
   // true for echo loops, only for muted cycles.
   bool InMutedCycle() const { return mCycleMarker; }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     size_t amount = MediaStream::SizeOfExcludingThis(aMallocSizeOf);
     // Not owned:
     // - mInputs elements
+    // - mSuspendedInputs elements
     amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
+    amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
     return amount;
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
 protected:
   // This state is all accessed only on the media graph thread.
 
-  // The list of all inputs that are currently enabled or waiting to be enabled.
+  // The list of all inputs that are not currently suspended.
   nsTArray<MediaInputPort*> mInputs;
+  // The list of all inputs that are currently suspended.
+  nsTArray<MediaInputPort*> mSuspendedInputs;
   bool mAutofinish;
   // After UpdateStreamOrder(), mCycleMarker is either 0 or 1 to indicate
   // whether this stream is in a muted cycle.  During ordering it can contain
   // other marker values - see MediaStreamGraphImpl::UpdateStreamOrder().
   uint32_t mCycleMarker;
 };
 
 /**
--- a/dom/media/TrackUnionStream.cpp
+++ b/dom/media/TrackUnionStream.cpp
@@ -73,54 +73,58 @@ TrackUnionStream::TrackUnionStream() :
       return;
     }
     AutoTArray<bool,8> mappedTracksFinished;
     AutoTArray<bool,8> mappedTracksWithMatchingInputTracks;
     for (uint32_t i = 0; i < mTrackMap.Length(); ++i) {
       mappedTracksFinished.AppendElement(true);
       mappedTracksWithMatchingInputTracks.AppendElement(false);
     }
-    bool allFinished = !mInputs.IsEmpty();
-    bool allHaveCurrentData = !mInputs.IsEmpty();
-    for (uint32_t i = 0; i < mInputs.Length(); ++i) {
-      MediaStream* stream = mInputs[i]->GetSource();
+
+    AutoTArray<MediaInputPort*, 32> inputs(mInputs);
+    inputs.AppendElements(mSuspendedInputs);
+
+    bool allFinished = !inputs.IsEmpty();
+    bool allHaveCurrentData = !inputs.IsEmpty();
+    for (uint32_t i = 0; i < inputs.Length(); ++i) {
+      MediaStream* stream = inputs[i]->GetSource();
       if (!stream->IsFinishedOnGraphThread()) {
         // XXX we really should check whether 'stream' has finished within time aTo,
         // not just that it's finishing when all its queued data eventually runs
         // out.
         allFinished = false;
       }
       if (!stream->HasCurrentData()) {
         allHaveCurrentData = false;
       }
       bool trackAdded = false;
       for (StreamTracks::TrackIter tracks(stream->GetStreamTracks());
            !tracks.IsEnded(); tracks.Next()) {
         bool found = false;
         for (uint32_t j = 0; j < mTrackMap.Length(); ++j) {
           TrackMapEntry* map = &mTrackMap[j];
-          if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) {
+          if (map->mInputPort == inputs[i] && map->mInputTrackID == tracks->GetID()) {
             bool trackFinished = false;
             StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID);
             found = true;
             if (!outputTrack || outputTrack->IsEnded() ||
-                !mInputs[i]->PassTrackThrough(tracks->GetID())) {
+                !inputs[i]->PassTrackThrough(tracks->GetID())) {
               trackFinished = true;
             } else {
               CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished);
             }
             mappedTracksFinished[j] = trackFinished;
             mappedTracksWithMatchingInputTracks[j] = true;
             break;
           }
         }
-        if (!found && mInputs[i]->AllowCreationOf(tracks->GetID())) {
+        if (!found && inputs[i]->AllowCreationOf(tracks->GetID())) {
           bool trackFinished = false;
           trackAdded = true;
-          uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom);
+          uint32_t mapIndex = AddTrack(inputs[i], tracks.get(), aFrom);
           CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished);
           mappedTracksFinished.AppendElement(trackFinished);
           mappedTracksWithMatchingInputTracks.AppendElement(true);
         }
       }
       if (trackAdded) {
         for (MediaStreamListener* l : mListeners) {
           l->NotifyFinishedTrackCreation(Graph());
@@ -167,18 +171,20 @@ TrackUnionStream::TrackUnionStream() :
     TrackID id;
     if (IsTrackIDExplicit(id = aPort->GetDestinationTrackId())) {
       MOZ_ASSERT(id >= mNextAvailableTrackID &&
                  mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex,
                  "Desired destination id taken. Only provide a destination ID "
                  "if you can assure its availability, or we may not be able "
                  "to bind to the correct DOM-side track.");
 #ifdef DEBUG
-      for (size_t i = 0; mInputs[i] != aPort; ++i) {
-        MOZ_ASSERT(mInputs[i]->GetSourceTrackId() != TRACK_ANY,
+      AutoTArray<MediaInputPort*, 32> inputs(mInputs);
+      inputs.AppendElements(mSuspendedInputs);
+      for (size_t i = 0; inputs[i] != aPort; ++i) {
+        MOZ_ASSERT(inputs[i]->GetSourceTrackId() != TRACK_ANY,
                    "You are adding a MediaInputPort with a track mapping "
                    "while there already exist generic MediaInputPorts for this "
                    "destination stream. This can lead to TrackID collisions!");
       }
 #endif
       mUsedTracks.InsertElementSorted(id);
     } else if ((id = aTrack->GetID()) &&
                id > mNextAvailableTrackID &&
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -904,28 +904,27 @@ GeckoMediaPluginServiceParent::AsyncAddP
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   nsString dir(aDirectory);
   RefPtr<GeckoMediaPluginServiceParent> self = this;
   return InvokeAsync<nsString&&>(
            thread, this, __func__,
            &GeckoMediaPluginServiceParent::AddOnGMPThread, dir)
-    ->Then(AbstractThread::MainThread(), __func__,
+    ->ThenPromise(AbstractThread::MainThread(), __func__,
       [dir, self]() -> void {
         LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s succeeded",
               NS_ConvertUTF16toUTF8(dir).get()));
         MOZ_ASSERT(NS_IsMainThread());
         self->UpdateContentProcessGMPCapabilities();
       },
       [dir]() -> void {
         LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s failed",
               NS_ConvertUTF16toUTF8(dir).get()));
-      })
-    ->CompletionPromise();
+      });
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginServiceParent::AddPluginDirectory(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_IsMainThread());
   RefPtr<GenericPromise> p = AsyncAddPluginDirectory(aDirectory);
   Unused << p;
@@ -1130,28 +1129,27 @@ GeckoMediaPluginServiceParent::AddOnGMPT
 
   RefPtr<GMPParent> gmp = CreateGMPParent();
   if (!gmp) {
     NS_WARNING("Can't Create GMPParent");
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   RefPtr<GeckoMediaPluginServiceParent> self(this);
-  return gmp->Init(this, directory)->Then(thread, __func__,
+  return gmp->Init(this, directory)->ThenPromise(thread, __func__,
     [gmp, self, dir]() -> void {
       LOGD(("%s::%s: %s Succeeded", __CLASS__, __FUNCTION__, dir.get()));
       {
         MutexAutoLock lock(self->mMutex);
         self->mPlugins.AppendElement(gmp);
       }
     },
     [dir]() -> void {
       LOGD(("%s::%s: %s Failed", __CLASS__, __FUNCTION__, dir.get()));
-    })
-    ->CompletionPromise();
+    });
 }
 
 void
 GeckoMediaPluginServiceParent::RemoveOnGMPThread(const nsAString& aDirectory,
                                                  const bool aDeleteFromDisk,
                                                  const bool aCanDefer)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
--- a/dom/media/gtest/TestMozPromise.cpp
+++ b/dom/media/gtest/TestMozPromise.cpp
@@ -143,35 +143,31 @@ TEST(MozPromise, AsyncResolve)
 
 TEST(MozPromise, CompletionPromises)
 {
   bool invokedPass = false;
   AutoTaskQueue atq;
   RefPtr<TaskQueue> queue = atq.Queue();
   RunOnTaskQueue(queue, [queue, &invokedPass] () -> void {
     TestPromise::CreateAndResolve(40, __func__)
-    ->Then(queue, __func__,
+    ->ThenPromise(queue, __func__,
       [] (int aVal) -> RefPtr<TestPromise> { return TestPromise::CreateAndResolve(aVal + 10, __func__); },
       DO_FAIL)
-    ->CompletionPromise()
-    ->Then(queue, __func__, [&invokedPass] () -> void { invokedPass = true; }, DO_FAIL)
-    ->CompletionPromise()
-    ->Then(queue, __func__,
+    ->ThenPromise(queue, __func__, [&invokedPass] () -> void { invokedPass = true; }, DO_FAIL)
+    ->ThenPromise(queue, __func__,
       [queue] (int aVal) -> RefPtr<TestPromise> {
         RefPtr<TestPromise::Private> p = new TestPromise::Private(__func__);
         nsCOMPtr<nsIRunnable> resolver = new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(aVal - 8), 10);
         queue->Dispatch(resolver.forget());
         return RefPtr<TestPromise>(p);
       },
       DO_FAIL)
-    ->CompletionPromise()
-    ->Then(queue, __func__,
+    ->ThenPromise(queue, __func__,
       [queue] (int aVal) -> RefPtr<TestPromise> { return TestPromise::CreateAndReject(double(aVal - 42) + 42.0, __func__); },
       DO_FAIL)
-    ->CompletionPromise()
     ->Then(queue, __func__,
       DO_FAIL,
       [queue, &invokedPass] (double aVal) -> void { EXPECT_EQ(aVal, 42.0); EXPECT_TRUE(invokedPass); queue->BeginShutdown(); });
   });
 }
 
 TEST(MozPromise, PromiseAllResolve)
 {
@@ -227,22 +223,22 @@ TEST(MozPromise, Chaining)
   AutoTaskQueue atq;
   RefPtr<TaskQueue> queue = atq.Queue();
   MozPromiseRequestHolder<TestPromise> holder;
 
   RunOnTaskQueue(queue, [queue, &holder] () {
     auto p = TestPromise::CreateAndResolve(42, __func__);
     const size_t kIterations = 100;
     for (size_t i = 0; i < kIterations; ++i) {
-      p = p->Then(queue, __func__,
+      p = p->ThenPromise(queue, __func__,
         [] (int aVal) {
           EXPECT_EQ(aVal, 42);
         },
         [] () {}
-      )->CompletionPromise();
+      );
 
       if (i == kIterations / 2) {
         p->Then(queue, __func__,
           [queue, &holder] () {
             holder.Disconnect();
             queue->BeginShutdown();
           },
           DO_FAIL);
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -254,26 +254,25 @@ OmxDataDecoder::DoAsyncShutdown()
   MOZ_ASSERT(!mFlushing);
 
   mWatchManager.Unwatch(mOmxState, &OmxDataDecoder::OmxStateRunner);
   mWatchManager.Unwatch(mPortSettingsChanged, &OmxDataDecoder::PortSettingsChanged);
 
   // Flush to all ports, so all buffers can be returned from component.
   RefPtr<OmxDataDecoder> self = this;
   mOmxLayer->SendCommand(OMX_CommandFlush, OMX_ALL, nullptr)
-    ->Then(mOmxTaskQueue, __func__,
+    ->ThenPromise(mOmxTaskQueue, __func__,
            [self] () -> RefPtr<OmxCommandPromise> {
              LOGL("DoAsyncShutdown: flush complete");
              return self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateIdle, nullptr);
            },
            [self] () {
              self->mOmxLayer->Shutdown();
            })
-    ->CompletionPromise()
-    ->Then(mOmxTaskQueue, __func__,
+    ->ThenPromise(mOmxTaskQueue, __func__,
            [self] () -> RefPtr<OmxCommandPromise> {
              RefPtr<OmxCommandPromise> p =
                self->mOmxLayer->SendCommand(OMX_CommandStateSet, OMX_StateLoaded, nullptr);
 
              // According to spec 3.1.1.2.2.1:
              // OMX_StateLoaded needs to be sent before releasing buffers.
              // And state transition from OMX_StateIdle to OMX_StateLoaded
              // is completed when all of the buffers have been removed
@@ -285,17 +284,16 @@ OmxDataDecoder::DoAsyncShutdown()
              self->ReleaseBuffers(OMX_DirInput);
              self->ReleaseBuffers(OMX_DirOutput);
 
              return p;
            },
            [self] () {
              self->mOmxLayer->Shutdown();
            })
-    ->CompletionPromise()
     ->Then(mOmxTaskQueue, __func__,
            [self] () {
              LOGL("DoAsyncShutdown: OMX_StateLoaded, it is safe to shutdown omx");
              self->mOmxLayer->Shutdown();
              self->mWatchManager.Shutdown();
              self->mOmxLayer = nullptr;
              self->mMediaDataHelper = nullptr;
 
@@ -793,17 +791,17 @@ OmxDataDecoder::PortSettingsChanged()
                                               sizeof(def));
   CHECK_OMX_ERR(err);
 
   RefPtr<OmxDataDecoder> self = this;
   if (def.bEnabled) {
     // 1. disable port.
     LOG("PortSettingsChanged: disable port %d", def.nPortIndex);
     mOmxLayer->SendCommand(OMX_CommandPortDisable, mPortSettingsChanged, nullptr)
-      ->Then(mOmxTaskQueue, __func__,
+      ->ThenPromise(mOmxTaskQueue, __func__,
              [self, def] () -> RefPtr<OmxCommandPromise> {
                // 3. enable port.
                // Send enable port command.
                RefPtr<OmxCommandPromise> p =
                  self->mOmxLayer->SendCommand(OMX_CommandPortEnable,
                                               self->mPortSettingsChanged,
                                               nullptr);
 
@@ -814,17 +812,16 @@ OmxDataDecoder::PortSettingsChanged()
                  self->NotifyError(OMX_ErrorUndefined, __func__);
                }
 
                return p;
              },
              [self] () {
                self->NotifyError(OMX_ErrorUndefined, __func__);
              })
-      ->CompletionPromise()
       ->Then(mOmxTaskQueue, __func__,
              [self] () {
                LOGL("PortSettingsChanged: port settings changed complete");
                // finish port setting changed.
                self->mPortSettingsChanged = -1;
                self->FillAndEmptyBuffers();
              },
              [self] () {
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1446,17 +1446,20 @@ PeerConnectionWrapper.prototype = {
    * all sending and receiving track involved in this test.
    *
    * @returns {Promise}
    *        A promise that resolves when media flows for all elements and tracks
    */
   waitForMediaFlow : function() {
     return Promise.all([].concat(
       this.localMediaElements.map(element => this.waitForMediaElementFlow(element)),
-      this.remoteMediaElements.map(element => this.waitForMediaElementFlow(element)),
+      Object.keys(this.expectedRemoteTrackInfoById)
+          .map(id => this.remoteMediaElements
+              .find(e => e.srcObject.getTracks().some(t => t.id == id)))
+          .map(e => this.waitForMediaElementFlow(e)),
       this._pc.getSenders().map(sender => this.waitForRtpFlow(sender.track)),
       this._pc.getReceivers().map(receiver => this.waitForRtpFlow(receiver.track))));
   },
 
   /**
    * Check that correct audio (typically a flat tone) is flowing to this
    * PeerConnection. Uses WebAudio AnalyserNodes to compare input and output
    * audio data in the frequency domain.
--- a/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
@@ -96,16 +96,24 @@
         checkMediaStreamContains(videoStream, [], "1, Removed original track");
         checkMediaStreamContains(audioStream, [audioTrack, videoTrack],
                                  "2, Added external track");
 
         var elem = createMediaElement('video', 'testAddRemoveOriginalTrackVideo');
         var playback = new LocalMediaStreamPlayback(elem, audioStream);
         return playback.playMedia(false);
       }))
+    .then(() => getUserMedia({ audio: true, video: true })).then(stream => {
+      info("Test removing stopped tracks");
+      stream.getTracks().forEach(t => {
+        t.stop();
+        stream.removeTrack(t);
+      });
+      checkMediaStreamContains(stream, [], "Removed stopped tracks");
+    })
     .then(() => {
       var ac = new AudioContext();
 
       var osc1k = createOscillatorStream(ac, 1000);
       var audioTrack1k = osc1k.getTracks()[0];
 
       var osc5k = createOscillatorStream(ac, 5000);
       var audioTrack5k = osc5k.getTracks()[0];
--- a/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
@@ -18,18 +18,20 @@
    */
   runTest(function () {
     const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
     if (IsMacOSX10_6orOlder() || isWinXP) {
         ok(true, "Screensharing disabled for OSX10.6 and WinXP");
         return;
     }
     var testVideo = createMediaElement('video', 'testVideo');
+    var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
 
     return Promise.resolve()
+      .then(() => pushPrefs(["media.getusermedia.browser.enabled", true]))
       .then(() => getUserMedia({
         video: { mediaSource: "browser",
                  scrollWithPage: true },
         fake: false
       }))
       .then(stream => {
         var playback = new LocalMediaStreamPlayback(testVideo, stream);
         return playback.playMediaWithDeprecatedStreamStop(false);
--- a/ipc/ipdl/ipdl/cgen.py
+++ b/ipc/ipdl/ipdl/cgen.py
@@ -1,16 +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/.
 
 import os, sys
 
 from ipdl.ast import Visitor
-from ipdl.ast import IN, OUT, INOUT, ASYNC, SYNC, INTR
 
 class CodePrinter:
     def __init__(self, outf=sys.stdout, indentCols=4):
         self.outf = outf
         self.col = 0
         self.indentCols = indentCols
 
     def write(self, str):
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -1445,18 +1445,16 @@ class CheckTypes(TcheckVisitor):
         if not mgstype.isManagedBy(ptype):
             self.error(
                 loc,
                 "|manages| declaration in protocol `%s' does not match any |manager| declaration in protocol `%s'",
                 pname, mgsname)
 
 
     def visitManager(self, mgr):
-        # FIXME/bug 541126: check that the protocol graph is acyclic
-
         pdecl = mgr.of.decl
         ptype, pname = pdecl.type, pdecl.shortname
 
         mgrdecl = mgr.decl
         mgrtype, mgrname = mgrdecl.type, mgrdecl.shortname
 
         # we added this information; sanity check it
         assert ptype.isManagedBy(mgrtype)
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -143,27 +143,25 @@ case "$target" in
 
         # Make sure compilers are valid
         CFLAGS="$CFLAGS -TC -nologo"
         CXXFLAGS="$CXXFLAGS -TP -nologo"
         if test -z "$CLANG_CL"; then
             CFLAGS="$CFLAGS -utf-8"
             CXXFLAGS="$CXXFLAGS -utf-8"
         fi
-        # MSVC warning C4345 warns of newly conformant behavior as of VS2003.
-        # MSVC warning C4351 warns of newly conformant behavior as of VS2005.
         # MSVC warning C4800 warns when a value is implicitly cast to bool,
         # because this also forces narrowing to a single byte, which can be a
         # perf hit.  But this matters so little in practice (and often we want
         # that behavior) that it's better to turn it off.
         # _CRT_SECURE_NO_WARNINGS disables warnings about using MSVC-specific
         # secure CRT functions.
-        # MSVC warning wd4595 warns non-member operator new or delete functions
+        # MSVC warning C4595 warns non-member operator new or delete functions
         # may not be declared inline, as of VS2015 Update 2.
-        CXXFLAGS="$CXXFLAGS -wd4345 -wd4351 -wd4800 -wd4595 -D_CRT_SECURE_NO_WARNINGS"
+        CXXFLAGS="$CXXFLAGS -wd4800 -wd4595 -D_CRT_SECURE_NO_WARNINGS"
         AC_LANG_SAVE
         AC_LANG_C
         AC_TRY_COMPILE([#include <stdio.h>],
             [ printf("Hello World\n"); ],,
             AC_MSG_ERROR([\$(CC) test failed.  You must have MS VC++ in your path to build.]) )
 
         AC_LANG_CPLUSPLUS
         AC_TRY_COMPILE([#include <new.h>],
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -462,17 +462,17 @@ pref("media.peerconnection.video.enabled
 pref("media.navigator.video.max_fs", 12288); // Enough for 2048x1536
 pref("media.navigator.video.max_fr", 60);
 pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1
 pref("media.navigator.video.h264.max_br", 0);
 pref("media.navigator.video.h264.max_mbps", 0);
 pref("media.peerconnection.video.h264_enabled", false);
 pref("media.peerconnection.video.vp9_enabled", true);
 pref("media.getusermedia.aec", 1);
-pref("media.getusermedia.browser.enabled", true);
+pref("media.getusermedia.browser.enabled", false);
 #endif
 // Gonk typically captures at QVGA, and so min resolution is QQVGA or
 // 160x120; 100Kbps is plenty for that.
 // Desktop is typically VGA capture or more; and qm_select will not drop resolution
 // below 1/2 in each dimension (or so), so QVGA (320x200) is the lowest here usually.
 pref("media.peerconnection.video.min_bitrate", 0);
 pref("media.peerconnection.video.start_bitrate", 0);
 pref("media.peerconnection.video.max_bitrate", 0);
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -1,17 +1,16 @@
 /* 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/. */
 
 pref("security.tls.version.min", 1);
 pref("security.tls.version.max", 4);
 pref("security.tls.version.fallback-limit", 3);
 pref("security.tls.insecure_fallback_hosts", "");
-pref("security.tls.unrestricted_rc4_fallback", false);
 pref("security.tls.enable_0rtt_data", false);
 
 pref("security.ssl.treat_unsafe_negotiation_as_broken", false);
 pref("security.ssl.require_safe_negotiation",  false);
 pref("security.ssl.enable_ocsp_stapling", true);
 pref("security.ssl.enable_false_start", true);
 pref("security.ssl.false_start.require-npn", false);
 pref("security.ssl.enable_alpn", true);
--- a/old-configure.in
+++ b/old-configure.in
@@ -1032,26 +1032,24 @@ case "$target" in
         # khuey says we can safely ignore MSVC warning C4251
         # MSVC warning C4244 (implicit type conversion may lose data) warns
         # and requires workarounds for perfectly valid code.  Also, GCC/clang
         # don't warn about it by default. So for consistency/sanity, we turn
         # it off on MSVC, too.
         # MSVC warning C4267 warns for narrowing type conversions from size_t
         # to 32-bit integer types on 64-bit platforms.  Since this is virtually
         # the same thing as C4244, we disable C4267, too.
-        # MSVC warning C4345 warns of newly conformant behavior as of VS2003.
-        # MSVC warning C4351 warns of newly conformant behavior as of VS2005.
         # MSVC warning C4800 warns when a value is implicitly cast to bool,
         # because this also forces narrowing to a single byte, which can be a
         # perf hit.  But this matters so little in practice (and often we want
         # that behavior) that it's better to turn it off.
-        # MSVC warning wd4595 warns non-member operator new or delete functions
+        # MSVC warning C4595 warns non-member operator new or delete functions
         # may not be declared inline, as of VS2015 Update 2.
         CFLAGS="$CFLAGS -wd4244 -wd4267"
-        CXXFLAGS="$CXXFLAGS -wd4251 -wd4244 -wd4267 -wd4345 -wd4351 -wd4800 -wd4595"
+        CXXFLAGS="$CXXFLAGS -wd4251 -wd4244 -wd4267 -wd4800 -wd4595"
         if test -n "$CLANG_CL"; then
             # XXX We should combine some of these with our generic GCC-style
             # warning checks.
             #
             # Suppress the clang-cl warning for the inline 'new' and 'delete' in mozalloc
             CXXFLAGS="$CXXFLAGS -Wno-inline-new-delete"
             # We use offsetof on non-POD objects all the time.
             # We also suppress this warning on other platforms.
deleted file mode 100644
--- a/security/manager/ssl/WeakCryptoOverride.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=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/. */
-
-#include "WeakCryptoOverride.h"
-
-#include "MainThreadUtils.h"
-#include "SharedSSLState.h"
-#include "nss.h"
-
-using namespace mozilla;
-using namespace mozilla::psm;
-
-NS_IMPL_ISUPPORTS(WeakCryptoOverride,
-                  nsIWeakCryptoOverride)
-
-WeakCryptoOverride::WeakCryptoOverride()
-{
-}
-
-WeakCryptoOverride::~WeakCryptoOverride()
-{
-}
-
-NS_IMETHODIMP
-WeakCryptoOverride::AddWeakCryptoOverride(const nsACString& aHostName,
-                                          bool aPrivate, bool aTemporary)
-{
-  if (!NS_IsMainThread()) {
-    return NS_ERROR_NOT_SAME_THREAD;
-  }
-
-  SharedSSLState* sharedState = aPrivate ? PrivateSSLState()
-                                         : PublicSSLState();
-  if (!sharedState) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  const nsPromiseFlatCString& host = PromiseFlatCString(aHostName);
-  sharedState->IOLayerHelpers().addInsecureFallbackSite(host, aTemporary);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-WeakCryptoOverride::RemoveWeakCryptoOverride(const nsACString& aHostName,
-                                             int32_t aPort, bool aPrivate)
-{
-  if (!NS_IsMainThread()) {
-    return NS_ERROR_NOT_SAME_THREAD;
-  }
-
-  SharedSSLState* sharedState = aPrivate ? PrivateSSLState()
-                                         : PublicSSLState();
-  if (!sharedState) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  const nsPromiseFlatCString& host = PromiseFlatCString(aHostName);
-  sharedState->IOLayerHelpers().removeInsecureFallbackSite(host, aPort);
-
-  // Some servers will fail with SSL_ERROR_ILLEGAL_PARAMETER_ALERT
-  // unless the session cache is cleared.
-  SSL_ClearSessionCache();
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/security/manager/ssl/WeakCryptoOverride.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * 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/. */
-
-#ifndef WEAKCRYPTOOVERRIDE_H
-#define WEAKCRYPTOOVERRIDE_H
-
-#include "nsIWeakCryptoOverride.h"
-#include "nsWeakReference.h"
-
-namespace mozilla {
-namespace psm {
-
-class WeakCryptoOverride final : public nsIWeakCryptoOverride
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIWEAKCRYPTOOVERRIDE
-
-  WeakCryptoOverride();
-
-protected:
-  ~WeakCryptoOverride();
-};
-
-} // psm
-} // mozilla
-
-#define NS_WEAKCRYPTOOVERRIDE_CID /* ffb06724-3c20-447c-8328-ae71513dd618 */ \
-{ 0xffb06724, 0x3c20, 0x447c, \
-  { 0x83, 0x28, 0xae, 0x71, 0x51, 0x3d, 0xd6, 0x18 } }
-
-#endif
--- a/security/manager/ssl/moz.build
+++ b/security/manager/ssl/moz.build
@@ -34,17 +34,16 @@ XPIDL_SOURCES += [
     'nsISecretDecoderRing.idl',
     'nsISecurityUITelemetry.idl',
     'nsISiteSecurityService.idl',
     'nsISSLStatus.idl',
     'nsISSLStatusProvider.idl',
     'nsITokenDialogs.idl',
     'nsITokenPasswordDialogs.idl',
     'nsIU2FToken.idl',
-    'nsIWeakCryptoOverride.idl',
     'nsIX509Cert.idl',
     'nsIX509CertDB.idl',
     'nsIX509CertList.idl',
     'nsIX509CertValidity.idl',
 ]
 
 if CONFIG['MOZ_XUL']:
     XPIDL_SOURCES += [
@@ -135,17 +134,16 @@ UNIFIED_SOURCES += [
     'PSMContentListener.cpp',
     'PSMRunnable.cpp',
     'PublicKeyPinningService.cpp',
     'RootCertificateTelemetryUtils.cpp',
     'SecretDecoderRing.cpp',
     'SharedSSLState.cpp',
     'SSLServerCertVerification.cpp',
     'TransportSecurityInfo.cpp',
-    'WeakCryptoOverride.cpp',
 ]
 
 IPDL_SOURCES += [
     'PPSMContentDownloader.ipdl',
 ]
 
 if not CONFIG['MOZ_NO_SMART_CARDS']:
     UNIFIED_SOURCES += [
deleted file mode 100644
--- a/security/manager/ssl/nsIWeakCryptoOverride.idl
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * 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/. */
-
-#include "nsISupports.idl"
-
-%{C++
-#define NS_WEAKCRYPTOOVERRIDE_CONTRACTID "@mozilla.org/security/weakcryptooverride;1"
-%}
-
-/**
- * This represents the fallback whitelist for
- * weak crypto servers such as RC4-only.
- */
-[scriptable, uuid(27b4d3df-8f15-4eb4-a35f-474e911b61e7)]
-interface nsIWeakCryptoOverride : nsISupports {
-  /**
-   *  Add a weak crypto override for the given hostname.
-   *  Main thread only.
-   *
-   *  @param aHostName The host (punycode) this mapping belongs to
-   *  @param aPrivate The override info will used for the private browsing
-   *                  session and no information will be written to the disk.
-   *  @param aTemporary The override info will not persist between sessions.
-   *                    Ignored if aPrivate is true.
-   */
-  void addWeakCryptoOverride(in ACString aHostName,
-                             in boolean aPrivate,
-                             [optional] in boolean aTemporary);
-
-  /**
-   *  Remove a weak crypto override for the given hostname:port.
-   *  Main thread only.
-   *
-   *  @param aHostName The host (punycode) whose entry should be cleared.
-   *  @param aPort The port whose entry should be cleared.
-   *  @param aPrivate The override info will used for the private browsing
-   *                  session.
-   */
-  void removeWeakCryptoOverride(in ACString aHostName,
-                                in int32_t aPort,
-                                in boolean aPrivate);
-};
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -1049,18 +1049,16 @@ AccumulateCipherSuite(Telemetry::ID prob
     // ECDHE key exchange
     case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: value = 1; break;
     case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: value = 2; break;
     case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: value = 3; break;
     case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: value = 4; break;
     case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: value = 5; break;
     case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: value = 6; break;
     case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 7; break;
-    case TLS_ECDHE_RSA_WITH_RC4_128_SHA: value = 8; break;
-    case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: value = 9; break;
     case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break;
     case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: value = 11; break;
     case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: value = 12; break;
     case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: value = 13; break;
     case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: value = 14; break;
     // DHE key exchange
     case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break;
     case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break;
@@ -1074,28 +1072,24 @@ AccumulateCipherSuite(Telemetry::ID prob
     case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: value = 30; break;
     // ECDH key exchange
     case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: value = 41; break;
     case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: value = 42; break;
     case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: value = 43; break;
     case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: value = 44; break;
     case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 45; break;
     case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: value = 46; break;
-    case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: value = 47; break;
-    case TLS_ECDH_RSA_WITH_RC4_128_SHA: value = 48; break;
     // RSA key exchange
     case TLS_RSA_WITH_AES_128_CBC_SHA: value = 61; break;
     case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 62; break;
     case TLS_RSA_WITH_AES_256_CBC_SHA: value = 63; break;
     case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 64; break;
     case SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA: value = 65; break;
     case TLS_RSA_WITH_3DES_EDE_CBC_SHA: value = 66; break;
     case TLS_RSA_WITH_SEED_CBC_SHA: value = 67; break;
-    case TLS_RSA_WITH_RC4_128_SHA: value = 68; break;
-    case TLS_RSA_WITH_RC4_128_MD5: value = 69; break;
     // TLS 1.3 PSK resumption
     case TLS_AES_128_GCM_SHA256: value = 70; break;
     case TLS_CHACHA20_POLY1305_SHA256: value = 71; break;
     case TLS_AES_256_GCM_SHA384: value = 72; break;
     // unknown
     default:
       value = 0;
       break;
@@ -1208,17 +1202,16 @@ void HandshakeCallback(PRFileDesc* fd, v
           fd, static_cast<unsigned int>(versions.min),
               static_cast<unsigned int>(versions.max)));
 
   // If the handshake completed, then we know the site is TLS tolerant
   ioLayerHelpers.rememberTolerantAtVersion(infoObject->GetHostName(),
                                            infoObject->GetPort(),
                                            versions.max);
 
-  bool usesFallbackCipher = false;
   SSLChannelInfo channelInfo;
   rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
   MOZ_ASSERT(rv == SECSuccess);
   if (rv == SECSuccess) {
     // Get the protocol version for telemetry
     // 1=tls1, 2=tls1.1, 3=tls1.2
     unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
     MOZ_ASSERT(versionEnum > 0);
@@ -1228,18 +1221,16 @@ void HandshakeCallback(PRFileDesc* fd, v
                                     : Telemetry::SSL_CIPHER_SUITE_RESUMED,
       channelInfo);
 
     SSLCipherSuiteInfo cipherInfo;
     rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
                                 sizeof cipherInfo);
     MOZ_ASSERT(rv == SECSuccess);
     if (rv == SECSuccess) {
-      usesFallbackCipher = channelInfo.keaType == ssl_kea_dh;
-
       // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
       Telemetry::Accumulate(
         infoObject->IsFullHandshake()
           ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
           : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
         channelInfo.keaType);
 
       MOZ_ASSERT(infoObject->GetKEAUsed() == channelInfo.keaType);
@@ -1320,24 +1311,22 @@ void HandshakeCallback(PRFileDesc* fd, v
                                                              status);
 
   uint32_t state;
   if (renegotiationUnsafe) {
     state = nsIWebProgressListener::STATE_IS_BROKEN;
   } else {
     state = nsIWebProgressListener::STATE_IS_SECURE |
             nsIWebProgressListener::STATE_SECURE_HIGH;
-    if (!usesFallbackCipher) {
-      SSLVersionRange defVersion;
-      rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
-      if (rv == SECSuccess && versions.max >= defVersion.max) {
-        // we know this site no longer requires a fallback cipher
-        ioLayerHelpers.removeInsecureFallbackSite(infoObject->GetHostName(),
-                                                  infoObject->GetPort());
-      }
+    SSLVersionRange defVersion;
+    rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
+    if (rv == SECSuccess && versions.max >= defVersion.max) {
+      // we know this site no longer requires a version fallback
+      ioLayerHelpers.removeInsecureFallbackSite(infoObject->GetHostName(),
+                                                infoObject->GetPort());
     }
   }
 
   if (status->HasServerCert()) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("HandshakeCallback KEEPING existing cert\n"));
   } else {
     DetermineEVStatusAndSetNewCert(status, fd, infoObject);
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1308,17 +1308,16 @@ nsNSSComponent::InitializePIPNSSBundle()
   return rv;
 }
 
 // Table of pref names and SSL cipher ID
 typedef struct {
   const char* pref;
   long id;
   bool enabledByDefault;
-  bool weak;
 } CipherPref;
 
 // Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp
 // when you add/remove cipher suites here.
 static const CipherPref sCipherPrefs[] = {
  { "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, true },
  { "security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",
@@ -1364,41 +1363,16 @@ static const CipherPref sCipherPrefs[] =
  { "security.ssl3.rsa_des_ede3_sha",
    TLS_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (RSA key exchange, 3DES)
 
  // All the rest are disabled
 
  { nullptr, 0 } // end marker
 };
 
-// Bit flags indicating what weak ciphers are enabled.
-// The bit index will correspond to the index in sCipherPrefs.
-// Wrtten by the main thread, read from any threads.
-static Atomic<uint32_t> sEnabledWeakCiphers;
-static_assert(MOZ_ARRAY_LENGTH(sCipherPrefs) - 1 <= sizeof(uint32_t) * CHAR_BIT,
-              "too many cipher suites");
-
-/*static*/ bool
-nsNSSComponent::AreAnyWeakCiphersEnabled()
-{
-  return !!sEnabledWeakCiphers;
-}
-
-/*static*/ void
-nsNSSComponent::UseWeakCiphersOnSocket(PRFileDesc* fd)
-{
-  const uint32_t enabledWeakCiphers = sEnabledWeakCiphers;
-  const CipherPref* const cp = sCipherPrefs;
-  for (size_t i = 0; cp[i].pref; ++i) {
-    if (enabledWeakCiphers & ((uint32_t)1 << i)) {
-      SSL_CipherPrefSet(fd, cp[i].id, true);
-    }
-  }
-}
-
 // This function will convert from pref values like 1, 2, ...
 // to the internal values of SSL_LIBRARY_VERSION_TLS_1_0,
 // SSL_LIBRARY_VERSION_TLS_1_1, ...
 /*static*/ void
 nsNSSComponent::FillTLSVersionRange(SSLVersionRange& rangeOut,
                                     uint32_t minFromPrefs,
                                     uint32_t maxFromPrefs,
                                     SSLVersionRange defaults)
@@ -1504,32 +1478,18 @@ CipherSuiteChangeObserver::Observe(nsISu
   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
     NS_ConvertUTF16toUTF8  prefName(someData);
     // Look through the cipher table and set according to pref setting
     const CipherPref* const cp = sCipherPrefs;
     for (size_t i = 0; cp[i].pref; ++i) {
       if (prefName.Equals(cp[i].pref)) {
         bool cipherEnabled = Preferences::GetBool(cp[i].pref,
                                                   cp[i].enabledByDefault);
-        if (cp[i].weak) {
-          // Weak ciphers will not be used by default even if they
-          // are enabled in prefs. They are only used on specific
-          // sockets as a part of a fallback mechanism.
-          // Only the main thread will change sEnabledWeakCiphers.
-          uint32_t enabledWeakCiphers = sEnabledWeakCiphers;
-          if (cipherEnabled) {
-            enabledWeakCiphers |= ((uint32_t)1 << i);
-          } else {
-            enabledWeakCiphers &= ~((uint32_t)1 << i);
-          }
-          sEnabledWeakCiphers = enabledWeakCiphers;
-        } else {
-          SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
-          SSL_ClearSessionCache();
-        }
+        SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
+        SSL_ClearSessionCache();
         break;
       }
     }
   } else if (nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     Preferences::RemoveObserver(this, "security.");
     MOZ_ASSERT(sObserver.get() == this);
     sObserver = nullptr;
     nsCOMPtr<nsIObserverService> observerService =
@@ -2444,32 +2404,22 @@ InitializeCipherSuite()
 
   // Disable any ciphers that NSS might have enabled by default
   for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
     uint16_t cipher_id = SSL_ImplementedCiphers[i];
     SSL_CipherPrefSetDefault(cipher_id, false);
   }
 
   // Now only set SSL/TLS ciphers we knew about at compile time
-  uint32_t enabledWeakCiphers = 0;
   const CipherPref* const cp = sCipherPrefs;
   for (size_t i = 0; cp[i].pref; ++i) {
     bool cipherEnabled = Preferences::GetBool(cp[i].pref,
                                               cp[i].enabledByDefault);
-    if (cp[i].weak) {
-      // Weak ciphers are not used by default. See the comment
-      // in CipherSuiteChangeObserver::Observe for details.
-      if (cipherEnabled) {
-        enabledWeakCiphers |= ((uint32_t)1 << i);
-      }
-    } else {
-      SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
-    }
+    SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled);
   }
-  sEnabledWeakCiphers = enabledWeakCiphers;
 
   // Enable ciphers for PKCS#12
   SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
   SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
   SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
   SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
   SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
   SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -752,24 +752,20 @@ nsSSLIOLayerHelpers::rememberTolerantAtV
   IntoleranceEntry entry;
   if (mTLSIntoleranceInfo.Get(key, &entry)) {
     entry.AssertInvariant();
     entry.tolerant = std::max(entry.tolerant, tolerant);
     if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
       entry.intolerant = entry.tolerant + 1;
       entry.intoleranceReason = 0; // lose the reason
     }
-    if (entry.strongCipherStatus == StrongCipherStatusUnknown) {
-      entry.strongCipherStatus = StrongCiphersWorked;
-    }
   } else {
     entry.tolerant = tolerant;
     entry.intolerant = 0;
     entry.intoleranceReason = 0;
-    entry.strongCipherStatus = StrongCiphersWorked;
   }
 
   entry.AssertInvariant();
 
   mTLSIntoleranceInfo.Put(key, entry);
 }
 
 void
@@ -782,19 +778,16 @@ nsSSLIOLayerHelpers::forgetIntolerance(c
   MutexAutoLock lock(mutex);
 
   IntoleranceEntry entry;
   if (mTLSIntoleranceInfo.Get(key, &entry)) {
     entry.AssertInvariant();
 
     entry.intolerant = 0;
     entry.intoleranceReason = 0;
-    if (entry.strongCipherStatus != StrongCiphersWorked) {
-      entry.strongCipherStatus = StrongCipherStatusUnknown;
-    }
 
     entry.AssertInvariant();
     mTLSIntoleranceInfo.Put(key, entry);
   }
 }
 
 bool
 nsSSLIOLayerHelpers::fallbackLimitReached(const nsACString& hostName,
@@ -833,63 +826,30 @@ nsSSLIOLayerHelpers::rememberIntolerantA
       return false;
     }
     if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
       // We already know that the server is intolerant at a lower version.
       return true;
     }
   } else {
     entry.tolerant = 0;
-    entry.strongCipherStatus = StrongCipherStatusUnknown;
   }
 
   entry.intolerant = intolerant;
   entry.intoleranceReason = intoleranceReason;
   entry.AssertInvariant();
   mTLSIntoleranceInfo.Put(key, entry);
 
   return true;
 }
 
-// returns true if we should retry the handshake
-bool
-nsSSLIOLayerHelpers::rememberStrongCiphersFailed(const nsACString& hostName,
-                                                 int16_t port,
-                                                 PRErrorCode intoleranceReason)
-{
-  nsCString key;
-  getSiteKey(hostName, port, key);
-
-  MutexAutoLock lock(mutex);
-
-  IntoleranceEntry entry;
-  if (mTLSIntoleranceInfo.Get(key, &entry)) {
-    entry.AssertInvariant();
-    if (entry.strongCipherStatus != StrongCipherStatusUnknown) {
-      // We already know if the server supports a strong cipher.
-      return false;
-    }
-  } else {
-    entry.tolerant = 0;
-    entry.intolerant = 0;
-    entry.intoleranceReason = intoleranceReason;
-  }
-
-  entry.strongCipherStatus = StrongCiphersFailed;
-  entry.AssertInvariant();
-  mTLSIntoleranceInfo.Put(key, entry);
-
-  return true;
-}
-
 void
 nsSSLIOLayerHelpers::adjustForTLSIntolerance(const nsACString& hostName,
                                              int16_t port,
-                                             /*in/out*/ SSLVersionRange& range,
-                                             /*out*/ StrongCipherStatus& strongCipherStatus)
+                                             /*in/out*/ SSLVersionRange& range)
 {
   IntoleranceEntry entry;
 
   {
     nsCString key;
     getSiteKey(hostName, port, key);
 
     MutexAutoLock lock(mutex);
@@ -902,17 +862,16 @@ nsSSLIOLayerHelpers::adjustForTLSIntoler
 
   if (entry.intolerant != 0) {
     // We've tried connecting at a higher range but failed, so try at the
     // version we haven't tried yet, unless we have reached the minimum.
     if (range.min < entry.intolerant) {
       range.max = entry.intolerant - 1;
     }
   }
-  strongCipherStatus = entry.strongCipherStatus;
 }
 
 PRErrorCode
 nsSSLIOLayerHelpers::getIntoleranceReason(const nsACString& hostName,
                                           int16_t port)
 {
   IntoleranceEntry entry;
 
@@ -1125,38 +1084,16 @@ retryDueToTLSIntolerance(PRErrorCode err
                           tlsIntoleranceTelemetryBucket(originalReason));
 
     helpers.forgetIntolerance(socketInfo->GetHostName(),
                               socketInfo->GetPort());
 
     return false;
   }
 
-  // Disallow PR_CONNECT_RESET_ERROR if fallback limit reached.
-  bool fallbackLimitReached =
-    helpers.fallbackLimitReached(socketInfo->GetHostName(), range.max);
-  if (err == PR_CONNECT_RESET_ERROR && fallbackLimitReached) {
-    return false;
-  }
-
-  if ((err == SSL_ERROR_NO_CYPHER_OVERLAP || err == PR_END_OF_FILE_ERROR ||
-       err == PR_CONNECT_RESET_ERROR) &&
-       nsNSSComponent::AreAnyWeakCiphersEnabled()) {
-    if (helpers.isInsecureFallbackSite(socketInfo->GetHostName()) ||
-        helpers.mUnrestrictedRC4Fallback) {
-      if (helpers.rememberStrongCiphersFailed(socketInfo->GetHostName(),
-                                              socketInfo->GetPort(), err)) {
-        Telemetry::Accumulate(Telemetry::SSL_WEAK_CIPHERS_FALLBACK,
-                              tlsIntoleranceTelemetryBucket(err));
-        return true;
-      }
-      Telemetry::Accumulate(Telemetry::SSL_WEAK_CIPHERS_FALLBACK, 0);
-    }
-  }
-
   // When not using a proxy we'll see a connection reset error.
   // When using a proxy, we'll see an end of file error.
 
   // Don't allow STARTTLS connections to fall back on connection resets or
   // EOF.
   if ((err == PR_CONNECT_RESET_ERROR || err == PR_END_OF_FILE_ERROR)
       && socketInfo->GetForSTARTTLS()) {
     return false;
@@ -1350,17 +1287,16 @@ nsSSLIOLayerPoll(PRFileDesc* fd, int16_t
           ("[%p] poll SSL socket returned %d\n", (void*) fd, (int) result));
   return result;
 }
 
 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
   : mTreatUnsafeNegotiationAsBroken(false)
   , mTLSIntoleranceInfo()
   , mFalseStartRequireNPN(false)
-  , mUnrestrictedRC4Fallback(false)
   , mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0)
   , mutex("nsSSLIOLayerHelpers.mutex")
 {
 }
 
 static int
 _PSM_InvalidInt(void)
 {
@@ -1572,19 +1508,16 @@ PrefObserver::Observe(nsISupports* aSubj
     } else if (prefName.EqualsLiteral("security.tls.version.fallback-limit")) {
       mOwner->loadVersionFallbackLimit();
     } else if (prefName.EqualsLiteral("security.tls.insecure_fallback_hosts")) {
       // Changes to the whitelist on the public side will update the pref.
       // Don't propagate the changes to the private side.
       if (mOwner->isPublic()) {
         mOwner->initInsecureFallbackSites();
       }
-    } else if (prefName.EqualsLiteral("security.tls.unrestricted_rc4_fallback")) {
-      mOwner->mUnrestrictedRC4Fallback =
-        Preferences::GetBool("security.tls.unrestricted_rc4_fallback", false);
     }
   }
   return NS_OK;
 }
 
 static int32_t
 PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
               PRIntervalTime timeout)
@@ -1611,18 +1544,16 @@ nsSSLIOLayerHelpers::~nsSSLIOLayerHelper
     Preferences::RemoveObserver(mPrefObserver,
         "security.ssl.treat_unsafe_negotiation_as_broken");
     Preferences::RemoveObserver(mPrefObserver,
         "security.ssl.false_start.require-npn");
     Preferences::RemoveObserver(mPrefObserver,
         "security.tls.version.fallback-limit");
     Preferences::RemoveObserver(mPrefObserver,
         "security.tls.insecure_fallback_hosts");
-    Preferences::RemoveObserver(mPrefObserver,
-        "security.tls.unrestricted_rc4_fallback");
   }
 }
 
 nsresult
 nsSSLIOLayerHelpers::Init()
 {
   if (!nsSSLIOLayerInitialized) {
     nsSSLIOLayerInitialized = true;
@@ -1670,30 +1601,26 @@ nsSSLIOLayerHelpers::Init()
   Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
   setTreatUnsafeNegotiationAsBroken(enabled);
 
   mFalseStartRequireNPN =
     Preferences::GetBool("security.ssl.false_start.require-npn",
                          FALSE_START_REQUIRE_NPN_DEFAULT);
   loadVersionFallbackLimit();
   initInsecureFallbackSites();
-  mUnrestrictedRC4Fallback =
-    Preferences::GetBool("security.tls.unrestricted_rc4_fallback", false);
 
   mPrefObserver = new PrefObserver(this);
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.treat_unsafe_negotiation_as_broken");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.false_start.require-npn");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.tls.version.fallback-limit");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.tls.insecure_fallback_hosts");
-  Preferences::AddStrongObserver(mPrefObserver,
-                                 "security.tls.unrestricted_rc4_fallback");
   return NS_OK;
 }
 
 void
 nsSSLIOLayerHelpers::loadVersionFallbackLimit()
 {
   // see nsNSSComponent::setEnabledTLSVersions for pref handling rules
   uint32_t limit = Preferences::GetUint("security.tls.version.fallback-limit",
@@ -1749,40 +1676,16 @@ nsSSLIOLayerHelpers::initInsecureFallbac
 }
 
 bool
 nsSSLIOLayerHelpers::isPublic() const
 {
   return this == &PublicSSLState()->IOLayerHelpers();
 }
 
-void
-nsSSLIOLayerHelpers::addInsecureFallbackSite(const nsCString& hostname,
-                                             bool temporary)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  {
-    MutexAutoLock lock(mutex);
-    if (mInsecureFallbackSites.Contains(hostname)) {
-      return;
-    }
-    mInsecureFallbackSites.PutEntry(hostname);
-  }
-  if (!isPublic() || temporary) {
-    return;
-  }
-  nsCString value;
-  Preferences::GetCString("security.tls.insecure_fallback_hosts", &value);
-  if (!value.IsEmpty()) {
-    value.Append(',');
-  }
-  value.Append(hostname);
-  Preferences::SetCString("security.tls.insecure_fallback_hosts", value);
-}
-
 class FallbackPrefRemover final : public Runnable
 {
 public:
   explicit FallbackPrefRemover(const nsACString& aHost)
     : mHost(aHost)
   {}
   NS_IMETHOD Run() override;
 private:
@@ -2474,35 +2377,29 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
   }
 
   SSLVersionRange range;
   if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
 
   uint16_t maxEnabledVersion = range.max;
-  StrongCipherStatus strongCiphersStatus = StrongCipherStatusUnknown;
   infoObject->SharedState().IOLayerHelpers()
     .adjustForTLSIntolerance(infoObject->GetHostName(), infoObject->GetPort(),
-                             range, strongCiphersStatus);
+                             range);
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-         ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)%s\n",
+         ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
           fd, static_cast<unsigned int>(range.min),
-              static_cast<unsigned int>(range.max),
-          strongCiphersStatus == StrongCiphersFailed ? " with weak ciphers" : ""));
+              static_cast<unsigned int>(range.max)));
 
   if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
   infoObject->SetTLSVersionRange(range);
 
-  if (strongCiphersStatus == StrongCiphersFailed) {
-    nsNSSComponent::UseWeakCiphersOnSocket(fd);
-  }
-
   // when adjustForTLSIntolerance tweaks the maximum version downward,
   // we tell the server using this SCSV so they can detect a downgrade attack
   if (range.max < maxEnabledVersion) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
            ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
     // Some servers will choke if we send the fallback SCSV with TLS 1.2.
     if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) {
       if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
--- a/security/manager/ssl/nsNSSIOLayer.h
+++ b/security/manager/ssl/nsNSSIOLayer.h
@@ -156,22 +156,16 @@ private:
 
   uint32_t mProviderFlags;
   mozilla::TimeStamp mSocketCreationTimestamp;
   uint64_t mPlaintextBytesRead;
 
   nsCOMPtr<nsIX509Cert> mClientCert;
 };
 
-enum StrongCipherStatus {
-  StrongCipherStatusUnknown,
-  StrongCiphersWorked,
-  StrongCiphersFailed
-};
-
 class nsSSLIOLayerHelpers
 {
 public:
   nsSSLIOLayerHelpers();
   ~nsSSLIOLayerHelpers();
 
   nsresult Init();
   void Cleanup();
@@ -188,17 +182,16 @@ public:
   bool treatUnsafeNegotiationAsBroken();
 
 private:
   struct IntoleranceEntry
   {
     uint16_t tolerant;
     uint16_t intolerant;
     PRErrorCode intoleranceReason;
-    StrongCipherStatus strongCipherStatus;
 
     void AssertInvariant() const
     {
       MOZ_ASSERT(intolerant == 0 || tolerant < intolerant);
     }
   };
   nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo;
   // Sites that require insecure fallback to TLS 1.0, set by the pref
@@ -207,35 +200,30 @@ private:
   nsTHashtable<nsCStringHashKey> mInsecureFallbackSites;
 public:
   void rememberTolerantAtVersion(const nsACString& hostname, int16_t port,
                                  uint16_t tolerant);
   bool fallbackLimitReached(const nsACString& hostname, uint16_t intolerant);
   bool rememberIntolerantAtVersion(const nsACString& hostname, int16_t port,
                                    uint16_t intolerant, uint16_t minVersion,
                                    PRErrorCode intoleranceReason);
-  bool rememberStrongCiphersFailed(const nsACString& hostName, int16_t port,
-                                   PRErrorCode intoleranceReason);
   void forgetIntolerance(const nsACString& hostname, int16_t port);
   void adjustForTLSIntolerance(const nsACString& hostname, int16_t port,
-                               /*in/out*/ SSLVersionRange& range,
-                               /*out*/ StrongCipherStatus& strongCipherStatus);
+                               /*in/out*/ SSLVersionRange& range);
   PRErrorCode getIntoleranceReason(const nsACString& hostname, int16_t port);
 
   void clearStoredData();
   void loadVersionFallbackLimit();
   void setInsecureFallbackSites(const nsCString& str);
   void initInsecureFallbackSites();
   bool isPublic() const;
-  void addInsecureFallbackSite(const nsCString& hostname, bool temporary);
   void removeInsecureFallbackSite(const nsACString& hostname, uint16_t port);
   bool isInsecureFallbackSite(const nsACString& hostname);
 
   bool mFalseStartRequireNPN;
-  bool mUnrestrictedRC4Fallback;
   uint16_t mVersionFallbackLimit;
 private:
   mozilla::Mutex mutex;
   nsCOMPtr<nsIObserver> mPrefObserver;
 };
 
 nsresult nsSSLIOLayerNewSocket(int32_t family,
                                const char* host,
--- a/security/manager/ssl/nsNSSModule.cpp
+++ b/security/manager/ssl/nsNSSModule.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CertBlocklist.h"
 #include "ContentSignatureVerifier.h"
 #include "NSSErrorsService.h"
 #include "PSMContentListener.h"
 #include "SecretDecoderRing.h"
 #include "TransportSecurityInfo.h"
-#include "WeakCryptoOverride.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsCURILoader.h"
 #include "nsCertOverrideService.h"
 #include "nsCrypto.h"
 #include "nsCryptoHash.h"
 #include "nsDOMCID.h" // For the NS_CRYPTO_CONTRACTID define
 #include "nsDataSignatureVerifier.h"
 #include "nsICategoryManager.h"
@@ -214,17 +213,16 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEn
 
 typedef mozilla::psm::NSSErrorsService NSSErrorsService;
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NSSErrorsService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSVersion)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCertOverrideService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSecureBrowserUIImpl)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(CertBlocklist, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSiteSecurityService, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR(WeakCryptoOverride)
 
 NS_DEFINE_NAMED_CID(NS_NSSCOMPONENT_CID);
 NS_DEFINE_NAMED_CID(NS_SSLSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_STARTTLSSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_SECRETDECODERRING_CID);
 NS_DEFINE_NAMED_CID(NS_PK11TOKENDB_CID);
 NS_DEFINE_NAMED_CID(NS_PKCS11MODULEDB_CID);
 NS_DEFINE_NAMED_CID(NS_PSMCONTENTLISTEN_CID);
@@ -248,17 +246,16 @@ NS_DEFINE_NAMED_CID(NS_RANDOMGENERATOR_C
 NS_DEFINE_NAMED_CID(NS_NSSU2FTOKEN_CID);
 NS_DEFINE_NAMED_CID(NS_SSLSTATUS_CID);
 NS_DEFINE_NAMED_CID(TRANSPORTSECURITYINFO_CID);
 NS_DEFINE_NAMED_CID(NS_NSSERRORSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_NSSVERSION_CID);
 NS_DEFINE_NAMED_CID(NS_SECURE_BROWSER_UI_CID);
 NS_DEFINE_NAMED_CID(NS_SITE_SECURITY_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_CERT_BLOCKLIST_CID);
-NS_DEFINE_NAMED_CID(NS_WEAKCRYPTOOVERRIDE_CID);
 
 static const mozilla::Module::CIDEntry kNSSCIDs[] = {
   { &kNS_NSSCOMPONENT_CID, false, nullptr, nsNSSComponentConstructor },
   { &kNS_SSLSOCKETPROVIDER_CID, false, nullptr, nsSSLSocketProviderConstructor },
   { &kNS_STARTTLSSOCKETPROVIDER_CID, false, nullptr, nsTLSSocketProviderConstructor },
   { &kNS_SECRETDECODERRING_CID, false, nullptr, SecretDecoderRingConstructor },
   { &kNS_PK11TOKENDB_CID, false, nullptr, nsPK11TokenDBConstructor },
   { &kNS_PKCS11MODULEDB_CID, false, nullptr, nsPKCS11ModuleDBConstructor },
@@ -283,17 +280,16 @@ static const mozilla::Module::CIDEntry k
   { &kNS_NSSU2FTOKEN_CID, false, nullptr, nsNSSU2FTokenConstructor },
   { &kNS_SSLSTATUS_CID, false, nullptr, nsSSLStatusConstructor },
   { &kTRANSPORTSECURITYINFO_CID, false, nullptr, TransportSecurityInfoConstructor },
   { &kNS_NSSERRORSSERVICE_CID, false, nullptr, NSSErrorsServiceConstructor },
   { &kNS_NSSVERSION_CID, false, nullptr, nsNSSVersionConstructor },
   { &kNS_SECURE_BROWSER_UI_CID, false, nullptr, nsSecureBrowserUIImplConstructor },
   { &kNS_SITE_SECURITY_SERVICE_CID, false, nullptr, nsSiteSecurityServiceConstructor },
   { &kNS_CERT_BLOCKLIST_CID, false, nullptr, CertBlocklistConstructor},
-  { &kNS_WEAKCRYPTOOVERRIDE_CID, false, nullptr, WeakCryptoOverrideConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
   { PSM_COMPONENT_CONTRACTID, &kNS_NSSCOMPONENT_CID },
   { NS_NSS_ERRORS_SERVICE_CONTRACTID, &kNS_NSSERRORSSERVICE_CID },
   { NS_NSSVERSION_CONTRACTID, &kNS_NSSVERSION_CID },
   { NS_SSLSOCKETPROVIDER_CONTRACTID, &kNS_SSLSOCKETPROVIDER_CID },
@@ -319,17 +315,16 @@ static const mozilla::Module::ContractID
   { NS_DATASIGNATUREVERIFIER_CONTRACTID, &kNS_DATASIGNATUREVERIFIER_CID },
   { NS_CONTENTSIGNATUREVERIFIER_CONTRACTID, &kNS_CONTENTSIGNATUREVERIFIER_CID },
   { NS_CERTOVERRIDE_CONTRACTID, &kNS_CERTOVERRIDE_CID },
   { NS_RANDOMGENERATOR_CONTRACTID, &kNS_RANDOMGENERATOR_CID },
   { NS_NSSU2FTOKEN_CONTRACTID, &kNS_NSSU2FTOKEN_CID },
   { NS_SECURE_BROWSER_UI_CONTRACTID, &kNS_SECURE_BROWSER_UI_CID },
   { NS_SSSERVICE_CONTRACTID, &kNS_SITE_SECURITY_SERVICE_CID },
   { NS_CERTBLOCKLIST_CONTRACTID, &kNS_CERT_BLOCKLIST_CID },
-  { NS_WEAKCRYPTOOVERRIDE_CONTRACTID, &kNS_WEAKCRYPTOOVERRIDE_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kNSSCategories[] = {
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-ca-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-server-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-user-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-email-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
--- a/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
+++ b/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
@@ -22,81 +22,62 @@ protected:
 TEST_F(psm_TLSIntoleranceTest, FullFallbackProcess)
 {
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, helpers.mVersionFallbackLimit);
 
   // No adjustment made when there is no entry for the site.
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
-
-    ASSERT_TRUE(
-      helpers.rememberStrongCiphersFailed(
-        HOST, PORT, SSL_ERROR_NO_CYPHER_OVERLAP));
-    ASSERT_EQ(SSL_ERROR_NO_CYPHER_OVERLAP,
-              helpers.getIntoleranceReason(HOST, PORT));
   }
 
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
 
-    ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
     ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                     range.min, range.max, 0));
   }
 
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
 
-    ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
     ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                     range.min, range.max, 0));
   }
 
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
 
-    ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
     ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                      range.min, range.max, 0));
   }
 
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     // When rememberIntolerantAtVersion returns false, it also resets the
     // intolerance information for the server.
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
   }
 }
 
 TEST_F(psm_TLSIntoleranceTest, DisableFallbackWithHighLimit)
 {
   // this value disables version fallback entirely: with this value, all efforts
   // to mark an origin as version intolerant fail
   helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
@@ -120,21 +101,19 @@ TEST_F(psm_TLSIntoleranceTest, FallbackL
   // when it is higher than the fallback limit
   ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                   SSL_LIBRARY_VERSION_TLS_1_1,
                                                   SSL_LIBRARY_VERSION_TLS_1_2,
                                                   0));
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
   }
 
   ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                    SSL_LIBRARY_VERSION_TLS_1_1,
                                                    SSL_LIBRARY_VERSION_TLS_1_1,
                                                    0));
 }
 
@@ -142,55 +121,49 @@ TEST_F(psm_TLSIntoleranceTest, TolerantO
 {
   ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                   SSL_LIBRARY_VERSION_TLS_1_0,
                                                   SSL_LIBRARY_VERSION_TLS_1_1,
                                                   0));
   helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
   SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                             SSL_LIBRARY_VERSION_TLS_1_2 };
-  StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-  helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+  helpers.adjustForTLSIntolerance(HOST, PORT, range);
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-  ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
 }
 
 TEST_F(psm_TLSIntoleranceTest, TolerantOverridesIntolerant2)
 {
   ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                   SSL_LIBRARY_VERSION_TLS_1_0,
                                                   SSL_LIBRARY_VERSION_TLS_1_1,
                                                   0));
   helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_2);
   SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                             SSL_LIBRARY_VERSION_TLS_1_2 };
-  StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-  helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+  helpers.adjustForTLSIntolerance(HOST, PORT, range);
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-  ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
 }
 
 TEST_F(psm_TLSIntoleranceTest, IntolerantDoesNotOverrideTolerant)
 {
   // No adjustment made when there is no entry for the site.
   helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
   // false because we reached the floor set by rememberTolerantAtVersion.
   ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                    SSL_LIBRARY_VERSION_TLS_1_0,
                                                    SSL_LIBRARY_VERSION_TLS_1_1,
                                                    0));
   SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                             SSL_LIBRARY_VERSION_TLS_1_2 };
-  StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-  helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+  helpers.adjustForTLSIntolerance(HOST, PORT, range);
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
   ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-  ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
 }
 
 TEST_F(psm_TLSIntoleranceTest, PortIsRelevant)
 {
   helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_2);
   ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, 1,
                                                    SSL_LIBRARY_VERSION_TLS_1_0,
                                                    SSL_LIBRARY_VERSION_TLS_1_2,
@@ -198,26 +171,24 @@ TEST_F(psm_TLSIntoleranceTest, PortIsRel
   ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, 2,
                                                   SSL_LIBRARY_VERSION_TLS_1_0,
                                                   SSL_LIBRARY_VERSION_TLS_1_2,
                                                   0));
 
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, 1, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, 1, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
   }
 
   {
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, 2, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, 2, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
   }
 }
 
 TEST_F(psm_TLSIntoleranceTest, IntoleranceReasonInitial)
 {
   ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 1));
 
@@ -247,249 +218,75 @@ TEST_F(psm_TLSIntoleranceTest, Intoleran
                                       SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
   ASSERT_EQ(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT,
             helpers.getIntoleranceReason(HOST, 1));
 
   helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_2);
   ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 1));
 }
 
-TEST_F(psm_TLSIntoleranceTest, StrongCiphersFailed)
-{
-  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_1;
-
-  ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
-
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
-
-    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                    range.min, range.max, 0));
-  }
-
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
-
-    ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                     range.min, range.max, 0));
-  }
-
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-    // When rememberIntolerantAtVersion returns false, it also resets the
-    // intolerance information for the server.
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
-  }
-}
-
-TEST_F(psm_TLSIntoleranceTest, StrongCiphersFailedAt1_1)
-{
-  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_0;
-
-  // No adjustment made when there is no entry for the site.
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                    range.min, range.max, 0));
-  }
-
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
-  }
-
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
-
-    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                    range.min, range.max, 0));
-  }
-
-  {
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.max);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
-  }
-}
-
-TEST_F(psm_TLSIntoleranceTest, StrongCiphersFailedWithHighLimit)
-{
-  // this value disables version fallback entirely: with this value, all efforts
-  // to mark an origin as version intolerant fail
-  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
-  // ...but weak ciphers fallback will not be disabled
-  ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
-  ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                   SSL_LIBRARY_VERSION_TLS_1_0,
-                                                   SSL_LIBRARY_VERSION_TLS_1_2,
-                                                   0));
-  ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                   SSL_LIBRARY_VERSION_TLS_1_0,
-                                                   SSL_LIBRARY_VERSION_TLS_1_1,
-                                                   0));
-  ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
-                                                   SSL_LIBRARY_VERSION_TLS_1_0,
-                                                   SSL_LIBRARY_VERSION_TLS_1_0,
-                                                   0));
-}
-
-TEST_F(psm_TLSIntoleranceTest, TolerantDoesNotOverrideWeakCiphersFallback)
-{
-  ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
-  // No adjustment made when intolerant is zero.
-  helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
-  SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                            SSL_LIBRARY_VERSION_TLS_1_2 };
-  StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-  helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-  ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
-}
-
-TEST_F(psm_TLSIntoleranceTest, WeakCiphersFallbackDoesNotOverrideTolerant)
-{
-  // No adjustment made when there is no entry for the site.
-  helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
-  // false because strongCipherWorked is set by rememberTolerantAtVersion.
-  ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
-  SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                            SSL_LIBRARY_VERSION_TLS_1_2 };
-  StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-  helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
-  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-  ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
-}
-
 TEST_F(psm_TLSIntoleranceTest, TLSForgetIntolerance)
 {
   {
     ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                     SSL_LIBRARY_VERSION_TLS_1_0,
                                                     SSL_LIBRARY_VERSION_TLS_1_2,
                                                     0));
 
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
   }
 
   {
     helpers.forgetIntolerance(HOST, PORT);
 
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
-  }
-}
-
-TEST_F(psm_TLSIntoleranceTest, TLSForgetStrongCipherFailed)
-{
-  {
-    ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
-
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
-  }
-
-  {
-    helpers.forgetIntolerance(HOST, PORT);
-
-    SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
-    ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
   }
 }
 
 TEST_F(psm_TLSIntoleranceTest, TLSDontForgetTolerance)
 {
   {
     helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
 
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
   }
 
   {
     ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
                                                     SSL_LIBRARY_VERSION_TLS_1_0,
                                                     SSL_LIBRARY_VERSION_TLS_1_2,
                                                     0));
 
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
-    ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
   }
 
   {
     helpers.forgetIntolerance(HOST, PORT);
 
     SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
                               SSL_LIBRARY_VERSION_TLS_1_2 };
-    StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
-    helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
-    ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
   }
 }
 
 TEST_F(psm_TLSIntoleranceTest, TLSPerSiteFallbackLimit)
 {
   NS_NAMED_LITERAL_CSTRING(example_com, "example.com");
   NS_NAMED_LITERAL_CSTRING(example_net, "example.net");
   NS_NAMED_LITERAL_CSTRING(example_org, "example.org");
deleted file mode 100644
--- a/security/manager/ssl/tests/unit/test_weak_crypto.js
+++ /dev/null
@@ -1,273 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Tests the weak crypto override
-
-const TLS_RSA_WITH_RC4_128_MD5         = 0x0004;
-const TLS_RSA_WITH_RC4_128_SHA         = 0x0005;
-const TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007;
-const TLS_ECDHE_RSA_WITH_RC4_128_SHA   = 0xC011;
-
-// Need profile dir to store the key / cert
-do_get_profile();
-// Ensure PSM is initialized
-Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
-
-const certService = Cc["@mozilla.org/security/local-cert-service;1"]
-                    .getService(Ci.nsILocalCertService);
-const certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
-                            .getService(Ci.nsICertOverrideService);
-const weakCryptoOverride = Cc["@mozilla.org/security/weakcryptooverride;1"]
-                           .getService(Ci.nsIWeakCryptoOverride);
-const socketTransportService =
-  Cc["@mozilla.org/network/socket-transport-service;1"]
-  .getService(Ci.nsISocketTransportService);
-
-function getCert() {
-  let deferred = Promise.defer();
-  certService.getOrCreateCert("tls-test", {
-    handleCert: function(c, rv) {
-      if (rv) {
-        deferred.reject(rv);
-        return;
-      }
-      deferred.resolve(c);
-    }
-  });
-  return deferred.promise;
-}
-
-function startServer(cert, rc4only) {
-  let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
-                  .createInstance(Ci.nsITLSServerSocket);
-  tlsServer.init(-1, true, -1);
-  tlsServer.serverCert = cert;
-
-  let input, output;
-
-  let listener = {
-    onSocketAccepted: function(socket, transport) {
-      do_print("Accept TLS client connection");
-      let connectionInfo = transport.securityInfo
-                           .QueryInterface(Ci.nsITLSServerConnectionInfo);
-      connectionInfo.setSecurityObserver(listener);
-      input = transport.openInputStream(0, 0, 0);
-      output = transport.openOutputStream(0, 0, 0);
-    },
-    onHandshakeDone: function(socket, status) {
-      do_print("TLS handshake done");
-
-      equal(status.tlsVersionUsed, Ci.nsITLSClientStatus.TLS_VERSION_1_2,
-            "Using TLS 1.2");
-      let expectedCipher = rc4only ? "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"
-                                   : "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
-      equal(status.cipherName, expectedCipher,
-            "Using expected cipher");
-      equal(status.keyLength, 128, "Using 128-bit key");
-      equal(status.macLength, rc4only ? 160 : 128, "Using MAC of expected length");
-
-      input.asyncWait({
-        onInputStreamReady: function(streamReadyInput) {
-          NetUtil.asyncCopy(streamReadyInput, output);
-        }
-      }, 0, 0, Services.tm.currentThread);
-    },
-    onStopListening: function() {}
-  };
-
-  tlsServer.setSessionCache(false);
-  tlsServer.setSessionTickets(false);
-  tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUEST_NEVER);
-  if (rc4only) {
-    let cipherSuites = [
-      TLS_ECDHE_RSA_WITH_RC4_128_SHA,
-      TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
-      TLS_RSA_WITH_RC4_128_SHA,
-      TLS_RSA_WITH_RC4_128_MD5
-    ];
-    tlsServer.setCipherSuites(cipherSuites, cipherSuites.length);
-  }
-
-  tlsServer.asyncListen(listener);
-
-  return tlsServer.port;
-}
-
-function storeCertOverride(port, cert) {
-  let overrideBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
-                     Ci.nsICertOverrideService.ERROR_MISMATCH;
-  certOverrideService.rememberValidityOverride("127.0.0.1", port, cert,
-                                               overrideBits, true);
-}
-
-function startClient(port, expectedResult, options = {}) {
-  let transport =
-    socketTransportService.createTransport(["ssl"], 1, "127.0.0.1", port, null);
-  if (options.isPrivate) {
-    transport.connectionFlags |= Ci.nsISocketTransport.NO_PERMANENT_STORAGE;
-  }
-  let input;
-  let output;
-
-  let deferred = Promise.defer();
-
-  let handler = {
-
-    onTransportStatus: function(unused, status) {
-      if (status === Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
-        output.asyncWait(handler, 0, 0, Services.tm.currentThread);
-      }
-    },
-
-    onInputStreamReady: function(streamReadyInput) {
-      try {
-        let data =
-          NetUtil.readInputStreamToString(streamReadyInput,
-                                          streamReadyInput.available());
-        equal(Cr.NS_OK, expectedResult, "Connection should succeed");
-        equal(data, "HELLO", "Echoed data received");
-      } catch (e) {
-        if (!((e.result == Cr.NS_ERROR_NET_RESET) && options.allowReset) &&
-            (e.result != expectedResult)) {
-          deferred.reject(e);
-        }
-      }
-      streamReadyInput.close();
-      output.close();
-      deferred.resolve();
-    },
-
-    onOutputStreamReady: function(streamReadyOutput) {
-      try {
-        try {
-          streamReadyOutput.write("HELLO", 5);
-        } catch (e) {
-          if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {
-            streamReadyOutput.asyncWait(handler, 0, 0, Services.tm.currentThread);
-            return;
-          }
-          if (e.result != Cr.NS_OK) {
-            ok((e.result === expectedResult) ||
-               (options.allowReset && (e.result === Cr.NS_ERROR_NET_RESET)),
-               "Actual and expected connection result should match");
-            streamReadyOutput.close();
-            deferred.resolve();
-            return;
-          }
-        }
-        do_print("Output to server written");
-        input = transport.openInputStream(0, 0, 0);
-        input.asyncWait(handler, 0, 0, Services.tm.currentThread);
-      } catch (e) {
-        deferred.reject(e);
-      }
-    }
-
-  };
-
-  transport.setEventSink(handler, Services.tm.currentThread);
-  output = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED, 0, 0);
-  output.QueryInterface(Ci.nsIAsyncOutputStream);
-
-  return deferred.promise;
-}
-
-function run_test() {
-  Services.prefs.setBoolPref("security.tls.unrestricted_rc4_fallback", false);
-  run_next_test();
-}
-
-// for sanity check
-add_task(function* () {
-  let cert = yield getCert();
-  ok(!!cert, "Got self-signed cert");
-  let port = startServer(cert, false);
-  storeCertOverride(port, cert);
-  yield startClient(port, Cr.NS_OK);
-  yield startClient(port, Cr.NS_OK, {isPrivate: true});
-});
-
-add_task(function* () {
-  let cert = yield getCert();
-  ok(!!cert, "Got self-signed cert");
-  let port = startServer(cert, true);
-  storeCertOverride(port, cert);
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true});
-
-  weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", true);
-  // private browsing should not affect the permanent storage.
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "");
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
-  // The auto-retry on connection reset is implemented in our HTTP layer.
-  // So we will see the crafted NS_ERROR_NET_RESET when we use
-  // nsISocketTransport directly.
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true, allowReset: true});
-  // retry manually to simulate the HTTP layer
-  yield startClient(port, Cr.NS_OK, {isPrivate: true});
-
-  weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, true);
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "");
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true});
-
-  weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false, true);
-  // temporary override should not change the pref.
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "");
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {allowReset: true});
-  yield startClient(port, Cr.NS_OK);
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true});
-
-  weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, false);
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "");
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true});
-
-  weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false);
-  // permanent override should change the pref.
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "127.0.0.1");
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {allowReset: true});
-  yield startClient(port, Cr.NS_OK);
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true});
-
-  weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, false);
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "");
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {isPrivate: true});
-
-  // add a host to the pref to prepare the next test
-  weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false);
-  yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
-                    {allowReset: true});
-  yield startClient(port, Cr.NS_OK);
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "127.0.0.1");
-});
-
-add_task(function* () {
-  let cert = yield getCert();
-  ok(!!cert, "Got self-signed cert");
-  let port = startServer(cert, false);
-  storeCertOverride(port, cert);
-  yield startClient(port, Cr.NS_OK);
-  // Successful strong cipher will remove the host from the pref.
-  equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
-        "");
-});
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8413,23 +8413,16 @@
   },
   "SSL_VERSION_FALLBACK_INAPPROPRIATE": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 64,
     "description": "TLS/SSL version intolerance was falsely detected, server rejected handshake (see tlsIntoleranceTelemetryBucket() in nsNSSIOLayer.cpp)."
   },
-  "SSL_WEAK_CIPHERS_FALLBACK": {
-    "alert_emails": ["seceng-telemetry@mozilla.com"],
-    "expires_in_version": "never",
-    "kind": "enumerated",
-    "n_values": 64,
-    "description": "Fallback attempted when server did not support any strong cipher suites"
-  },
   "SSL_CIPHER_SUITE_FULL": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 128,
     "description": "Negotiated cipher suite in full handshake (see key in HandshakeCallback in nsNSSCallbacks.cpp)"
   },
   "SSL_CIPHER_SUITE_RESUMED": {
@@ -8481,24 +8474,24 @@
     "n_values": 36,
     "description": "ECDSA signature curve for TLS_*_ECDSA_* in full handshake (23=P-256, 24=P-384, 25=P-521)"
   },
   "SSL_SYMMETRIC_CIPHER_FULL": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 32,
-    "description": "Symmetric cipher used in full handshake (null=0, rc4=1, 3des=4, aes-cbc=7, camellia=8, seed=9, aes-gcm=10)"
+    "description": "Symmetric cipher used in full handshake (null=0, 3des=4, aes-cbc=7, aes-gcm=10, chacha20=11)"
   },
   "SSL_SYMMETRIC_CIPHER_RESUMED": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 32,
-    "description": "Symmetric cipher used in resumed handshake (null=0, rc4=1, 3des=4, aes-cbc=7, camellia=8, seed=9, aes-gcm=10)"
+    "description": "Symmetric cipher used in resumed handshake (null=0, 3des=4, aes-cbc=7, aes-gcm=10, chacha20=11)"
   },
   "SSL_REASONS_FOR_NOT_FALSE_STARTING": {
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 512,
     "description": "Bitmask of reasons we did not false start when libssl would have let us (see key in nsNSSCallbacks.cpp)"
   },
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -1540,17 +1540,16 @@
     "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_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",
     "STS_POLL_BLOCK_TIME",
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -60,17 +60,17 @@ option('--enable-dmd', env='MOZ_DMD',
 def dmd(value):
     if value:
         return True
 
 set_config('MOZ_DMD', dmd)
 set_define('MOZ_DMD', dmd)
 add_old_configure_assignment('MOZ_DMD', dmd)
 imply_option('--enable-profiling', dmd)
-imply_option('--enable-jemalloc', dmd)
+# --enable-jemalloc is implied below.
 imply_option('--enable-replace-malloc', dmd)
 
 # JACK cubeb backend
 # ==============================================================
 option('--enable-jack', env='MOZ_JACK',
        help='Enable JACK audio backend.')
 
 @depends('--enable-jack')
@@ -566,17 +566,26 @@ option('--enable-stylo', env='STYLO_ENAB
 
 @depends('--enable-stylo')
 def stylo(value):
     if value:
         return True
 
 set_config('MOZ_STYLO', stylo)
 set_define('MOZ_STYLO', stylo)
-imply_option('--enable-jemalloc', depends_if('--enable-stylo')(lambda _: 'moz'))
+
+@depends(stylo, dmd)
+def jemalloc(stylo, dmd):
+    if stylo:
+        return 'moz'
+    elif dmd:
+        return True
+
+imply_option('--enable-jemalloc', jemalloc,
+             reason='--enable-dmd or --enable-stylo')
 
 option('--with-servo', env='SERVO_TARGET_DIR', nargs=1,
        help='Absolute path of the target directory where libgeckoservo can '
             'be found. This is generally servo_src_dir/target/release.')
 
 @depends_if('--with-servo')
 def servo_target_dir(value):
     return value[0]
--- a/widget/NativeKeyToDOMKeyName.h
+++ b/widget/NativeKeyToDOMKeyName.h
@@ -188,16 +188,17 @@ KEY_MAP_ANDROID (Symbol, AKEYCODE_SYM)
 KEY_MAP_WIN     (Enter, VK_RETURN)
 KEY_MAP_COCOA   (Enter, kVK_Return)
 KEY_MAP_COCOA   (Enter, kVK_ANSI_KeypadEnter)
 KEY_MAP_COCOA   (Enter, kVK_Powerbook_KeypadEnter)
 KEY_MAP_GTK     (Enter, GDK_Return)
 KEY_MAP_GTK     (Enter, GDK_KP_Enter)
 KEY_MAP_GTK     (Enter, GDK_ISO_Enter)
 KEY_MAP_GTK     (Enter, GDK_3270_Enter)
+KEY_MAP_ANDROID (Enter, AKEYCODE_DPAD_CENTER)
 KEY_MAP_ANDROID (Enter, AKEYCODE_ENTER)
 KEY_MAP_ANDROID (Enter, AKEYCODE_NUMPAD_ENTER)
 
 // Tab
 KEY_MAP_WIN     (Tab, VK_TAB)
 KEY_MAP_COCOA   (Tab, kVK_Tab)
 KEY_MAP_GTK     (Tab, GDK_Tab)
 KEY_MAP_GTK     (Tab, GDK_KP_Tab)
@@ -276,24 +277,26 @@ KEY_MAP_WIN     (Clear, VK_CLEAR)
 KEY_MAP_WIN     (Clear, VK_OEM_CLEAR)
 KEY_MAP_COCOA   (Clear, kVK_ANSI_KeypadClear)
 KEY_MAP_GTK     (Clear, GDK_Clear)
 KEY_MAP_ANDROID (Clear, AKEYCODE_CLEAR)
 
 // Copy
 KEY_MAP_WIN_CMD (Copy, APPCOMMAND_COPY)
 KEY_MAP_GTK     (Copy, GDK_Copy)
+KEY_MAP_ANDROID (Copy, AKEYCODE_COPY)
 
 // CrSel
 KEY_MAP_WIN     (CrSel, VK_CRSEL)
 KEY_MAP_GTK     (CrSel, GDK_3270_CursorSelect) // legacy IBM keyboard layout
 
 // Cut
 KEY_MAP_WIN_CMD (Cut, APPCOMMAND_CUT)
 KEY_MAP_GTK     (Cut, GDK_Cut)
+KEY_MAP_ANDROID (Cut, AKEYCODE_CUT)
 
 // Delete
 KEY_MAP_WIN     (Delete, VK_DELETE)
 KEY_MAP_COCOA   (Delete, kVK_PC_Delete)
 KEY_MAP_GTK     (Delete, GDK_Delete)
 KEY_MAP_GTK     (Delete, GDK_KP_Delete)
 KEY_MAP_ANDROID (Delete, AKEYCODE_FORWARD_DEL)
 
@@ -309,31 +312,31 @@ KEY_MAP_GTK     (ExSel, GDK_3270_ExSelec
 KEY_MAP_WIN     (Insert, VK_INSERT)
 KEY_MAP_GTK     (Insert, GDK_Insert)
 KEY_MAP_GTK     (Insert, GDK_KP_Insert)
 KEY_MAP_ANDROID (Insert, AKEYCODE_INSERT)
 
 // Paste
 KEY_MAP_WIN_CMD (Paste, APPCOMMAND_PASTE)
 KEY_MAP_GTK     (Paste, GDK_Paste)
+KEY_MAP_ANDROID (Paste, AKEYCODE_PASTE)
 
 // Redo
 KEY_MAP_WIN_CMD (Redo, APPCOMMAND_REDO)
 KEY_MAP_GTK     (Redo, GDK_Redo)
 
 // Undo
 KEY_MAP_WIN_CMD (Undo, APPCOMMAND_UNDO)
 KEY_MAP_GTK     (Undo, GDK_Undo)
 
 /******************************************************************************
  * UI Keys
  ******************************************************************************/
 // Accept
 KEY_MAP_WIN     (Accept, VK_ACCEPT)
-KEY_MAP_ANDROID (Accept, AKEYCODE_DPAD_CENTER)
 
 // Attn
 KEY_MAP_WIN_OTH (Attn, VK_ATTN) // not valid with Japanese keyboard layout
 KEY_MAP_GTK     (Attn, GDK_3270_Attn) // legacy IBM keyboard layout
 
 // Cancel
 KEY_MAP_WIN     (Cancel, VK_CANCEL)
 KEY_MAP_GTK     (Cancel, GDK_Cancel)
@@ -358,17 +361,17 @@ KEY_MAP_GTK     (Execute, GDK_Execute)
 KEY_MAP_WIN_CMD (Find, APPCOMMAND_FIND)
 KEY_MAP_GTK     (Find, GDK_Find)
 
 // Help
 KEY_MAP_WIN     (Help, VK_HELP)
 KEY_MAP_WIN_CMD (Help, APPCOMMAND_HELP)
 KEY_MAP_COCOA   (Help, kVK_Help)
 KEY_MAP_GTK     (Help, GDK_Help)
-KEY_MAP_ANDROID (Help, AKEYCODE_ASSIST)
+KEY_MAP_ANDROID (Help, AKEYCODE_HELP)
 
 // Pause
 KEY_MAP_WIN     (Pause, VK_PAUSE)
 KEY_MAP_GTK     (Pause, GDK_Pause)
 // Break is typically mapped to Alt+Pause or Ctrl+Pause on GTK.
 KEY_MAP_GTK     (Pause, GDK_Break)
 KEY_MAP_ANDROID (Pause, AKEYCODE_BREAK)
 
@@ -388,19 +391,21 @@ KEY_MAP_ANDROID (ZoomIn, AKEYCODE_ZOOM_I
 KEY_MAP_GTK     (ZoomOut, GDK_ZoomOut)
 KEY_MAP_ANDROID (ZoomOut, AKEYCODE_ZOOM_OUT)
 
 /******************************************************************************
  * Device Keys
  ******************************************************************************/
 // BrightnessDown
 KEY_MAP_GTK     (BrightnessDown, GDK_MonBrightnessDown)
+KEY_MAP_ANDROID (BrightnessDown, AKEYCODE_BRIGHTNESS_DOWN)
 
 // BrightnessUp
 KEY_MAP_GTK     (BrightnessUp, GDK_MonBrightnessUp)
+KEY_MAP_ANDROID (BrightnessUp, AKEYCODE_BRIGHTNESS_UP)
 
 // Eject
 KEY_MAP_GTK     (Eject, GDK_Eject)
 KEY_MAP_ANDROID (Eject, AKEYCODE_MEDIA_EJECT)
 
 // LogOff
 KEY_MAP_GTK     (LogOff, GDK_LogOff)
 
@@ -421,19 +426,21 @@ KEY_MAP_ANDROID (PrintScreen, AKEYCODE_S
 // Hibernate
 KEY_MAP_GTK     (Hibernate, GDK_Hibernate)
 
 // Standby
 KEY_MAP_WIN     (Standby, VK_SLEEP)
 KEY_MAP_GTK     (Standby, GDK_Standby)
 KEY_MAP_GTK     (Standby, GDK_Suspend)
 KEY_MAP_GTK     (Standby, GDK_Sleep)
+KEY_MAP_ANDROID (Standby, AKEYCODE_SLEEP)
 
 // WakeUp
 KEY_MAP_GTK     (WakeUp, GDK_WakeUp)
+KEY_MAP_ANDROID (WakeUp, AKEYCODE_WAKEUP)
 
 /******************************************************************************
  * IME and Composition Keys
  ******************************************************************************/
 // AllCandidates
 KEY_MAP_GTK     (AllCandidates, GDK_MultipleCandidate) // OADG 109, Zen Koho
 
 // Alphanumeric
@@ -783,16 +790,21 @@ KEY_MAP_GTK     (MailForward, GDK_MailFo
 // MailReply
 KEY_MAP_WIN_CMD (MailReply, APPCOMMAND_REPLY_TO_MAIL)
 KEY_MAP_GTK     (MailReply, GDK_Reply)
 
 // MailSend
 KEY_MAP_WIN_CMD (MailSend, APPCOMMAND_SEND_MAIL)
 KEY_MAP_GTK     (MailSend, GDK_Send)
 
+// MediaFastForward
+KEY_MAP_WIN_CMD (MediaFastForward, APPCOMMAND_MEDIA_FAST_FORWARD)
+KEY_MAP_GTK     (MediaFastForward, GDK_AudioForward)
+KEY_MAP_ANDROID (MediaFastForward, AKEYCODE_MEDIA_FAST_FORWARD)
+
 // MediaPause
 KEY_MAP_WIN_CMD (MediaPause, APPCOMMAND_MEDIA_PAUSE)
 KEY_MAP_GTK     (MediaPause, GDK_AudioPause)
 KEY_MAP_ANDROID (MediaPause, AKEYCODE_MEDIA_PAUSE)
 
 // MediaPlay
 KEY_MAP_WIN_CMD (MediaPlay, APPCOMMAND_MEDIA_PLAY)
 KEY_MAP_GTK     (MediaPlay, GDK_AudioPlay)
@@ -855,47 +867,53 @@ KEY_MAP_GTK     (SpellCheck, GDK_Spell)
  *****************************************************************************/
 // AudioBassBoostDown
 KEY_MAP_WIN_CMD (AudioBassBoostDown, APPCOMMAND_BASS_DOWN)
 
 // AudioBassBoostUp
 KEY_MAP_WIN_CMD (AudioBassBoostUp, APPCOMMAND_BASS_UP)
 
 // AudioVolumeDown
-KEY_MAP_WIN               (AudioVolumeDown, VK_VOLUME_DOWN)
-KEY_MAP_WIN_CMD           (AudioVolumeDown, APPCOMMAND_VOLUME_DOWN)
-KEY_MAP_COCOA             (AudioVolumeDown, kVK_VolumeDown)
-KEY_MAP_GTK               (AudioVolumeDown, GDK_AudioLowerVolume)
-KEY_MAP_ANDROID           (AudioVolumeDown, AKEYCODE_VOLUME_DOWN)
+KEY_MAP_WIN     (AudioVolumeDown, VK_VOLUME_DOWN)
+KEY_MAP_WIN_CMD (AudioVolumeDown, APPCOMMAND_VOLUME_DOWN)
+KEY_MAP_COCOA   (AudioVolumeDown, kVK_VolumeDown)
+KEY_MAP_GTK     (AudioVolumeDown, GDK_AudioLowerVolume)
+KEY_MAP_ANDROID (AudioVolumeDown, AKEYCODE_VOLUME_DOWN)
 
 // AudioVolumeUp
-KEY_MAP_WIN               (AudioVolumeUp, VK_VOLUME_UP)
-KEY_MAP_WIN_CMD           (AudioVolumeUp, APPCOMMAND_VOLUME_UP)
-KEY_MAP_COCOA             (AudioVolumeUp, kVK_VolumeUp)
-KEY_MAP_GTK               (AudioVolumeUp, GDK_AudioRaiseVolume)
-KEY_MAP_ANDROID           (AudioVolumeUp, AKEYCODE_VOLUME_UP)
+KEY_MAP_WIN     (AudioVolumeUp, VK_VOLUME_UP)
+KEY_MAP_WIN_CMD (AudioVolumeUp, APPCOMMAND_VOLUME_UP)
+KEY_MAP_COCOA   (AudioVolumeUp, kVK_VolumeUp)
+KEY_MAP_GTK     (AudioVolumeUp, GDK_AudioRaiseVolume)
+KEY_MAP_ANDROID (AudioVolumeUp, AKEYCODE_VOLUME_UP)
 
 // AudioVolumeMute
-KEY_MAP_WIN               (AudioVolumeMute, VK_VOLUME_MUTE)
-KEY_MAP_WIN_CMD           (AudioVolumeMute, APPCOMMAND_VOLUME_MUTE)
-KEY_MAP_COCOA             (AudioVolumeMute, kVK_Mute)
-KEY_MAP_GTK               (AudioVolumeMute, GDK_AudioMute)
-KEY_MAP_ANDROID           (AudioVolumeMute, AKEYCODE_VOLUME_MUTE)
+KEY_MAP_WIN     (AudioVolumeMute, VK_VOLUME_MUTE)
+KEY_MAP_WIN_CMD (AudioVolumeMute, APPCOMMAND_VOLUME_MUTE)
+KEY_MAP_COCOA   (AudioVolumeMute, kVK_Mute)
+KEY_MAP_GTK     (AudioVolumeMute, GDK_AudioMute)
+KEY_MAP_ANDROID (AudioVolumeMute, AKEYCODE_VOLUME_MUTE)
+
+// MicrophoneVolumeMute
+KEY_MAP_ANDROID (MicrophoneVolumeMute, AKEYCODE_MUTE)
 
 /******************************************************************************
  * Application Keys
  ******************************************************************************/
 // LaunchCalculator
 KEY_MAP_GTK     (LaunchCalculator, GDK_Calculator)
 KEY_MAP_ANDROID (LaunchCalculator, AKEYCODE_CALCULATOR)
 
 // LaunchCalendar
 KEY_MAP_GTK     (LaunchCalendar, GDK_Calendar)
 KEY_MAP_ANDROID (LaunchCalendar, AKEYCODE_CALENDAR)
 
+// LaunchContacts
+KEY_MAP_ANDROID (LaunchContacts, AKEYCODE_CONTACTS)
+
 // LaunchMail
 KEY_MAP_WIN     (LaunchMail, VK_LAUNCH_MAIL)
 KEY_MAP_WIN_CMD (LaunchMail, APPCOMMAND_LAUNCH_MAIL)
 KEY_MAP_GTK     (LaunchMail, GDK_Mail)
 KEY_MAP_ANDROID (LaunchMail, AKEYCODE_ENVELOPE)
 
 // LaunchMediaPlayer
 KEY_MAP_WIN     (LaunchMediaPlayer, VK_LAUNCH_MEDIA_SELECT)
@@ -988,17 +1006,16 @@ KEY_MAP_GTK     (LaunchApplication16, GD
 
 /******************************************************************************
  * Browser Keys
  ******************************************************************************/
 // BrowserBack
 KEY_MAP_WIN     (BrowserBack, VK_BROWSER_BACK)
 KEY_MAP_WIN_CMD (BrowserBack, APPCOMMAND_BROWSER_BACKWARD)
 KEY_MAP_GTK     (BrowserBack, GDK_Back)
-KEY_MAP_ANDROID (BrowserBack, AKEYCODE_BACK)
 
 // BrowserFavorites
 KEY_MAP_WIN     (BrowserFavorites, VK_BROWSER_FAVORITES)
 KEY_MAP_WIN_CMD (BrowserFavorites, APPCOMMAND_BROWSER_FAVORITES)
 KEY_MAP_ANDROID (BrowserFavorites, AKEYCODE_BOOKMARK)
 
 // BrowserForward
 KEY_MAP_WIN     (BrowserForward, VK_BROWSER_FORWARD)
@@ -1026,41 +1043,137 @@ KEY_MAP_ANDROID (BrowserSearch, AKEYCODE
 // BrowserStop
 KEY_MAP_WIN     (BrowserStop, VK_BROWSER_STOP)
 KEY_MAP_WIN_CMD (BrowserStop, APPCOMMAND_BROWSER_STOP)
 KEY_MAP_GTK     (BrowserStop, GDK_Stop)
 
 /******************************************************************************
  * Mobile Phone Keys
  ******************************************************************************/
+// AppSwitch
+KEY_MAP_ANDROID (AppSwitch, AKEYCODE_APP_SWITCH)
+
 // Call
 KEY_MAP_ANDROID (Call, AKEYCODE_CALL)
 
 // Camera
 KEY_MAP_ANDROID (Camera, AKEYCODE_CAMERA)
 
 // CameraFocus
-KEY_MAP_ANDROID_EXCEPT_B2G(CameraFocus,       AKEYCODE_FOCUS)
+KEY_MAP_ANDROID_EXCEPT_B2G(CameraFocus, AKEYCODE_FOCUS)
+
+// EndCall
+KEY_MAP_ANDROID (EndCall, AKEYCODE_ENDCALL)
+
+// GoBack
+KEY_MAP_ANDROID (GoBack, AKEYCODE_BACK)
 
 // GoHome
 KEY_MAP_ANDROID_EXCEPT_B2G(GoHome,     AKEYCODE_HOME)
 KEY_MAP_B2G               (HomeScreen, AKEYCODE_HOME)
 
+// HeadsetHook
+KEY_MAP_ANDROID (HeadsetHook, AKEYCODE_HEADSETHOOK)
+
+// Notification
+KEY_MAP_ANDROID (Notification, AKEYCODE_NOTIFICATION)
+
+// MannerMode
+KEY_MAP_ANDROID (MannerMode, AKEYCODE_MANNER_MODE)
+
 /******************************************************************************
  * TV Keys
  ******************************************************************************/
 // TV
 KEY_MAP_ANDROID (TV, AKEYCODE_TV)
 
+// TV3DMode
+KEY_MAP_ANDROID (TV3DMode, AKEYCODE_3D_MODE)
+
+// TVAntennaCable
+KEY_MAP_ANDROID (TVAntennaCable, AKEYCODE_TV_ANTENNA_CABLE)
+
+// TVAudioDescription
+KEY_MAP_ANDROID (TVAudioDescription, AKEYCODE_TV_AUDIO_DESCRIPTION)
+
+// TVAudioDescriptionMixDown
+KEY_MAP_ANDROID (TVAudioDescriptionMixDown, AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN)
+
+// TVAudioDescriptionMixUp
+KEY_MAP_ANDROID (TVAudioDescriptionMixUp, AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP)
+
+// TVContentsMenu
+KEY_MAP_ANDROID (TVContentsMenu, AKEYCODE_TV_CONTENTS_MENU)
+
+// TVDataService
+KEY_MAP_ANDROID (TVDataService, AKEYCODE_TV_DATA_SERVICE)
+
 // TVInput
 KEY_MAP_ANDROID (TVInput, AKEYCODE_TV_INPUT)
 
+// TVInputComponent1
+KEY_MAP_ANDROID (TVInputComponent1, AKEYCODE_TV_INPUT_COMPONENT_1)
+
+// TVInputComponent2
+KEY_MAP_ANDROID (TVInputComponent2, AKEYCODE_TV_INPUT_COMPONENT_2)
+
+// TVInputComposite1
+KEY_MAP_ANDROID (TVInputComposite1, AKEYCODE_TV_INPUT_COMPOSITE_1)
+
+// TVInputComposite2
+KEY_MAP_ANDROID (TVInputComposite2, AKEYCODE_TV_INPUT_COMPOSITE_2)
+
+// TVInputHDMI1
+KEY_MAP_ANDROID (TVInputHDMI1, AKEYCODE_TV_INPUT_HDMI_1)
+
+// TVInputHDMI2
+KEY_MAP_ANDROID (TVInputHDMI2, AKEYCODE_TV_INPUT_HDMI_2)
+
+// TVInputHDMI3
+KEY_MAP_ANDROID (TVInputHDMI3, AKEYCODE_TV_INPUT_HDMI_3)
+
+// TVInputHDMI4
+KEY_MAP_ANDROID (TVInputHDMI4, AKEYCODE_TV_INPUT_HDMI_4)
+
+// TVInputVGA1
+KEY_MAP_ANDROID (TVInputVGA1, AKEYCODE_TV_INPUT_VGA_1)
+
+// TVNetwork
+KEY_MAP_ANDROID (TVNetwork, AKEYCODE_TV_NETWORK)
+
+// TVNumberEntry
+KEY_MAP_ANDROID (TVNumberEntry, AKEYCODE_TV_NUMBER_ENTRY)
+
 // TVPower
 KEY_MAP_ANDROID (TVPower, AKEYCODE_TV_POWER)
 
+// TVRadioService
+KEY_MAP_ANDROID (TVRadioService, AKEYCODE_TV_RADIO_SERVICE)
+
+// TVSatellite
+KEY_MAP_ANDROID (TVSatellite, AKEYCODE_TV_SATELLITE)
+
+// TVSatelliteBS
+KEY_MAP_ANDROID (TVSatelliteBS, AKEYCODE_TV_SATELLITE_BS)
+
+// TVSatelliteCS
+KEY_MAP_ANDROID (TVSatelliteCS, AKEYCODE_TV_SATELLITE_CS)
+
+// TVSatelliteToggle
+KEY_MAP_ANDROID (TVSatelliteToggle, AKEYCODE_TV_SATELLITE_SERVICE)
+
+// TVTerrestrialAnalog
+KEY_MAP_ANDROID (TVTerrestrialAnalog, AKEYCODE_TV_TERRESTRIAL_ANALOG)
+
+// TVTerrestrialDigital
+KEY_MAP_ANDROID (TVTerrestrialDigital, AKEYCODE_TV_TERRESTRIAL_DIGITAL)
+
+// TVTimer
+KEY_MAP_ANDROID (TVTimer, AKEYCODE_TV_TIMER_PROGRAMMING)
+
 /******************************************************************************
  * Media Controller Keys
  ******************************************************************************/
 // AVRInput
 KEY_MAP_ANDROID (AVRInput, AKEYCODE_AVR_INPUT)
 
 // AVRPower
 KEY_MAP_ANDROID (AVRPower, AKEYCODE_AVR_POWER)
@@ -1076,31 +1189,66 @@ KEY_MAP_ANDROID (ColorF1Green, AKEYCODE_
 // ColorF2Yellow
 KEY_MAP_GTK     (ColorF2Yellow, GDK_Yellow)
 KEY_MAP_ANDROID (ColorF2Yellow, AKEYCODE_PROG_YELLOW)
 
 // ColorF3Blue
 KEY_MAP_GTK     (ColorF3Blue, GDK_Blue)
 KEY_MAP_ANDROID (ColorF3Blue, AKEYCODE_PROG_BLUE)
 
+// ClosedCaptionToggle
+KEY_MAP_ANDROID (ClosedCaptionToggle, AKEYCODE_CAPTIONS)
+
 // Dimmer
 KEY_MAP_GTK     (Dimmer, GDK_BrightnessAdjust)
 
+// DVR
+KEY_MAP_ANDROID (DVR, AKEYCODE_DVR)
+
 // Guide
 KEY_MAP_ANDROID (Guide, AKEYCODE_GUIDE)
 
 // Info
 KEY_MAP_ANDROID (Info, AKEYCODE_INFO)
 
-// MediaFastForward
-KEY_MAP_WIN_CMD (MediaFastForward, APPCOMMAND_MEDIA_FAST_FORWARD)
-KEY_MAP_GTK     (MediaFastForward, GDK_AudioForward)
-KEY_MAP_ANDROID (MediaFastForward, AKEYCODE_MEDIA_FAST_FORWARD)
+// MediaAudioTrack
+KEY_MAP_ANDROID (MediaAudioTrack, AKEYCODE_MEDIA_AUDIO_TRACK)
 
 // MediaLast
+KEY_MAP_ANDROID (MediaLast, AKEYCODE_LAST_CHANNEL)
+
+// MediaTopMenu
+KEY_MAP_ANDROID (MediaTopMenu, AKEYCODE_MEDIA_TOP_MENU)
+
+// MediaSkipBackward
+KEY_MAP_ANDROID (MediaSkipBackward, AKEYCODE_MEDIA_SKIP_BACKWARD)
+
+// MediaSkipForward
+KEY_MAP_ANDROID (MediaSkipForward, AKEYCODE_MEDIA_SKIP_FORWARD)
+
+// MediaStepBackward
+KEY_MAP_ANDROID (MediaStepBackward, AKEYCODE_MEDIA_STEP_BACKWARD)
+
+// MediaStepForward
+KEY_MAP_ANDROID (MediaStepForward, AKEYCODE_MEDIA_STEP_FORWARD)
+
+// NavigateIn
+KEY_MAP_ANDROID (NavigateIn, AKEYCODE_NAVIGATE_IN)
+
+// NavigateNext
+KEY_MAP_ANDROID (NavigateNext, AKEYCODE_NAVIGATE_NEXT)
+
+// NavigateOut
+KEY_MAP_ANDROID (NavigateOut, AKEYCODE_NAVIGATE_OUT)
+
+// NavigatePrevious
+KEY_MAP_ANDROID (NavigatePrevious, AKEYCODE_NAVIGATE_PREVIOUS)
+
+// Pairing
+KEY_MAP_ANDROID (Pairing, AKEYCODE_PAIRING)
 
 // PinPToggle
 KEY_MAP_ANDROID (PinPToggle, AKEYCODE_WINDOW)
 
 // RandomToggle
 KEY_MAP_GTK     (RandomToggle, GDK_AudioRandomPlay)
 
 // Settings
@@ -1109,23 +1257,26 @@ KEY_MAP_ANDROID (Settings, AKEYCODE_SETT
 // STBInput
 KEY_MAP_ANDROID (STBInput, AKEYCODE_STB_INPUT)
 
 // STBPower
 KEY_MAP_ANDROID (STBPower, AKEYCODE_STB_POWER)
 
 // Subtitle
 KEY_MAP_GTK     (Subtitle, GDK_Subtitle)
-KEY_MAP_ANDROID (Subtitle, AKEYCODE_CAPTIONS)
+
+// Teletext
+KEY_MAP_ANDROID (Teletext, AKEYCODE_TV_TELETEXT)
 
 // VideoModeNext
 KEY_MAP_GTK     (VideoModeNext, GDK_Next_VMode)
 
 // ZoomToggle
 KEY_MAP_WIN     (ZoomToggle, VK_ZOOM)
+KEY_MAP_ANDROID (ZoomToggle, AKEYCODE_TV_ZOOM_MODE)
 
 /******************************************************************************
  * Keys not defined by any standards
  ******************************************************************************/
 // SoftLeft
 KEY_MAP_ANDROID (SoftLeft, AKEYCODE_SOFT_LEFT)
 
 // SoftRight
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -143,16 +143,98 @@ enum {
     AKEYCODE_MUHENKAN           = 213,
     AKEYCODE_HENKAN             = 214,
     AKEYCODE_KATAKANA_HIRAGANA  = 215,
     AKEYCODE_YEN                = 216,
     AKEYCODE_RO                 = 217,
     AKEYCODE_KANA               = 218,
     AKEYCODE_ASSIST             = 219,
 #endif
+#if __ANDROID_API__ < 18
+    AKEYCODE_BRIGHTNESS_DOWN    = 220,
+    AKEYCODE_BRIGHTNESS_UP      = 221,
+#endif
+#if __ANDROID_API__ < 19
+    AKEYCODE_MEDIA_AUDIO_TRACK  = 222,
+#endif
+#if __ANDROID_API__ < 20
+    AKEYCODE_SLEEP              = 223,
+    AKEYCODE_WAKEUP             = 224,
+#endif
+#if __ANDROID_API__ < 21
+    AKEYCODE_PAIRING                       = 225,
+    AKEYCODE_MEDIA_TOP_MENU                = 226,
+    AKEYCODE_11                            = 227,
+    AKEYCODE_12                            = 228,
+    AKEYCODE_LAST_CHANNEL                  = 229,
+    AKEYCODE_TV_DATA_SERVICE               = 230,
+    AKEYCODE_VOICE_ASSIST                  = 231,
+    AKEYCODE_TV_RADIO_SERVICE              = 232,
+    AKEYCODE_TV_TELETEXT                   = 233,
+    AKEYCODE_TV_NUMBER_ENTRY               = 234,
+    AKEYCODE_TV_TERRESTRIAL_ANALOG         = 235,
+    AKEYCODE_TV_TERRESTRIAL_DIGITAL        = 236,
+    AKEYCODE_TV_SATELLITE                  = 237,
+    AKEYCODE_TV_SATELLITE_BS               = 238,
+    AKEYCODE_TV_SATELLITE_CS               = 239,
+    AKEYCODE_TV_SATELLITE_SERVICE          = 240,
+    AKEYCODE_TV_NETWORK                    = 241,
+    AKEYCODE_TV_ANTENNA_CABLE              = 242,
+    AKEYCODE_TV_INPUT_HDMI_1               = 243,
+    AKEYCODE_TV_INPUT_HDMI_2               = 244,
+    AKEYCODE_TV_INPUT_HDMI_3               = 245,
+    AKEYCODE_TV_INPUT_HDMI_4               = 246,
+    AKEYCODE_TV_INPUT_COMPOSITE_1          = 247,
+    AKEYCODE_TV_INPUT_COMPOSITE_2          = 248,
+    AKEYCODE_TV_INPUT_COMPONENT_1          = 249,
+    AKEYCODE_TV_INPUT_COMPONENT_2          = 250,
+    AKEYCODE_TV_INPUT_VGA_1                = 251,
+    AKEYCODE_TV_AUDIO_DESCRIPTION          = 252,
+    AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP   = 253,
+    AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254,
+    AKEYCODE_TV_ZOOM_MODE                  = 255,
+    AKEYCODE_TV_CONTENTS_MENU              = 256,
+    AKEYCODE_TV_MEDIA_CONTEXT_MENU         = 257,
+    AKEYCODE_TV_TIMER_PROGRAMMING          = 258,
+    AKEYCODE_HELP                          = 259,
+#endif
+#if __ANDROID_API__ < 23
+    AKEYCODE_NAVIGATE_PREVIOUS  = 260,
+    AKEYCODE_NAVIGATE_NEXT      = 261,
+    AKEYCODE_NAVIGATE_IN        = 262,
+    AKEYCODE_NAVIGATE_OUT       = 263,
+#endif
+#if __ANDROID_API__ < 24
+    AKEYCODE_STEM_PRIMARY       = 264,
+    AKEYCODE_STEM_1             = 265,
+    AKEYCODE_STEM_2             = 266,
+    AKEYCODE_STEM_3             = 267,
+    AKEYCODE_DPAD_UP_LEFT       = 268,
+    AKEYCODE_DPAD_DOWN_LEFT     = 269,
+    AKEYCODE_DPAD_UP_RIGHT      = 270,
+    AKEYCODE_DPAD_DOWN_RIGHT    = 271,
+#endif
+#if __ANDROID_API__ < 23
+    AKEYCODE_MEDIA_SKIP_FORWARD  = 272,
+    AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
+    AKEYCODE_MEDIA_STEP_FORWARD  = 274,
+    AKEYCODE_MEDIA_STEP_BACKWARD = 275,
+#endif
+#if __ANDROID_API__ < 24
+    AKEYCODE_SOFT_SLEEP         = 276,
+    AKEYCODE_CUT                = 277,
+    AKEYCODE_COPY               = 278,
+    AKEYCODE_PASTE              = 279,
+#endif
+#if __ANDROID_API__ < 25
+    AKEYCODE_SYSTEM_NAVIGATION_UP    = 280,
+    AKEYCODE_SYSTEM_NAVIGATION_DOWN  = 281,
+    AKEYCODE_SYSTEM_NAVIGATION_LEFT  = 282,
+    AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283,
+#endif
 
     AMETA_FUNCTION_ON           = 0x00000008,
     AMETA_CTRL_ON               = 0x00001000,
     AMETA_CTRL_LEFT_ON          = 0x00002000,
     AMETA_CTRL_RIGHT_ON         = 0x00004000,
     AMETA_META_ON               = 0x00010000,
     AMETA_META_LEFT_ON          = 0x00020000,
     AMETA_META_RIGHT_ON         = 0x00040000,
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2320,20 +2320,17 @@ ConvertAndroidKeyCodeToKeyNameIndex(int 
         case AKEYCODE_NUMPAD_EQUALS:
         case AKEYCODE_NUMPAD_LEFT_PAREN:
         case AKEYCODE_NUMPAD_RIGHT_PAREN:
 
         case AKEYCODE_YEN:                // yen sign key
         case AKEYCODE_RO:                 // Japanese Ro key
             return KEY_NAME_INDEX_USE_STRING;
 
-        case AKEYCODE_ENDCALL:
         case AKEYCODE_NUM:                // XXX Not sure
-        case AKEYCODE_HEADSETHOOK:
-        case AKEYCODE_NOTIFICATION:       // XXX Not sure
         case AKEYCODE_PICTSYMBOLS:
 
         case AKEYCODE_BUTTON_A:
         case AKEYCODE_BUTTON_B:
         case AKEYCODE_BUTTON_C:
         case AKEYCODE_BUTTON_X:
         case AKEYCODE_BUTTON_Y:
         case AKEYCODE_BUTTON_Z:
@@ -2342,41 +2339,34 @@ ConvertAndroidKeyCodeToKeyNameIndex(int 
         case AKEYCODE_BUTTON_L2:
         case AKEYCODE_BUTTON_R2:
         case AKEYCODE_BUTTON_THUMBL:
         case AKEYCODE_BUTTON_THUMBR:
         case AKEYCODE_BUTTON_START:
         case AKEYCODE_BUTTON_SELECT:
         case AKEYCODE_BUTTON_MODE:
 
-        case AKEYCODE_MUTE: // mutes the microphone
         case AKEYCODE_MEDIA_CLOSE:
 
-        case AKEYCODE_DVR:
-
         case AKEYCODE_BUTTON_1:
         case AKEYCODE_BUTTON_2:
         case AKEYCODE_BUTTON_3:
         case AKEYCODE_BUTTON_4:
         case AKEYCODE_BUTTON_5:
         case AKEYCODE_BUTTON_6:
         case AKEYCODE_BUTTON_7:
         case AKEYCODE_BUTTON_8:
         case AKEYCODE_BUTTON_9:
         case AKEYCODE_BUTTON_10:
         case AKEYCODE_BUTTON_11:
         case AKEYCODE_BUTTON_12:
         case AKEYCODE_BUTTON_13:
         case AKEYCODE_BUTTON_14:
         case AKEYCODE_BUTTON_15:
         case AKEYCODE_BUTTON_16:
-
-        case AKEYCODE_MANNER_MODE:
-        case AKEYCODE_3D_MODE:
-        case AKEYCODE_CONTACTS:
             return KEY_NAME_INDEX_Unidentified;
 
         case AKEYCODE_UNKNOWN:
             MOZ_ASSERT(
                 action != AKEY_EVENT_ACTION_MULTIPLE,
                 "Don't call this when action is AKEY_EVENT_ACTION_MULTIPLE!");
             // It's actually an unknown key if the action isn't ACTION_MULTIPLE.
             // However, it might cause text input.  So, let's check the value.
--- a/widget/gonk/libui/android_keycodes.h
+++ b/widget/gonk/libui/android_keycodes.h
@@ -298,16 +298,40 @@ enum {
     AKEYCODE_TV_AUDIO_DESCRIPTION = 252,
     AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253,
     AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254,
     AKEYCODE_TV_ZOOM_MODE    = 255,
     AKEYCODE_TV_CONTENTS_MENU = 256,
     AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257,
     AKEYCODE_TV_TIMER_PROGRAMMING = 258,
     AKEYCODE_HELP            = 259,
+    AKEYCODE_NAVIGATE_PREVIOUS = 260,
+    AKEYCODE_NAVIGATE_NEXT   = 261,
+    AKEYCODE_NAVIGATE_IN     = 262,
+    AKEYCODE_NAVIGATE_OUT    = 263,
+    AKEYCODE_STEM_PRIMARY    = 264,
+    AKEYCODE_STEM_1          = 265,
+    AKEYCODE_STEM_2          = 266,
+    AKEYCODE_STEM_3          = 267,
+    AKEYCODE_DPAD_UP_LEFT    = 268,
+    AKEYCODE_DPAD_DOWN_LEFT  = 269,
+    AKEYCODE_DPAD_UP_RIGHT   = 270,
+    AKEYCODE_DPAD_DOWN_RIGHT = 271,
+    AKEYCODE_MEDIA_SKIP_FORWARD = 272,
+    AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
+    AKEYCODE_MEDIA_STEP_FORWARD = 274,
+    AKEYCODE_MEDIA_STEP_BACKWARD = 275,
+    AKEYCODE_SOFT_SLEEP      = 276,
+    AKEYCODE_CUT             = 277,
+    AKEYCODE_COPY            = 278,
+    AKEYCODE_PASTE           = 279,
+    AKEYCODE_SYSTEM_NAVIGATION_UP = 280,
+    AKEYCODE_SYSTEM_NAVIGATION_DOWN = 281,
+    AKEYCODE_SYSTEM_NAVIGATION_LEFT = 282,
+    AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283,
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
 };
 
 #ifdef __cplusplus
 }
 #endif
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -273,18 +273,16 @@ public:
   {
   public:
     virtual void Disconnect() = 0;
 
     // MSVC complains when an inner class (ThenValueBase::{Resolve,Reject}Runnable)
     // tries to access an inherited protected member.
     bool IsDisconnected() const { return mDisconnected; }
 
-    virtual MozPromise* CompletionPromise() = 0;
-
     virtual void AssertIsDead() = 0;
 
   protected:
     Request() : mComplete(false), mDisconnected(false) {}
     virtual ~Request() {}
 
     bool mComplete;
     bool mDisconnected;
@@ -295,16 +293,18 @@ protected:
   /*
    * A ThenValue tracks a single consumer waiting on the promise. When a consumer
    * invokes promise->Then(...), a ThenValue is created. Once the Promise is
    * resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which
    * invokes the resolve/reject method and then deletes the ThenValue.
    */
   class ThenValueBase : public Request
   {
+    friend class MozPromise;
+
   public:
     class ResolveOrRejectRunnable : public Runnable
     {
     public:
       ResolveOrRejectRunnable(ThenValueBase* aThenValue, MozPromise* aPromise)
         : mThenValue(aThenValue)
         , mPromise(aPromise)
       {
@@ -328,39 +328,20 @@ protected:
       }
 
     private:
       RefPtr<ThenValueBase> mThenValue;
       RefPtr<MozPromise> mPromise;
     };
 
     ThenValueBase(AbstractThread* aResponseTarget,
-                  const char* aCallSite,
-                  bool aInitCompletionPromise = false)
+                  const char* aCallSite)
       : mResponseTarget(aResponseTarget)
       , mCallSite(aCallSite)
-      , mInitCompletionPromise(aInitCompletionPromise)
-    {
-      if (mInitCompletionPromise) {
-        mCompletionPromise = new MozPromise::Private(
-          "<completion promise>", true /* aIsCompletionPromise */);
-      }
-    }
-
-    MozPromise* CompletionPromise() override
-    {
-      MOZ_DIAGNOSTIC_ASSERT(mInitCompletionPromise ||
-                            mResponseTarget->IsCurrentThreadIn());
-      MOZ_DIAGNOSTIC_ASSERT(!Request::mComplete);
-      if (!mInitCompletionPromise && !mCompletionPromise) {
-        mCompletionPromise = new MozPromise::Private(
-          "<completion promise>", true /* aIsCompletionPromise */);
-      }
-      return mCompletionPromise;
-    }
+    { }
 
     void AssertIsDead() override
     {
       // We want to assert that this ThenValues is dead - that is to say, that
       // there are no consumers waiting for the result. In the case of a normal
       // ThenValue, we check that it has been disconnected, which is the way
       // that the consumer signals that it no longer wishes to hear about the
       // result. If this ThenValue has a completion promise (which is mutually
@@ -439,20 +420,16 @@ protected:
 
     // Declaring RefPtr<MozPromise::Private> here causes build failures
     // on MSVC because MozPromise::Private is only forward-declared at this
     // point. This hack can go away when we inline-declare MozPromise::Private,
     // which is blocked on the B2G ICS compiler being too old.
     RefPtr<MozPromise> mCompletionPromise;
 
     const char* mCallSite;
-
-    // True if mCompletionPromise should be initialized in the constructor
-    // to make CompletionPromise() thread-safe.
-    const bool mInitCompletionPromise;
   };
 
   /*
    * We create two overloads for invoking Resolve/Reject Methods so as to
    * make the resolve/reject value argument "optional".
    */
 
   template<typename ThisType, typename MethodType, typename ValueType>
@@ -494,18 +471,18 @@ protected:
   }
 
   template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
   class MethodThenValue : public ThenValueBase
   {
   public:
     MethodThenValue(AbstractThread* aResponseTarget, ThisType* aThisVal,
                     ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod,
-                    const char* aCallSite, bool aInitCompletionPromise = false)
-      : ThenValueBase(aResponseTarget, aCallSite, aInitCompletionPromise)
+                    const char* aCallSite)
+      : ThenValueBase(aResponseTarget, aCallSite)
       , mThisVal(aThisVal)
       , mResolveMethod(aResolveMethod)
       , mRejectMethod(aRejectMethod) {}
 
   virtual void Disconnect() override
   {
     ThenValueBase::Disconnect();
 
@@ -543,19 +520,18 @@ protected:
   // NB: We could use std::function here instead of a template if it were supported. :-(
   template<typename ResolveFunction, typename RejectFunction>
   class FunctionThenValue : public ThenValueBase
   {
   public:
     FunctionThenValue(AbstractThread* aResponseTarget,
                       ResolveFunction&& aResolveFunction,
                       RejectFunction&& aRejectFunction,
-                      const char* aCallSite,
-                      bool aInitCompletionPromise = false)
-      : ThenValueBase(aResponseTarget, aCallSite, aInitCompletionPromise)
+                      const char* aCallSite)
+      : ThenValueBase(aResponseTarget, aCallSite)
     {
       mResolveFunction.emplace(Move(aResolveFunction));
       mRejectFunction.emplace(Move(aRejectFunction));
     }
 
   virtual void Disconnect() override
   {
     ThenValueBase::Disconnect();
@@ -632,49 +608,50 @@ public:
                        ResolveFunction&& aResolveFunction, RejectFunction&& aRejectFunction)
   {
     RefPtr<ThenValueBase> thenValue = new FunctionThenValue<ResolveFunction, RejectFunction>(aResponseThread,
                                               Move(aResolveFunction), Move(aRejectFunction), aCallSite);
     ThenInternal(aResponseThread, thenValue, aCallSite);
     return thenValue.forget(); // Implicit conversion from already_AddRefed<ThenValueBase> to RefPtr<Request>.
   }
 
-  // Equivalent to Then(target, ...)->CompletionPromise()
-  // without the restriction that CompletionPromise() must be called on the
-  // |target| thread. So ThenPromise() can be called on any thread as Then().
+  // ThenPromise() can be called on any thread as Then().
   // The syntax is close to JS promise and makes promise chaining easier
   // where you can do: p->ThenPromise()->ThenPromise()->ThenPromise();
   //
   // Note you would have to call Then() instead when the result needs to be held
   // by a MozPromiseRequestHolder for future disconnection.
-  //
-  // TODO: replace Then()->CompletionPromise() with ThenPromise() and
-  // stop exposing CompletionPromise() to the client code.
   template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
   MOZ_MUST_USE RefPtr<MozPromise>
   ThenPromise(AbstractThread* aResponseThread, const char* aCallSite, ThisType* aThisVal,
               ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
   {
     using ThenType = MethodThenValue<ThisType, ResolveMethodType, RejectMethodType>;
-    RefPtr<ThenValueBase> thenValue = new ThenType(aResponseThread, aThisVal, aResolveMethod,
-      aRejectMethod, aCallSite, true /* aInitCompletionPromise */);
+    RefPtr<ThenValueBase> thenValue = new ThenType(
+      aResponseThread, aThisVal, aResolveMethod, aRejectMethod, aCallSite);
+    // mCompletionPromise must be created before ThenInternal() to avoid race.
+    thenValue->mCompletionPromise = new MozPromise::Private(
+      "<completion promise>", true /* aIsCompletionPromise */);
     ThenInternal(aResponseThread, thenValue, aCallSite);
-    return thenValue->CompletionPromise();
+    return thenValue->mCompletionPromise;
   }
 
   template<typename ResolveFunction, typename RejectFunction>
   MOZ_MUST_USE RefPtr<MozPromise>
   ThenPromise(AbstractThread* aResponseThread, const char* aCallSite,
               ResolveFunction&& aResolveFunction, RejectFunction&& aRejectFunction)
   {
     using ThenType = FunctionThenValue<ResolveFunction, RejectFunction>;
-    RefPtr<ThenValueBase> thenValue = new ThenType(aResponseThread, Move(aResolveFunction),
-      Move(aRejectFunction), aCallSite, true /* aInitCompletionPromise */);
+    RefPtr<ThenValueBase> thenValue = new ThenType(
+      aResponseThread, Move(aResolveFunction), Move(aRejectFunction), aCallSite);
+    // mCompletionPromise must be created before ThenInternal() to avoid race.
+    thenValue->mCompletionPromise = new MozPromise::Private(
+      "<completion promise>", true /* aIsCompletionPromise */);
     ThenInternal(aResponseThread, thenValue, aCallSite);
-    return thenValue->CompletionPromise();
+    return thenValue->mCompletionPromise;
   }
 
   void ChainTo(already_AddRefed<Private> aChainedPromise, const char* aCallSite)
   {
     MutexAutoLock lock(mMutex);
     MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveRequest);
     mHaveRequest = true;
     RefPtr<Private> chainedPromise = aChainedPromise;