Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 31 Jan 2017 15:57:48 +0100
changeset 468838 06928edb7f9eeb7c503496c5fb1913818a5c9e65
parent 468837 2467b35c59b20469943c6091197dada4bcd1f69d (current diff)
parent 468496 b47946b2076f6ac3ffd2cb72367f789237a11ab6 (diff)
child 468839 d1b25168d2ccaa52a7609d58b34ddd129828d5f3
push id43551
push userbmo:kgilbert@mozilla.com
push dateTue, 31 Jan 2017 23:27:06 +0000
milestone54.0a1
Merge mozilla-central to mozilla-inbound
dom/ipc/TabParent.cpp
dom/media/gmp/rlz/COPYING
dom/media/gmp/rlz/GMPDeviceBinding.cpp
dom/media/gmp/rlz/GMPDeviceBinding.h
dom/media/gmp/rlz/README.mozilla
dom/media/gmp/rlz/lib/assert.h
dom/media/gmp/rlz/lib/machine_id.h
dom/media/gmp/rlz/lib/string_utils.cc
dom/media/gmp/rlz/lib/string_utils.h
dom/media/gmp/rlz/mac/lib/machine_id_mac.cc
dom/media/gmp/rlz/moz.build
dom/media/gmp/rlz/sha256.c
dom/media/gmp/rlz/sha256.h
dom/media/gmp/rlz/win/lib/machine_id_win.cc
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -453,23 +453,33 @@ function findChildShell(aDocument, aDocS
   }
   return null;
 }
 
 var gPopupBlockerObserver = {
   _reportButton: null,
 
   onReportButtonMousedown(aEvent) {
-    // If this method is called on the same event tick as the popup gets
-    // hidden, do nothing to avoid re-opening the popup.
+    // The button is part of the textbox that is considered the popup's anchor,
+    // thus consumeoutsideclicks="false" is ignored. Moreover On OS X the popup
+    // is hidden well before mousedown gets dispatched.
+    // Thus, if the popup is open and the user clicks on the button, it gets
+    // hidden before mousedown, and may then be unexpectedly reopened by click.
+    // To avoid this, we check if mousedown is in the same tick as popupHidden,
+    // and, in such a case, we don't handle the click event.
+    // Note we can't just openPopup in mousedown, cause this popup is shared by
+    // multiple anchors, and we could end up opening it just before the other
+    // anchor tries to hide it.
     if (aEvent.button != 0 || aEvent.target != this._reportButton || this.isPopupHidingTick)
       return;
 
-    document.getElementById("blockedPopupOptions")
-            .openPopup(this._reportButton, "after_end", 0, 2, false, false, aEvent);
+    this._reportButton.addEventListener("click", event => {
+      document.getElementById("blockedPopupOptions")
+              .openPopup(event.target, "after_end", 0, 2, false, false, event);
+    }, { once: true });
   },
 
   handleEvent(aEvent) {
     if (aEvent.originalTarget != gBrowser.selectedBrowser)
       return;
 
     if (!this._reportButton)
       this._reportButton = document.getElementById("page-report-button");
@@ -644,21 +654,22 @@ var gPopupBlockerObserver = {
       // Show the separator if we added any
       // showable popup addresses to the menu.
       if (foundUsablePopupURI)
         blockedPopupsSeparator.removeAttribute("hidden");
     }, null);
   },
 
   onPopupHiding(aEvent) {
-    if (aEvent.target.anchorNode.id == "page-report-button")
+    if (aEvent.target.anchorNode.id == "page-report-button") {
       aEvent.target.anchorNode.removeAttribute("open");
 
-    this.isPopupHidingTick = true;
-    setTimeout(() => this.isPopupHidingTick = false, 0);
+      this.isPopupHidingTick = true;
+      setTimeout(() => this.isPopupHidingTick = false, 0);
+    }
 
     let item = aEvent.target.lastChild;
     while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
       let next = item.previousSibling;
       item.remove();
       item = next;
     }
   },
--- a/browser/base/content/test/general/browser_selectpopup.js
+++ b/browser/base/content/test/general/browser_selectpopup.js
@@ -75,16 +75,24 @@ const PAGECONTENT_SOMEHIDDEN =
 const PAGECONTENT_TRANSLATED =
   "<html><body>" +
   "<div id='div'>" +
   "<iframe id='frame' width='320' height='295' style='border: none;'" +
   "        src='data:text/html,<select id=select autofocus><option>he he he</option><option>boo boo</option><option>baz baz</option></select>'" +
   "</iframe>" +
   "</div></body></html>";
 
+const PAGECONTENT_COLORS =
+  "<html><head><style>.blue { color: #fff; background-color: #00f; } .green { color: #800080; background-color: green; }</style>" +
+  "<body><select id='one'>" +
+  '  <option value="One" style="color: #fff; background-color: #f00;">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(255, 0, 0)"}</option>' +
+  '  <option value="Two" class="blue">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 255)"}</option>' +
+  '  <option value="Three" class="green">{"color": "rgb(128, 0, 128)", "backgroundColor": "rgb(0, 128, 0)"}</option>' +
+  "</select></body></html>";
+
 function openSelectPopup(selectPopup, mode = "key", selector = "select", win = window) {
   let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
 
   if (mode == "click" || mode == "mousedown") {
     let mousePromise;
     if (mode == "click") {
       mousePromise = BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, win.gBrowser.selectedBrowser);
     } else {
@@ -724,8 +732,87 @@ add_task(function* test_somehidden() {
        "Item " + (idx++) + " is visible");
     child = child.nextSibling;
   }
 
   yield hideSelectPopup(selectPopup, "escape");
   yield BrowserTestUtils.removeTab(tab);
 });
 
+add_task(function* test_colors_applied_to_popup() {
+  function inverseRGBString(rgbString) {
+    let [, r, g, b] = rgbString.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
+    return `rgb(${255 - r}, ${255 - g}, ${255 - b})`;
+  }
+
+  const pageUrl = "data:text/html," + escape(PAGECONTENT_COLORS);
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
+
+  let selectPopup = document.getElementById("ContentSelectDropdown").menupopup;
+
+  let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
+  yield popupShownPromise;
+
+  // The label contains a JSON string of the expected colors for
+  // `color` and `background-color`.
+  is(selectPopup.parentNode.itemCount, 3, "Correct number of items");
+  let child = selectPopup.firstChild;
+  let idx = 1;
+
+  ok(child.selected, "The first child should be selected");
+  while (child) {
+    let expectedColors = JSON.parse(child.label);
+
+    // We need to use Canvas here to get the actual pixel color
+    // because the computedStyle will only tell us the 'color' or
+    // 'backgroundColor' of the element, but not what the displayed
+    // color is due to composition of various CSS rules such as
+    // 'filter' which is applied when elements have custom background
+    // or foreground elements.
+    let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+    canvas = document.documentElement.appendChild(canvas);
+    let rect = child.getBoundingClientRect();
+    canvas.setAttribute("width", rect.width);
+    canvas.setAttribute("height", rect.height);
+    canvas.mozOpaque = true;
+
+    let ctx = canvas.getContext("2d");
+    ctx.drawWindow(window, rect.x + rect.left, rect.y + rect.top, rect.width, rect.height, "#000", ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
+    let frame = ctx.getImageData(0, 0, rect.width, rect.height);
+
+    let pixels = frame.data.length / 4;
+    // Assume the inverse backgroundColor is the color of the first pixel.
+    let [inverseBgR, inverseBgG, inverseBgB] = frame.data;
+    let inverseBackgroundColor = `rgb(${inverseBgR}, ${inverseBgG}, ${inverseBgB})`;
+    // Use the next different pixel color as the foreground color, assuming
+    // no anti-aliasing.
+    let inverseColor = inverseBackgroundColor;
+    for (let i = 0; i < pixels; i++) {
+      if (inverseBgR != frame.data[i * 4 + 0] &&
+          inverseBgG != frame.data[i * 4 + 1] &&
+          inverseBgB != frame.data[i * 4 + 2]) {
+        inverseColor = `rgb(${frame.data[i * 4 + 0]}, ${frame.data[i * 4 + 1]}, ${frame.data[i * 4 + 2]})`;
+      }
+    }
+    // The canvas code above isn't getting the right colors for the pixels,
+    // it always returns rgb(255,255,255).
+    todo_is(inverseColor, inverseRGBString(getComputedStyle(child).color),
+      "Item " + (idx) + " has correct inverse foreground color when selected");
+    todo_is(inverseBackgroundColor, inverseRGBString(getComputedStyle(child).backgroundColor),
+      "Item " + (idx) + " has correct inverse background color when selected");
+
+    canvas.remove();
+
+    // Press Down to move the selected item to the next item in the
+    // list and check the colors of this item when it's not selected.
+    EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
+
+    is(getComputedStyle(child).color, expectedColors.color,
+       "Item " + (idx) + " has correct foreground color");
+    is(getComputedStyle(child).backgroundColor, expectedColors.backgroundColor,
+       "Item " + (idx++) + " has correct background color");
+    child = child.nextSibling;
+  }
+
+  yield hideSelectPopup(selectPopup, "escape");
+  yield BrowserTestUtils.removeTab(tab);
+});
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -1,16 +1,17 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 Cu.import("resource://gre/modules/MatchPattern.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 var {
   ExtensionError,
   IconDetails,
   SingletonEventManager,
 } = ExtensionUtils;
 
 const ACTION_MENU_TOP_LEVEL_LIMIT = 6;
@@ -227,16 +228,23 @@ var gMenuBuilder = {
         // Select the clicked radio item.
         item.checked = true;
       }
 
       item.tabManager.addActiveTabPermission();
 
       let tab = item.tabManager.convert(contextData.tab);
       let info = item.getClickInfo(contextData, wasChecked);
+
+      const map = {shiftKey: "Shift", altKey: "Alt", metaKey: "Command", ctrlKey: "Ctrl"};
+      info.modifiers = Object.keys(map).filter(key => event[key]).map(key => map[key]);
+      if (event.ctrlKey && AppConstants.platform === "macosx") {
+        info.modifiers.push("MacCtrl");
+      }
+
       item.extension.emit("webext-contextmenu-menuitem-click", info, tab);
     });
 
     return element;
   },
 
   handleEvent(event) {
     if (this.xulMenu != event.target || event.type != "popuphidden") {
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js
@@ -1,12 +1,14 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
+const PAGE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
+
 // Loaded both as a background script and a tab page.
 function testScript() {
   let page = location.pathname.includes("tab.html") ? "tab" : "background";
   let clickCounts = {
     old: 0,
     new: 0,
   };
   browser.contextMenus.onClicked.addListener(() => {
@@ -71,18 +73,17 @@ function testScript() {
     pages = pages.filter(w => w !== window);
     browser.test.assertEq(pages[0], browser.extension.getBackgroundPage(),
         "Expected the other page to be a background page");
     browser.test.sendMessage("tab.html ready");
   }
 }
 
 add_task(function* () {
-  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
-    "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
 
   gBrowser.selectedTab = tab1;
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["contextMenus"],
     },
     background: testScript,
@@ -189,8 +190,57 @@ add_task(function* () {
       // more coverage, let's use removeAll instead of remove.
       extension.sendMessage(pageOne, "removeAll");
       yield extension.awaitMessage("next");
     }
   }
   yield extension.unload();
   yield BrowserTestUtils.removeTab(tab1);
 });
+
+add_task(function* test_onclick_modifiers() {
+  const manifest = {
+    permissions: ["contextMenus"],
+  };
+
+  function background() {
+    function onclick(info) {
+      browser.test.sendMessage("click", info);
+    }
+    browser.contextMenus.create({contexts: ["all"], title: "modify", onclick});
+    browser.test.sendMessage("ready");
+  }
+
+  const extension = ExtensionTestUtils.loadExtension({manifest, background});
+  const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
+
+  yield extension.startup();
+  yield extension.awaitMessage("ready");
+
+  function* click(modifiers = {}) {
+    const menu = yield openContextMenu();
+    const items = menu.getElementsByAttribute("label", "modify");
+    yield closeExtensionContextMenu(items[0], modifiers);
+    return extension.awaitMessage("click");
+  }
+
+  const plain = yield click();
+  is(plain.modifiers.length, 0, "modifiers array empty with a plain click");
+
+  const shift = yield click({shiftKey: true});
+  is(shift.modifiers.join(), "Shift", "Correct modifier: Shift");
+
+  const ctrl = yield click({ctrlKey: true});
+  if (AppConstants.platform !== "macosx") {
+    is(ctrl.modifiers.join(), "Ctrl", "Correct modifier: Ctrl");
+  } else {
+    is(ctrl.modifiers.sort().join(), "Ctrl,MacCtrl", "Correct modifier: Ctrl (and MacCtrl)");
+
+    const meta = yield click({metaKey: true});
+    is(meta.modifiers.join(), "Command", "Correct modifier: Command");
+  }
+
+  const altShift = yield click({altKey: true, shiftKey: true});
+  is(altShift.modifiers.sort().join(), "Alt,Shift", "Correct modifiers: Shift+Alt");
+
+  yield BrowserTestUtils.removeTab(tab);
+  yield extension.unload();
+});
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -252,20 +252,20 @@ function* openExtensionContextMenu(selec
 
   let extensionMenu = topLevelMenu[0].childNodes[0];
   let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
   EventUtils.synthesizeMouseAtCenter(extensionMenu, {});
   yield popupShownPromise;
   return extensionMenu;
 }
 
-function* closeExtensionContextMenu(itemToSelect) {
+function* closeExtensionContextMenu(itemToSelect, modifiers = {}) {
   let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
   let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
-  EventUtils.synthesizeMouseAtCenter(itemToSelect, {});
+  EventUtils.synthesizeMouseAtCenter(itemToSelect, modifiers);
   yield popupHiddenPromise;
 }
 
 function* openChromeContextMenu(menuId, target, win = window) {
   const node = win.document.querySelector(target);
   const menu = win.document.getElementById(menuId);
   const shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
   EventUtils.synthesizeMouseAtCenter(node, {type: "contextmenu"}, win);
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -22,22 +22,24 @@ Cu.import("resource:///modules/Migration
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
                                   "resource://gre/modules/AsyncShutdown.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
                                   "resource://gre/modules/LoginHelper.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
+                                  "resource://gre/modules/NewTabUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
-                                  "resource://gre/modules/NewTabUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
+                                  "resource://gre/modules/TelemetryStopwatch.jsm");
 
 Cu.importGlobalProperties(["URL"]);
 
 /* globals kUndoStateFullPath */
 XPCOMUtils.defineLazyGetter(this, "kUndoStateFullPath", function() {
   return OS.Path.join(OS.Constants.Path.profileDir, "initialMigrationMetadata.jsonlz4");
 });
 
@@ -189,48 +191,85 @@ const AutoMigrate = {
       fileExists = yield OS.File.exists(kUndoStateFullPath);
     } catch (ex) {
       Cu.reportError(ex);
     }
     return fileExists;
   }),
 
   undo: Task.async(function* () {
+    let browserId = Preferences.get(kAutoMigrateBrowserPref, "unknown");
+    TelemetryStopwatch.startKeyed("FX_STARTUP_MIGRATION_UNDO_TOTAL_MS", browserId);
     let histogram = Services.telemetry.getHistogramById("FX_STARTUP_MIGRATION_AUTOMATED_IMPORT_UNDO");
     histogram.add(0);
     if (!(yield this.canUndo())) {
       histogram.add(5);
       throw new Error("Can't undo!");
     }
 
     this._pendingUndoTasks = true;
     this._removeNotificationBars();
     histogram.add(10);
 
     let readPromise = OS.File.read(kUndoStateFullPath, {
       encoding: "utf-8",
       compression: "lz4",
     });
     let stateData = this._dejsonifyUndoState(yield readPromise);
-    yield this._removeUnchangedBookmarks(stateData.get("bookmarks"));
+    histogram.add(12);
+
+    this._errorMap = {bookmarks: 0, visits: 0, logins: 0};
+    let reportErrorTelemetry = (type) => {
+      let histogramId = `FX_STARTUP_MIGRATION_UNDO_${type.toUpperCase()}_ERRORCOUNT`;
+      Services.telemetry.getKeyedHistogramById(histogramId).add(browserId, this._errorMap[type]);
+    };
+
+    let startTelemetryStopwatch = resourceType => {
+      let histogramId = `FX_STARTUP_MIGRATION_UNDO_${resourceType.toUpperCase()}_MS`;
+      TelemetryStopwatch.startKeyed(histogramId, browserId);
+    };
+    let stopTelemetryStopwatch = resourceType => {
+      let histogramId = `FX_STARTUP_MIGRATION_UNDO_${resourceType.toUpperCase()}_MS`;
+      TelemetryStopwatch.finishKeyed(histogramId, browserId);
+    };
+    startTelemetryStopwatch("bookmarks");
+    yield this._removeUnchangedBookmarks(stateData.get("bookmarks")).catch(ex => {
+      Cu.reportError("Uncaught exception when removing unchanged bookmarks!");
+      Cu.reportError(ex);
+    });
+    stopTelemetryStopwatch("bookmarks");
+    reportErrorTelemetry("bookmarks");
     histogram.add(15);
 
-    yield this._removeSomeVisits(stateData.get("visits"));
+    startTelemetryStopwatch("visits");
+    yield this._removeSomeVisits(stateData.get("visits")).catch(ex => {
+      Cu.reportError("Uncaught exception when removing history visits!");
+      Cu.reportError(ex);
+    });
+    stopTelemetryStopwatch("visits");
+    reportErrorTelemetry("visits");
     histogram.add(20);
 
-    yield this._removeUnchangedLogins(stateData.get("logins"));
+    startTelemetryStopwatch("logins");
+    yield this._removeUnchangedLogins(stateData.get("logins")).catch(ex => {
+      Cu.reportError("Uncaught exception when removing unchanged logins!");
+      Cu.reportError(ex);
+    });
+    stopTelemetryStopwatch("logins");
+    reportErrorTelemetry("logins");
     histogram.add(25);
 
     // This is async, but no need to wait for it.
     NewTabUtils.links.populateCache(() => {
       NewTabUtils.allPages.update();
     }, true);
 
     this._purgeUndoState(this.UNDO_REMOVED_REASON_UNDO_USED);
     histogram.add(30);
+    TelemetryStopwatch.finishKeyed("FX_STARTUP_MIGRATION_UNDO_TOTAL_MS", browserId);
   }),
 
   _removeNotificationBars() {
     let browserWindows = Services.wm.getEnumerator("navigator:browser");
     while (browserWindows.hasMoreElements()) {
       let win = browserWindows.getNext();
       if (!win.closed) {
         for (let browser of win.gBrowser.browsers) {
@@ -414,26 +453,31 @@ const AutoMigrate = {
       return;
     }
 
     let guidToLMMap = new Map(bookmarks.map(b => [b.guid, b.lastModified]));
     let bookmarksFromDB = [];
     let bmPromises = Array.from(guidToLMMap.keys()).map(guid => {
       // Ignore bookmarks where the promise doesn't resolve (ie that are missing)
       // Also check that the bookmark fetch returns isn't null before adding it.
-      return PlacesUtils.bookmarks.fetch(guid).then(bm => bm && bookmarksFromDB.push(bm), () => {});
+      try {
+        return PlacesUtils.bookmarks.fetch(guid).then(bm => bm && bookmarksFromDB.push(bm), () => {});
+      } catch (ex) {
+        // Ignore immediate exceptions, too.
+      }
+      return Promise.resolve();
     });
     // We can't use the result of Promise.all because that would include nulls
     // for bookmarks that no longer exist (which we're catching above).
     yield Promise.all(bmPromises);
     let unchangedBookmarks = bookmarksFromDB.filter(bm => {
       return bm.lastModified.getTime() == guidToLMMap.get(bm.guid).getTime();
     });
 
-    // We need to remove items with no ancestors first, followed by their
+    // We need to remove items without children first, followed by their
     // parents, etc. In order to do this, find out how many ancestors each item
     // has that also appear in our list of things to remove, and sort the items
     // by those numbers. This ensures that children are always removed before
     // their parents.
     function determineAncestorCount(bm) {
       if (bm._ancestorCount) {
         return bm._ancestorCount;
       }
@@ -443,36 +487,42 @@ const AutoMigrate = {
         myCount = determineAncestorCount(parentBM) + 1;
       }
       bm._ancestorCount = myCount;
       return myCount;
     }
     unchangedBookmarks.forEach(determineAncestorCount);
     unchangedBookmarks.sort((a, b) => b._ancestorCount - a._ancestorCount);
     for (let {guid} of unchangedBookmarks) {
-      yield PlacesUtils.bookmarks.remove(guid, {preventRemovalOfNonEmptyFolders: true}).catch(err => {
+      // Can't just use a .catch() because Bookmarks.remove() can throw (rather
+      // than returning rejected promises).
+      try {
+        yield PlacesUtils.bookmarks.remove(guid, {preventRemovalOfNonEmptyFolders: true});
+      } catch (err) {
         if (err && err.message != "Cannot remove a non-empty folder.") {
+          this._errorMap.bookmarks++;
           Cu.reportError(err);
         }
-      });
+      }
     }
   }),
 
   _removeUnchangedLogins: Task.async(function* (logins) {
     for (let login of logins) {
       let foundLogins = LoginHelper.searchLoginsWithObject({guid: login.guid});
       if (foundLogins.length) {
         let foundLogin = foundLogins[0];
         foundLogin.QueryInterface(Ci.nsILoginMetaInfo);
         if (foundLogin.timePasswordChanged == login.timePasswordChanged) {
           try {
             Services.logins.removeLogin(foundLogin);
           } catch (ex) {
             Cu.reportError("Failed to remove a login for " + foundLogins.hostname);
             Cu.reportError(ex);
+            this._errorMap.logins++;
           }
         }
       }
     }
   }),
 
   _removeSomeVisits: Task.async(function* (visits) {
     for (let urlVisits of visits) {
@@ -485,20 +535,21 @@ const AutoMigrate = {
       let visitData = {
         url: urlObj,
         beginDate: PlacesUtils.toDate(urlVisits.first),
         endDate: PlacesUtils.toDate(urlVisits.last),
         limit: urlVisits.visitCount,
       };
       try {
         yield PlacesUtils.history.removeVisitsByFilter(visitData);
-      } catch(ex) {
+      } catch (ex) {
+        this._errorMap.visits++;
         try {
           visitData.url = visitData.url.href;
-        } catch (ex) {}
+        } catch (ignoredEx) {}
         Cu.reportError("Failed to remove a visit: " + JSON.stringify(visitData));
         Cu.reportError(ex);
       }
     }
   }),
 
   QueryInterface: XPCOMUtils.generateQI(
     [Ci.nsIObserver, Ci.nsINavBookmarkObserver, Ci.nsISupportsWeakReference]
--- a/browser/components/migration/tests/unit/test_automigration.js
+++ b/browser/components/migration/tests/unit/test_automigration.js
@@ -183,16 +183,17 @@ add_task(function* checkUndoPrecondition
   Assert.ok(true, "Should be able to finish an undo cycle.");
 });
 
 /**
  * Fake a migration and then try to undo it to verify all data gets removed.
  */
 add_task(function* checkUndoRemoval() {
   MigrationUtils.initializeUndoData();
+  Preferences.set("browser.migrate.automigrate.browser", "automationbrowser");
   // Insert a login and check that that worked.
   MigrationUtils.insertLoginWrapper({
     hostname: "www.mozilla.org",
     formSubmitURL: "http://www.mozilla.org",
     username: "user",
     password: "pass",
   });
   let storedLogins = Services.logins.findLogins({}, "www.mozilla.org",
@@ -252,16 +253,38 @@ add_task(function* checkUndoRemoval() {
   visits.root.containerOpen = false;
 
   yield AutoMigrate.saveUndoState();
 
   // Verify that we can undo, then undo:
   Assert.ok(AutoMigrate.canUndo(), "Should be possible to undo migration");
   yield AutoMigrate.undo();
 
+  let histograms = [
+    "FX_STARTUP_MIGRATION_UNDO_BOOKMARKS_ERRORCOUNT",
+    "FX_STARTUP_MIGRATION_UNDO_LOGINS_ERRORCOUNT",
+    "FX_STARTUP_MIGRATION_UNDO_VISITS_ERRORCOUNT",
+  ];
+  for (let histogramId of histograms) {
+    let keyedHistogram = Services.telemetry.getKeyedHistogramById(histogramId);
+    let histogramData = keyedHistogram.snapshot().automationbrowser;
+    Assert.equal(histogramData.sum, 0, `Should have reported 0 errors to ${histogramId}.`);
+    Assert.greaterOrEqual(histogramData.counts[0], 1, `Should have reported value of 0 one time to ${histogramId}.`);
+  }
+  histograms = [
+    "FX_STARTUP_MIGRATION_UNDO_BOOKMARKS_MS",
+    "FX_STARTUP_MIGRATION_UNDO_LOGINS_MS",
+    "FX_STARTUP_MIGRATION_UNDO_VISITS_MS",
+    "FX_STARTUP_MIGRATION_UNDO_TOTAL_MS",
+  ];
+  for (let histogramId of histograms) {
+    Assert.greater(Services.telemetry.getKeyedHistogramById(histogramId).snapshot().automationbrowser.sum, 0,
+                   `Should have reported non-zero time spent using undo for ${histogramId}`);
+  }
+
   // Check that the undo removed the history visits:
   visits = PlacesUtils.history.executeQuery(query, opts);
   visits.root.containerOpen = true;
   Assert.equal(visits.root.childCount, 0, "Should have no more visits");
   visits.root.containerOpen = false;
 
   // Check that the undo removed the bookmarks:
   bookmark = yield PlacesUtils.bookmarks.fetch({url: "http://www.example.org/"});
@@ -607,11 +630,32 @@ add_task(function* checkUndoVisitsState(
   Assert.equal(yield visitsForURL("http://www.example.org/"), 2,
                "2 example.org visits should have persisted (out of 4).");
   Assert.equal(yield visitsForURL("http://www.unrelated.org/"), 1,
                "1 unrelated.org visits should have persisted as it's not involved in the import.");
   yield PlacesTestUtils.clearHistory();
 });
 
 add_task(function* checkHistoryRemovalCompletion() {
+  AutoMigrate._errorMap = {bookmarks: 0, visits: 0, logins: 0};
   yield AutoMigrate._removeSomeVisits([{url: "http://www.example.com/", limit: -1}]);
   ok(true, "Removing visits should complete even if removing some visits failed.");
+  Assert.equal(AutoMigrate._errorMap.visits, 1, "Should have logged the error for visits.");
+
+  // Unfortunately there's not a reliable way to make removing bookmarks be
+  // unhappy unless the DB is messed up (e.g. contains children but has
+  // parents removed already).
+  yield AutoMigrate._removeUnchangedBookmarks([
+    {guid: PlacesUtils.bookmarks, lastModified: new Date(0), parentGuid: 0},
+    {guid: "gobbledygook", lastModified: new Date(0), parentGuid: 0},
+  ]);
+  ok(true, "Removing bookmarks should complete even if some items are gone or bogus.");
+  Assert.equal(AutoMigrate._errorMap.bookmarks, 0,
+               "Should have ignored removing non-existing (or builtin) bookmark.");
+
+
+  yield AutoMigrate._removeUnchangedLogins([
+    {guid: "gobbledygook", timePasswordChanged: new Date(0)},
+  ]);
+  ok(true, "Removing logins should complete even if logins don't exist.");
+  Assert.equal(AutoMigrate._errorMap.logins, 0,
+               "Should have ignored removing non-existing logins.");
 });
--- a/devtools/client/framework/connect/connect.css
+++ b/devtools/client/framework/connect/connect.css
@@ -37,17 +37,21 @@ label {
 label > span {
   display: inline-block;
   min-width: 150px;
   text-align: end;
   margin-inline-end: 10px;
 }
 
 #submit {
-  float: inline-end;
+  float: right;
+}
+
+#submit:dir(rtl) {
+  float: left;
 }
 
 input {
   direction: ltr;
 }
 
 input:invalid {
   box-shadow: 0 0 2px 2px #F06;
--- a/devtools/client/framework/options-panel.css
+++ b/devtools/client/framework/options-panel.css
@@ -10,17 +10,21 @@
 }
 
 #options-panel {
   display: block;
 }
 
 .options-vertical-pane {
   display: inline;
-  float: inline-start;
+  float: left;
+}
+
+.options-vertical-pane:dir(rtl) {
+  float: right;
 }
 
 .options-vertical-pane {
   margin: 5px;
   width: calc(100%/3 - 10px);
   min-width: 320px;
   padding-inline-start: 5px;
   box-sizing: border-box;
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -80,16 +80,9 @@ extern "C" {
     return GMPGenericErr;
   }
 
   PUBLIC_FUNC void
   GMPShutdown (void) {
     g_platform_api = NULL;
   }
 
-#if defined(GMP_FAKE_SUPPORT_DECRYPT)
-  PUBLIC_FUNC void
-  GMPSetNodeId(const char* aNodeId, uint32_t aLength) {
-    FakeDecryptor::SetNodeId(aNodeId, aLength);
-  }
-#endif
-
 } // extern "C"
--- a/dom/media/gmp-plugin/gmp-test-decryptor.cpp
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.cpp
@@ -15,18 +15,16 @@
 #include <sstream>
 #include <set>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 using namespace std;
 
-std::string FakeDecryptor::sNodeId;
-
 FakeDecryptor* FakeDecryptor::sInstance = nullptr;
 extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
 
 class GMPMutexAutoLock
 {
 public:
   explicit GMPMutexAutoLock(GMPMutex* aMutex) : mMutex(aMutex) {
     mMutex->Acquire();
@@ -471,55 +469,16 @@ public:
     } else {
       FakeDecryptor::Message("retrieved " + mRecordId + " " + aData);
     }
     delete this;
   }
   string mRecordId;
 };
 
-static void
-RecvGMPRecordIterator(GMPRecordIterator* aRecordIterator,
-                      void* aUserArg,
-                      GMPErr aStatus)
-{
-  FakeDecryptor* decryptor = reinterpret_cast<FakeDecryptor*>(aUserArg);
-  decryptor->ProcessRecordNames(aRecordIterator, aStatus);
-}
-
-void
-FakeDecryptor::ProcessRecordNames(GMPRecordIterator* aRecordIterator,
-                                  GMPErr aStatus)
-{
-  if (sInstance != this) {
-    FakeDecryptor::Message("Error aUserArg was not passed through GetRecordIterator");
-    return;
-  }
-  if (GMP_FAILED(aStatus)) {
-    FakeDecryptor::Message("Error GetRecordIterator failed");
-    return;
-  }
-  std::string response("record-names ");
-  bool first = true;
-  const char* name = nullptr;
-  uint32_t len = 0;
-  while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) {
-    std::string s(name, name+len);
-    if (!first) {
-      response += ",";
-    } else {
-      first = false;
-    }
-    response += s;
-    aRecordIterator->NextRecord();
-  }
-  aRecordIterator->Close();
-  FakeDecryptor::Message(response);
-}
-
 enum ShutdownMode {
   ShutdownNormal,
   ShutdownTimeout,
   ShutdownStoreToken
 };
 
 static ShutdownMode sShutdownMode = ShutdownNormal;
 static string sShutdownToken = "";
@@ -555,14 +514,10 @@ FakeDecryptor::UpdateSession(uint32_t aP
       sShutdownMode = ShutdownStoreToken;
       sShutdownToken = tokens[2];
       Message("shutdown-token received " + sShutdownToken);
     }
   } else if (task == "retrieve-shutdown-token") {
     ReadRecord("shutdown-token", new ReportReadRecordContinuation("shutdown-token"));
   } else if (task == "test-op-apis") {
     mozilla::gmptest::TestOuputProtectionAPIs();
-  } else if (task == "retrieve-record-names") {
-    GMPEnumRecordNames(&RecvGMPRecordIterator, this);
-  } else if (task == "retrieve-node-id") {
-    Message("node-id " + sNodeId);
   }
 }
--- a/dom/media/gmp-plugin/gmp-test-decryptor.h
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.h
@@ -66,27 +66,19 @@ public:
                GMPEncryptedBufferMetadata* aMetadata) override
   {
   }
 
   void DecryptingComplete() override;
 
   static void Message(const std::string& aMessage);
 
-  void ProcessRecordNames(GMPRecordIterator* aRecordIterator,
-                          GMPErr aStatus);
-
-  static void SetNodeId(const char* aNodeId, uint32_t aLength) {
-    sNodeId = std::string(aNodeId, aNodeId + aLength);
-  }
-
 private:
 
   virtual ~FakeDecryptor() {}
   static FakeDecryptor* sInstance;
-  static std::string sNodeId;
 
   void TestStorage();
 
   GMPDecryptorCallback* mCallback;
 };
 
 #endif
--- a/dom/media/gmp-plugin/gmp-test-storage.cpp
+++ b/dom/media/gmp-plugin/gmp-test-storage.cpp
@@ -219,15 +219,8 @@ private:
 };
 
 void
 GMPOpenRecord(const std::string& aRecordName,
               OpenContinuation* aContinuation)
 {
   OpenRecordClient::Open(aRecordName, aContinuation);
 }
-
-GMPErr
-GMPEnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                   void* aUserArg)
-{
-  return g_platform_api->getrecordenumerator(aRecvIteratorFunc, aUserArg);
-}
--- a/dom/media/gmp-plugin/gmp-test-storage.h
+++ b/dom/media/gmp-plugin/gmp-test-storage.h
@@ -51,13 +51,9 @@ public:
   virtual ~OpenContinuation() {}
   virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) = 0;
 };
 
 void
 GMPOpenRecord(const std::string& aRecordName,
               OpenContinuation* aContinuation);
 
-GMPErr
-GMPEnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                   void* aUserArg);
-
 #endif // TEST_GMP_STORAGE_H__
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -249,28 +249,16 @@ GMPChild::Init(const nsAString& aPluginP
   SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
 #endif
 
   mPluginPath = aPluginPath;
 
   return true;
 }
 
-mozilla::ipc::IPCResult
-GMPChild::RecvSetNodeId(const nsCString& aNodeId)
-{
-  LOGD("%s nodeId=%s", __FUNCTION__, aNodeId.Data());
-
-  // Store the per origin salt for the node id. Note: we do this in a
-  // separate message than RecvStartPlugin() so that the string is not
-  // sitting in a string on the IPC code's call stack.
-  mNodeId = aNodeId;
-  return IPC_OK();
-}
-
 GMPErr
 GMPChild::GetAPI(const char* aAPIName,
                  void* aHostAPI,
                  void** aPluginAPI,
                  uint32_t aDecryptorId)
 {
   if (!mGMPLoader) {
     return GMPGenericErr;
@@ -344,22 +332,24 @@ GMPChild::AnswerStartPlugin(const nsStri
   nsCString libPath;
   if (!GetUTF8LibPath(libPath)) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   auto platformAPI = new GMPPlatformAPI();
   InitPlatformAPI(*platformAPI, this);
 
-  mGMPLoader = GMPProcessChild::GetGMPLoader();
-  if (!mGMPLoader) {
-    NS_WARNING("Failed to get GMPLoader");
+  mGMPLoader = MakeUnique<GMPLoader>();
+#if defined(MOZ_GMP_SANDBOX)
+  if (!mGMPLoader->CanSandbox()) {
+    LOGD("%s Can't sandbox GMP, failing", __FUNCTION__);
     delete platformAPI;
     return IPC_FAIL_NO_REASON(this);
   }
+#endif
 
   bool isWidevine = aAdapter.EqualsLiteral("widevine");
 #if defined(MOZ_GMP_SANDBOX) && defined(XP_MACOSX)
   MacSandboxPluginType pluginType = MacSandboxPluginType_GMPlugin_Default;
   if (isWidevine) {
     pluginType = MacSandboxPluginType_GMPlugin_EME_Widevine;
   }
   if (!SetMacSandboxInfo(pluginType)) {
@@ -367,18 +357,16 @@ GMPChild::AnswerStartPlugin(const nsStri
     delete platformAPI;
     return IPC_FAIL_NO_REASON(this);
   }
 #endif
 
   GMPAdapter* adapter = (isWidevine) ? new WidevineAdapter() : nullptr;
   if (!mGMPLoader->Load(libPath.get(),
                         libPath.Length(),
-                        mNodeId.BeginWriting(),
-                        mNodeId.Length(),
                         platformAPI,
                         adapter)) {
     NS_WARNING("Failed to load GMP");
     delete platformAPI;
     return IPC_FAIL_NO_REASON(this);
   }
 
   return IPC_OK();
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -38,17 +38,16 @@ public:
   bool SetMacSandboxInfo(MacSandboxPluginType aPluginType);
 #endif
 
 private:
   friend class GMPContentChild;
 
   bool GetUTF8LibPath(nsACString& aOutLibPath);
 
-  mozilla::ipc::IPCResult RecvSetNodeId(const nsCString& aNodeId) override;
   mozilla::ipc::IPCResult AnswerStartPlugin(const nsString& aAdapter) override;
   mozilla::ipc::IPCResult RecvPreloadLibs(const nsCString& aLibs) override;
 
   PCrashReporterChild* AllocPCrashReporterChild(const NativeThreadId& aThread) override;
   bool DeallocPCrashReporterChild(PCrashReporterChild*) override;
 
   PGMPTimerChild* AllocPGMPTimerChild() override;
   bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) override;
@@ -70,16 +69,15 @@ private:
 
   nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
 
   RefPtr<GMPTimerChild> mTimerChild;
   RefPtr<GMPStorageChild> mStorage;
 
   MessageLoop* mGMPMessageLoop;
   nsString mPluginPath;
-  nsCString mNodeId;
-  GMPLoader* mGMPLoader;
+  UniquePtr<GMPLoader> mGMPLoader;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPChild_h_
--- a/dom/media/gmp/GMPDiskStorage.cpp
+++ b/dom/media/gmp/GMPDiskStorage.cpp
@@ -297,24 +297,16 @@ public:
 
     // Try to sync the file to disk, so that in the event of a crash,
     // the record is less likely to be corrupted.
     PR_Sync(record->mFileDesc);
 
     return GMPNoErr;
   }
 
-  GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) const override
-  {
-    for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) {
-      aOutRecordNames.AppendElement(iter.UserData()->mRecordName);
-    }
-    return GMPNoErr;
-  }
-
   void Close(const nsCString& aRecordName) override
   {
     Record* record = nullptr;
     mRecords.Get(aRecordName, &record);
     if (record && !!record->mFileDesc) {
       PR_Close(record->mFileDesc);
       record->mFileDesc = nullptr;
     }
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -5,63 +5,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPLoader.h"
 #include <stdio.h>
 #include "mozilla/Attributes.h"
 #include "gmp-entrypoints.h"
 #include "prlink.h"
 #include "prenv.h"
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+#include "mozilla/sandboxTarget.h"
+#include "mozilla/sandboxing/SandboxInitialization.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+#endif
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+#include "mozilla/Sandbox.h"
+#include "mozilla/SandboxInfo.h"
+#endif
 
 #include <string>
 
 #ifdef XP_WIN
 #include "windows.h"
 #endif
 
-#include "GMPDeviceBinding.h"
-
 namespace mozilla {
 namespace gmp {
-
-class GMPLoaderImpl : public GMPLoader {
-public:
-  explicit GMPLoaderImpl(UniquePtr<SandboxStarter> aStarter)
-    : mSandboxStarter(Move(aStarter))
-    , mAdapter(nullptr)
-  {}
-  ~GMPLoaderImpl() override = default;
-
-  bool Load(const char* aUTF8LibPath,
-            uint32_t aUTF8LibPathLen,
-            char* aOriginSalt,
-            uint32_t aOriginSaltLen,
-            const GMPPlatformAPI* aPlatformAPI,
-            GMPAdapter* aAdapter) override;
-
-  GMPErr GetAPI(const char* aAPIName,
-                void* aHostAPI,
-                void** aPluginAPI,
-                uint32_t aDecryptorId) override;
-
-  void Shutdown() override;
-
-#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-  void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override;
-#endif
-
-private:
-  UniquePtr<SandboxStarter> mSandboxStarter;
-  UniquePtr<GMPAdapter> mAdapter;
-};
-
-UniquePtr<GMPLoader> CreateGMPLoader(UniquePtr<SandboxStarter> aStarter) {
-  return MakeUnique<GMPLoaderImpl>(Move(aStarter));
-}
-
 class PassThroughGMPAdapter : public GMPAdapter {
 public:
   ~PassThroughGMPAdapter() override {
     // Ensure we're always shutdown, even if caller forgets to call GMPShutdown().
     GMPShutdown();
   }
 
   void SetAdaptee(PRLibrary* aLib) override
@@ -103,47 +74,26 @@ public:
       if (shutdownFunc) {
         shutdownFunc();
       }
       PR_UnloadLibrary(mLib);
       mLib = nullptr;
     }
   }
 
-  void GMPSetNodeId(const char* aNodeId, uint32_t aLength) override
-  {
-    if (!mLib) {
-      return;
-    }
-    GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId"));
-    if (setNodeIdFunc) {
-      setNodeIdFunc(aNodeId, aLength);
-    }
-  }
-
 private:
   PRLibrary* mLib = nullptr;
 };
 
 bool
-GMPLoaderImpl::Load(const char* aUTF8LibPath,
-                    uint32_t aUTF8LibPathLen,
-                    char* aOriginSalt,
-                    uint32_t aOriginSaltLen,
-                    const GMPPlatformAPI* aPlatformAPI,
-                    GMPAdapter* aAdapter)
+GMPLoader::Load(const char* aUTF8LibPath,
+                uint32_t aUTF8LibPathLen,
+                const GMPPlatformAPI* aPlatformAPI,
+                GMPAdapter* aAdapter)
 {
-  std::string nodeId;
-  if (!CalculateGMPDeviceId(aOriginSalt, aOriginSaltLen, nodeId)) {
-    return false;
-  }
-
-  // Start the sandbox now that we've generated the device bound node id.
-  // This must happen after the node id is bound to the device id, as
-  // generating the device id requires privileges.
   if (mSandboxStarter && !mSandboxStarter->Start(aUTF8LibPath)) {
     return false;
   }
 
   // Load the GMP.
   PRLibSpec libSpec;
 #ifdef XP_WIN
   int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0);
@@ -162,61 +112,135 @@ GMPLoaderImpl::Load(const char* aUTF8Lib
   libSpec.value.pathname = aUTF8LibPath;
   libSpec.type = PR_LibSpec_Pathname;
 #endif
   PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, 0);
   if (!lib) {
     return false;
   }
 
-  GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(lib, "GMPInit"));
-  if ((initFunc && aAdapter) ||
-      (!initFunc && !aAdapter)) {
-    // Ensure that if we're dealing with a GMP we do *not* use an adapter
-    // provided from the outside world. This is important as it means we
-    // don't call code not covered by Adobe's plugin-container voucher
-    // before we pass the node Id to Adobe's GMP.
-    return false;
-  }
-
-  // Note: PassThroughGMPAdapter's code must remain in this file so that it's
-  // covered by Adobe's plugin-container voucher.
   mAdapter.reset((!aAdapter) ? new PassThroughGMPAdapter() : aAdapter);
   mAdapter->SetAdaptee(lib);
 
   if (mAdapter->GMPInit(aPlatformAPI) != GMPNoErr) {
     return false;
   }
 
-  mAdapter->GMPSetNodeId(nodeId.c_str(), nodeId.size());
-
   return true;
 }
 
 GMPErr
-GMPLoaderImpl::GetAPI(const char* aAPIName,
-                      void* aHostAPI,
-                      void** aPluginAPI,
-                      uint32_t aDecryptorId)
+GMPLoader::GetAPI(const char* aAPIName,
+                  void* aHostAPI,
+                  void** aPluginAPI,
+                  uint32_t aDecryptorId)
 {
   return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
 }
 
 void
-GMPLoaderImpl::Shutdown()
+GMPLoader::Shutdown()
 {
   if (mAdapter) {
     mAdapter->GMPShutdown();
   }
 }
 
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
 void
-GMPLoaderImpl::SetSandboxInfo(MacSandboxInfo* aSandboxInfo)
+GMPLoader::SetSandboxInfo(MacSandboxInfo* aSandboxInfo)
 {
   if (mSandboxStarter) {
     mSandboxStarter->SetSandboxInfo(aSandboxInfo);
   }
 }
 #endif
+
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+class WinSandboxStarter : public mozilla::gmp::SandboxStarter
+{
+public:
+  bool Start(const char *aLibPath) override
+  {
+    mozilla::SandboxTarget::Instance()->StartSandbox();
+    return true;
+  }
+};
+#endif
+
+#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
+class MacSandboxStarter : public mozilla::gmp::SandboxStarter
+{
+public:
+  bool Start(const char *aLibPath) override
+  {
+    std::string err;
+    bool rv = mozilla::StartMacSandbox(mInfo, err);
+    if (!rv) {
+      fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
+    }
+    return rv;
+  }
+  void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override
+  {
+    mInfo = *aSandboxInfo;
+  }
+private:
+  MacSandboxInfo mInfo;
+};
+#endif
+
+#if defined (XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+namespace {
+class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter
+{
+private:
+  LinuxSandboxStarter() { }
+  friend mozilla::detail::UniqueSelector<LinuxSandboxStarter>::SingleObject mozilla::MakeUnique<LinuxSandboxStarter>();
+
+public:
+  static UniquePtr<SandboxStarter> Make()
+  {
+    if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
+      return MakeUnique<LinuxSandboxStarter>();
+    } else {
+      // Sandboxing isn't possible, but the parent has already
+      // checked that this plugin doesn't require it.  (Bug 1074561)
+      return nullptr;
+    }
+    return nullptr;
+  }
+  bool Start(const char *aLibPath) override
+  {
+    mozilla::SetMediaPluginSandbox(aLibPath);
+    return true;
+  }
+};
+} // anonymous namespace
+#endif // XP_LINUX && MOZ_GMP_SANDBOX
+
+static UniquePtr<SandboxStarter>
+MakeSandboxStarter()
+{
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  return mozilla::MakeUnique<WinSandboxStarter>();
+#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
+  return mozilla::MakeUnique<MacSandboxStarter>();
+#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+  return LinuxSandboxStarter::Make();
+#else
+  return nullptr;
+#endif
+}
+
+GMPLoader::GMPLoader()
+  : mSandboxStarter(MakeSandboxStarter())
+{
+}
+
+bool
+GMPLoader::CanSandbox() const
+{
+  return !!mSandboxStarter;
+}
+
 } // namespace gmp
 } // namespace mozilla
-
--- a/dom/media/gmp/GMPLoader.h
+++ b/dom/media/gmp/GMPLoader.h
@@ -42,72 +42,54 @@ public:
 
   // These are called in place of the corresponding GMP API functions.
   virtual GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) = 0;
   virtual GMPErr GMPGetAPI(const char* aAPIName,
                            void* aHostAPI,
                            void** aPluginAPI,
                            uint32_t aDecryptorId) = 0;
   virtual void GMPShutdown() = 0;
-  virtual void GMPSetNodeId(const char* aNodeId, uint32_t aLength) = 0;
 };
 
-// Encapsulates generating the device-bound node id, activating the sandbox,
-// loading the GMP, and passing the node id to the GMP (in that order).
-//
-// In Desktop Gecko, the implementation of this lives in plugin-container,
-// and is passed into XUL code from on startup. The GMP IPC child protocol actor
-// uses this interface to load and retrieve interfaces from the GMPs.
-//
-// In Desktop Gecko the implementation lives in the plugin-container so that
-// it can be covered by DRM vendor's voucher.
-//
-// On Android the GMPLoader implementation lives in libxul (because for the time
-// being GMPLoader relies upon NSPR, which we can't use in plugin-container
-// on Android).
-//
-// There is exactly one GMPLoader per GMP child process, and only one GMP
-// per child process (so the GMPLoader only loads one GMP).
-//
+// Encapsulates activating the sandbox, and loading the GMP.
 // Load() takes an optional GMPAdapter which can be used to adapt non-GMPs
 // to adhere to the GMP API.
 class GMPLoader {
 public:
-  virtual ~GMPLoader() {}
+  GMPLoader();
 
-  // Calculates the device-bound node id, then activates the sandbox,
-  // then loads the GMP library and (if applicable) passes the bound node id
-  // to the GMP. If aAdapter is non-null, the lib path is assumed to be
-  // a non-GMP, and the adapter is initialized with the lib and the adapter
-  // is used to interact with the plugin.
-  virtual bool Load(const char* aUTF8LibPath,
-                    uint32_t aLibPathLen,
-                    char* aOriginSalt,
-                    uint32_t aOriginSaltLen,
-                    const GMPPlatformAPI* aPlatformAPI,
-                    GMPAdapter* aAdapter = nullptr) = 0;
+  // Activates the sandbox, then loads the GMP library. If aAdapter is
+  // non-null, the lib path is assumed to be a non-GMP, and the adapter
+  // is initialized with the lib and the adapter is used to interact with
+  // the plugin.
+  bool Load(const char* aUTF8LibPath,
+            uint32_t aLibPathLen,
+            const GMPPlatformAPI* aPlatformAPI,
+            GMPAdapter* aAdapter = nullptr);
 
   // Retrieves an interface pointer from the GMP.
-  virtual GMPErr GetAPI(const char* aAPIName,
-                        void* aHostAPI,
-                        void** aPluginAPI,
-                        uint32_t aDecryptorId) = 0;
+  GMPErr GetAPI(const char* aAPIName,
+                void* aHostAPI,
+                void** aPluginAPI,
+                uint32_t aDecryptorId);
 
   // Calls the GMPShutdown function exported by the GMP lib, and unloads the
   // plugin library.
-  virtual void Shutdown() = 0;
+  void Shutdown();
 
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   // On OS X we need to set Mac-specific sandbox info just before we start the
   // sandbox, which we don't yet know when the GMPLoader and SandboxStarter
   // objects are created.
-  virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) = 0;
+  void SetSandboxInfo(MacSandboxInfo* aSandboxInfo);
 #endif
-};
+
+  bool CanSandbox() const;
 
-// On Desktop, this function resides in plugin-container.
-// On Mobile, this function resides in XUL.
-UniquePtr<GMPLoader> CreateGMPLoader(UniquePtr<SandboxStarter> aStarter);
+private:
+  UniquePtr<SandboxStarter> mSandboxStarter;
+  UniquePtr<GMPAdapter> mAdapter;
+};
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMP_LOADER_H__
--- a/dom/media/gmp/GMPMemoryStorage.cpp
+++ b/dom/media/gmp/GMPMemoryStorage.cpp
@@ -49,24 +49,16 @@ public:
     Record* record = nullptr;
     if (!mRecords.Get(aRecordName, &record)) {
       return GMPClosedErr;
     }
     record->mData = aBytes;
     return GMPNoErr;
   }
 
-  GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) const override
-  {
-    for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) {
-      aOutRecordNames.AppendElement(iter.Key());
-    }
-    return GMPNoErr;
-  }
-
   void Close(const nsCString& aRecordName) override
   {
     Record* record = nullptr;
     if (!mRecords.Get(aRecordName, &record)) {
       return;
     }
     if (!record->mData.Length()) {
       // Record is empty, delete.
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -172,37 +172,29 @@ GMPParent::LoadProcess()
     if (!opened) {
       LOGD("%s: Failed to open channel to new child process", __FUNCTION__);
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
     LOGD("%s: Opened channel to new child process", __FUNCTION__);
 
-    bool ok = SendSetNodeId(mNodeId);
-    if (!ok) {
-      LOGD("%s: Failed to send node id to child process", __FUNCTION__);
-      return NS_ERROR_FAILURE;
-    }
-    LOGD("%s: Sent node id to child process", __FUNCTION__);
-
 #ifdef XP_WIN
     if (!mLibs.IsEmpty()) {
       bool ok = SendPreloadLibs(mLibs);
       if (!ok) {
         LOGD("%s: Failed to send preload-libs to child process", __FUNCTION__);
         return NS_ERROR_FAILURE;
       }
       LOGD("%s: Sent preload-libs ('%s') to child process", __FUNCTION__, mLibs.get());
     }
 #endif
 
     // Intr call to block initialization on plugin load.
-    ok = CallStartPlugin(mAdapter);
-    if (!ok) {
+    if (!CallStartPlugin(mAdapter)) {
       LOGD("%s: Failed to send start to child process", __FUNCTION__);
       return NS_ERROR_FAILURE;
     }
     LOGD("%s: Sent StartPlugin to child process", __FUNCTION__);
   }
 
   mState = GMPStateLoaded;
 
--- a/dom/media/gmp/GMPPlatform.cpp
+++ b/dom/media/gmp/GMPPlatform.cpp
@@ -185,31 +185,16 @@ SetTimerOnMainThread(GMPTask* aTask, int
 
 GMPErr
 GetClock(GMPTimestamp* aOutTime)
 {
   *aOutTime = time(0) * 1000;
   return GMPNoErr;
 }
 
-GMPErr
-CreateRecordIterator(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                     void* aUserArg)
-{
-  if (!aRecvIteratorFunc) {
-    return GMPInvalidArgErr;
-  }
-  GMPStorageChild* storage = sChild->GetGMPStorage();
-  if (!storage) {
-    return GMPGenericErr;
-  }
-  MOZ_ASSERT(storage);
-  return storage->EnumerateRecords(aRecvIteratorFunc, aUserArg);
-}
-
 void
 InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
 {
   if (!sMainLoop) {
     sMainLoop = MessageLoop::current();
   }
   if (!sChild) {
     sChild = aChild;
@@ -218,17 +203,16 @@ InitPlatformAPI(GMPPlatformAPI& aPlatfor
   aPlatformAPI.version = 0;
   aPlatformAPI.createthread = &CreateThread;
   aPlatformAPI.runonmainthread = &RunOnMainThread;
   aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
   aPlatformAPI.createmutex = &CreateMutex;
   aPlatformAPI.createrecord = &CreateRecord;
   aPlatformAPI.settimer = &SetTimerOnMainThread;
   aPlatformAPI.getcurrenttime = &GetClock;
-  aPlatformAPI.getrecordenumerator = &CreateRecordIterator;
 }
 
 GMPThreadImpl::GMPThreadImpl()
 : mMutex("GMPThreadImpl"),
   mThread("GMPThread")
 {
   MOZ_COUNT_CTOR(GMPThread);
 }
--- a/dom/media/gmp/GMPProcessChild.cpp
+++ b/dom/media/gmp/GMPProcessChild.cpp
@@ -53,26 +53,10 @@ GMPProcessChild::Init()
 }
 
 void
 GMPProcessChild::CleanUp()
 {
   BackgroundHangMonitor::Shutdown();
 }
 
-GMPLoader* GMPProcessChild::mLoader = nullptr;
-
-/* static */
-void
-GMPProcessChild::SetGMPLoader(GMPLoader* aLoader)
-{
-  mLoader = aLoader;
-}
-
-/* static */
-GMPLoader*
-GMPProcessChild::GetGMPLoader()
-{
-  return mLoader;
-}
-
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPProcessChild.h
+++ b/dom/media/gmp/GMPProcessChild.h
@@ -20,24 +20,17 @@ protected:
 
 public:
   explicit GMPProcessChild(ProcessId aParentPid);
   ~GMPProcessChild();
 
   bool Init() override;
   void CleanUp() override;
 
-  // Set/get the GMPLoader singleton for this child process.
-  // Note: The GMPLoader is not deleted by this object, the caller of
-  // SetGMPLoader() must manage the GMPLoader's lifecycle.
-  static void SetGMPLoader(GMPLoader* aHost);
-  static GMPLoader* GetGMPLoader();
-
 private:
   GMPChild mPlugin;
-  static GMPLoader* mLoader;
   DISALLOW_COPY_AND_ASSIGN(GMPProcessChild);
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPProcessChild_h_
--- a/dom/media/gmp/GMPStorage.h
+++ b/dom/media/gmp/GMPStorage.h
@@ -20,17 +20,16 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPStorage)
 
   virtual GMPErr Open(const nsCString& aRecordName) = 0;
   virtual bool IsOpen(const nsCString& aRecordName) const = 0;
   virtual GMPErr Read(const nsCString& aRecordName,
                       nsTArray<uint8_t>& aOutBytes) = 0;
   virtual GMPErr Write(const nsCString& aRecordName,
                        const nsTArray<uint8_t>& aBytes) = 0;
-  virtual GMPErr GetRecordNames(nsTArray<nsCString>& aOutRecordNames) const = 0;
   virtual void Close(const nsCString& aRecordName) = 0;
 protected:
   virtual ~GMPStorage() {}
 };
 
 already_AddRefed<GMPStorage> CreateGMPMemoryStorage();
 already_AddRefed<GMPStorage> CreateGMPDiskStorage(const nsCString& aNodeId,
                                                   const nsString& aGMPName);
--- a/dom/media/gmp/GMPStorageChild.cpp
+++ b/dom/media/gmp/GMPStorageChild.cpp
@@ -273,107 +273,24 @@ GMPStorageChild::RecvWriteComplete(const
   if (!record) {
     // Not fatal.
     return IPC_OK();
   }
   record->WriteComplete(aStatus);
   return IPC_OK();
 }
 
-GMPErr
-GMPStorageChild::EnumerateRecords(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                                  void* aUserArg)
-{
-  MonitorAutoLock lock(mMonitor);
-
-  if (mShutdown) {
-    NS_WARNING("GMPStorage used after it's been shutdown!");
-    return GMPClosedErr;
-  }
-
-  MOZ_ASSERT(aRecvIteratorFunc);
-  mPendingRecordIterators.push(RecordIteratorContext(aRecvIteratorFunc, aUserArg));
-
-  CALL_ON_GMP_THREAD(SendGetRecordNames);
-
-  return GMPNoErr;
-}
-
-class GMPRecordIteratorImpl : public GMPRecordIterator {
-public:
-  explicit GMPRecordIteratorImpl(const InfallibleTArray<nsCString>& aRecordNames)
-    : mRecordNames(aRecordNames)
-    , mIndex(0)
-  {
-    mRecordNames.Sort();
-  }
-
-  GMPErr GetName(const char** aOutName, uint32_t* aOutNameLength) override {
-    if (!aOutName || !aOutNameLength) {
-      return GMPInvalidArgErr;
-    }
-    if (mIndex == mRecordNames.Length()) {
-      return GMPEndOfEnumeration;
-    }
-    *aOutName = mRecordNames[mIndex].get();
-    *aOutNameLength = mRecordNames[mIndex].Length();
-    return GMPNoErr;
-  }
-
-  GMPErr NextRecord() override {
-    if (mIndex < mRecordNames.Length()) {
-      mIndex++;
-    }
-    return (mIndex < mRecordNames.Length()) ? GMPNoErr
-                                            : GMPEndOfEnumeration;
-  }
-
-  void Close() override {
-    delete this;
-  }
-
-private:
-  nsTArray<nsCString> mRecordNames;
-  size_t mIndex;
-};
-
-mozilla::ipc::IPCResult
-GMPStorageChild::RecvRecordNames(InfallibleTArray<nsCString>&& aRecordNames,
-                                 const GMPErr& aStatus)
-{
-  RecordIteratorContext ctx;
-  {
-    MonitorAutoLock lock(mMonitor);
-    if (mShutdown || mPendingRecordIterators.empty()) {
-      return IPC_OK();
-    }
-    ctx = mPendingRecordIterators.front();
-    mPendingRecordIterators.pop();
-  }
-
-  if (GMP_FAILED(aStatus)) {
-    ctx.mFunc(nullptr, ctx.mUserArg, aStatus);
-  } else {
-    ctx.mFunc(new GMPRecordIteratorImpl(aRecordNames), ctx.mUserArg, GMPNoErr);
-  }
-
-  return IPC_OK();
-}
-
 mozilla::ipc::IPCResult
 GMPStorageChild::RecvShutdown()
 {
   // Block any new storage requests, and thus any messages back to the
   // parent. We don't delete any objects here, as that may invalidate
   // GMPRecord pointers held by the GMP.
   MonitorAutoLock lock(mMonitor);
   mShutdown = true;
-  while (!mPendingRecordIterators.empty()) {
-    mPendingRecordIterators.pop();
-  }
   return IPC_OK();
 }
 
 } // namespace gmp
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef ON_GMP_THREAD
--- a/dom/media/gmp/GMPStorageChild.h
+++ b/dom/media/gmp/GMPStorageChild.h
@@ -65,54 +65,36 @@ public:
   GMPErr Read(GMPRecordImpl* aRecord);
 
   GMPErr Write(GMPRecordImpl* aRecord,
                const uint8_t* aData,
                uint32_t aDataSize);
 
   GMPErr Close(const nsCString& aRecordName);
 
-  GMPErr EnumerateRecords(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                          void* aUserArg);
-
 private:
   bool HasRecord(const nsCString& aRecordName);
   already_AddRefed<GMPRecordImpl> GetRecord(const nsCString& aRecordName);
 
 protected:
   ~GMPStorageChild() {}
 
   // PGMPStorageChild
   mozilla::ipc::IPCResult RecvOpenComplete(const nsCString& aRecordName,
                                            const GMPErr& aStatus) override;
   mozilla::ipc::IPCResult RecvReadComplete(const nsCString& aRecordName,
                                            const GMPErr& aStatus,
                                            InfallibleTArray<uint8_t>&& aBytes) override;
   mozilla::ipc::IPCResult RecvWriteComplete(const nsCString& aRecordName,
                                             const GMPErr& aStatus) override;
-  mozilla::ipc::IPCResult RecvRecordNames(InfallibleTArray<nsCString>&& aRecordNames,
-                                          const GMPErr& aStatus) override;
   mozilla::ipc::IPCResult RecvShutdown() override;
 
 private:
   Monitor mMonitor;
   nsRefPtrHashtable<nsCStringHashKey, GMPRecordImpl> mRecords;
   GMPChild* mPlugin;
-
-  struct RecordIteratorContext {
-    explicit RecordIteratorContext(RecvGMPRecordIteratorPtr aFunc,
-                                   void* aUserArg)
-      : mFunc(aFunc)
-      , mUserArg(aUserArg)
-    {}
-    RecordIteratorContext() {}
-    RecvGMPRecordIteratorPtr mFunc;
-    void* mUserArg;
-  };
-
-  std::queue<RecordIteratorContext> mPendingRecordIterators;
   bool mShutdown;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPStorageChild_h_
--- a/dom/media/gmp/GMPStorageParent.cpp
+++ b/dom/media/gmp/GMPStorageParent.cpp
@@ -157,34 +157,16 @@ GMPStorageParent::RecvWrite(const nsCStr
         this, aRecordName.get(), rv));
 
   Unused << SendWriteComplete(aRecordName, rv);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-GMPStorageParent::RecvGetRecordNames()
-{
-  if (mShutdown) {
-    return IPC_OK();
-  }
-
-  nsTArray<nsCString> recordNames;
-  GMPErr status = mStorage->GetRecordNames(recordNames);
-
-  LOGD(("GMPStorageParent[%p]::RecvGetRecordNames() status=%d numRecords=%d",
-        this, status, recordNames.Length()));
-
-  Unused << SendRecordNames(recordNames, status);
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 GMPStorageParent::RecvClose(const nsCString& aRecordName)
 {
   LOGD(("GMPStorageParent[%p]::RecvClose(record='%s')",
         this, aRecordName.get()));
 
   if (mShutdown) {
     return IPC_OK();
   }
--- a/dom/media/gmp/GMPStorageParent.h
+++ b/dom/media/gmp/GMPStorageParent.h
@@ -23,17 +23,16 @@ public:
   nsresult Init();
   void Shutdown();
 
 protected:
   mozilla::ipc::IPCResult RecvOpen(const nsCString& aRecordName) override;
   mozilla::ipc::IPCResult RecvRead(const nsCString& aRecordName) override;
   mozilla::ipc::IPCResult RecvWrite(const nsCString& aRecordName,
                                     InfallibleTArray<uint8_t>&& aBytes) override;
-  mozilla::ipc::IPCResult RecvGetRecordNames() override;
   mozilla::ipc::IPCResult RecvClose(const nsCString& aRecordName) override;
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   ~GMPStorageParent() {}
 
   RefPtr<GMPStorage> mStorage;
 
--- a/dom/media/gmp/PGMP.ipdl
+++ b/dom/media/gmp/PGMP.ipdl
@@ -24,16 +24,15 @@ parent:
   async PGMPTimer();
   async PGMPStorage();
 
   async PGMPContentChildDestroyed();
 
 child:
   async CrashPluginNow();
   intr StartPlugin(nsString adapter);
-  async SetNodeId(nsCString nodeId);
   async PreloadLibs(nsCString libs);
   async CloseActive();
   async InitGMPContentChild(Endpoint<PGMPContentChild> endpoint);
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/PGMPStorage.ipdl
+++ b/dom/media/gmp/PGMPStorage.ipdl
@@ -14,23 +14,21 @@ namespace gmp {
 async protocol PGMPStorage
 {
   manager PGMP;
 
 child:
   async OpenComplete(nsCString aRecordName, GMPErr aStatus);
   async ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
   async WriteComplete(nsCString aRecordName, GMPErr aStatus);
-  async RecordNames(nsCString[] aRecordNames, GMPErr aStatus);
   async Shutdown();
 
 parent:
   async Open(nsCString aRecordName);
   async Read(nsCString aRecordName);
   async Write(nsCString aRecordName, uint8_t[] aBytes);
   async Close(nsCString aRecordName);
-  async GetRecordNames();
   async __delete__();
 
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/gmp-api/gmp-entrypoints.h
+++ b/dom/media/gmp/gmp-api/gmp-entrypoints.h
@@ -61,15 +61,9 @@ typedef GMPErr (*GMPInitFunc)(const GMPP
 //   API object is defined by the API.
 typedef GMPErr (*GMPGetAPIFunc)(const char* aAPIName, void* aHostAPI, void** aPluginAPI);
 
 // GMPShutdown
 // - Called once before exiting process (unloading library).
 // - Called on main thread.
 typedef void   (*GMPShutdownFunc)(void);
 
-// GMPSetNodeId
-// - Optional, not required to be implemented. Only useful for EME plugins.
-// - Called after GMPInit to set the device-bound origin-specific node id
-//   that this GMP instance is running under.
-typedef void   (*GMPSetNodeIdFunc)(const char* aNodeId, uint32_t aLength);
-
 #endif // GMP_ENTRYPOINTS_h_
--- a/dom/media/gmp/gmp-api/gmp-platform.h
+++ b/dom/media/gmp/gmp-api/gmp-platform.h
@@ -77,42 +77,25 @@ typedef GMPErr (*GMPCreateRecordPtr)(con
                                      uint32_t aRecordNameSize,
                                      GMPRecord** aOutRecord,
                                      GMPRecordClient* aClient);
 
 // Call on main thread only.
 typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
 typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);
 
-typedef void (*RecvGMPRecordIteratorPtr)(GMPRecordIterator* aRecordIterator,
-                                         void* aUserArg,
-                                         GMPErr aStatus);
-
-// Creates a GMPCreateRecordIterator to enumerate the records in storage.
-// When the iterator is ready, the function at aRecvIteratorFunc
-// is called with the GMPRecordIterator as an argument. If the operation
-// fails, RecvGMPRecordIteratorPtr is called with a failure aStatus code.
-// The list that the iterator is covering is fixed when
-// GMPCreateRecordIterator is called, it is *not* updated when changes are
-// made to storage.
-// Iterator begins pointing at first record.
-// aUserArg is passed to the aRecvIteratorFunc upon completion.
-typedef GMPErr (*GMPCreateRecordIteratorPtr)(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                                             void* aUserArg);
-
 struct GMPPlatformAPI {
   // Increment the version when things change. Can only add to the struct,
   // do not change what already exists. Pointers to functions may be NULL
   // when passed to plugins, but beware backwards compat implications of
   // doing that.
   uint16_t version; // Currently version 0
 
   GMPCreateThreadPtr createthread;
   GMPRunOnMainThreadPtr runonmainthread;
   GMPSyncRunOnMainThreadPtr syncrunonmainthread;
   GMPCreateMutexPtr createmutex;
   GMPCreateRecordPtr createrecord;
   GMPSetTimerOnMainThreadPtr settimer;
   GMPGetCurrentTimePtr getcurrenttime;
-  GMPCreateRecordIteratorPtr getrecordenumerator;
 };
 
 #endif // GMP_PLATFORM_h_
--- a/dom/media/gmp/gmp-api/gmp-storage.h
+++ b/dom/media/gmp/gmp-api/gmp-storage.h
@@ -105,37 +105,9 @@ class GMPRecordClient {
   // - GMPGenericErr - Unspecified error.
   // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must
   // call Close() on the GMPRecord to dispose of it.
   virtual void WriteComplete(GMPErr aStatus) = 0;
 
   virtual ~GMPRecordClient() {}
 };
 
-// Iterates over the records that are available. Note: this list maintains
-// a snapshot of the records that were present when the iterator was created.
-// Create by calling the GMPCreateRecordIteratorPtr function on the
-// GMPPlatformAPI struct.
-// Iteration is in alphabetical order.
-class GMPRecordIterator {
-public:
-  // Retrieve the name for the current record.
-  // aOutName is null terminated at character  at index (*aOutNameLength).
-  // Returns GMPNoErr if successful, or GMPEndOfEnumeration if iteration has
-  // reached the end.
-  virtual GMPErr GetName(const char ** aOutName, uint32_t * aOutNameLength) = 0;
-
-  // Advance iteration to the next record.
-  // Returns GMPNoErr if successful, or GMPEndOfEnumeration if iteration has
-  // reached the end.
-  virtual GMPErr NextRecord() = 0;
-
-  // Signals to the GMP host that the GMP is finished with the
-  // GMPRecordIterator. GMPs must call this to release memory held by
-  // the GMPRecordIterator. Do not access the GMPRecordIterator pointer
-  // after calling this!
-  // Memory retrieved by GetName is *not* valid after calling Close()!
-  virtual void Close() = 0;
-
-  virtual ~GMPRecordIterator() {}
-};
-
 #endif // GMP_STORAGE_h_
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -61,37 +61,28 @@ EXPORTS += [
     'GMPVideoEncoderParent.h',
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
     'widevine-adapter/content_decryption_module.h',
 ]
 
-# We link GMPLoader into xul on Android and Linux as its code does not
-# need to be covered by a DRM vendor's voucher.
-if CONFIG['OS_ARCH'] == 'Linux':
-    SOURCES += [
-      'GMPLoader.cpp',
-    ]
-    USE_LIBS += [
-        'rlz',
-    ]
-
 UNIFIED_SOURCES += [
     'GMPCDMCallbackProxy.cpp',
     'GMPCDMProxy.cpp',
     'GMPChild.cpp',
     'GMPContentChild.cpp',
     'GMPContentParent.cpp',
     'GMPCrashHelper.cpp',
     'GMPDecryptorChild.cpp',
     'GMPDecryptorParent.cpp',
     'GMPDiskStorage.cpp',
     'GMPEncryptedBufferDataImpl.cpp',
+    'GMPLoader.cpp',
     'GMPMemoryStorage.cpp',
     'GMPParent.cpp',
     'GMPPlatform.cpp',
     'GMPProcessChild.cpp',
     'GMPProcessParent.cpp',
     'GMPService.cpp',
     'GMPServiceChild.cpp',
     'GMPServiceParent.cpp',
@@ -107,17 +98,16 @@ UNIFIED_SOURCES += [
     'GMPVideoEncoderChild.cpp',
     'GMPVideoEncoderParent.cpp',
     'GMPVideoHost.cpp',
     'GMPVideoi420FrameImpl.cpp',
     'GMPVideoPlaneImpl.cpp'
 ]
 
 DIRS += [
-    'rlz',
     'widevine-adapter',
 ]
 
 IPDL_SOURCES += [
   'GMPTypes.ipdlh',
   'PGMP.ipdl',
   'PGMPContent.ipdl',
   'PGMPDecryptor.ipdl',
@@ -128,16 +118,24 @@ IPDL_SOURCES += [
   'PGMPVideoEncoder.ipdl',
 ]
 
 # comment this out to use Unsafe Shmem for more performance
 DEFINES['GMP_SAFE_SHMEM'] = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
+if CONFIG['MOZ_SANDBOX']:
+    # For sandbox includes and the include dependencies those have
+    LOCAL_INCLUDES += [
+        '/security/sandbox/chromium',
+        '/security/sandbox/chromium-shim',
+    ]
+
+
 FINAL_LIBRARY = 'xul'
 # media/mtransport so we work with --disable-webrtc
 LOCAL_INCLUDES += [
     '/media/mtransport',
     '/xpcom/base',
     '/xpcom/build',
     '/xpcom/threads',
 ]
deleted file mode 100644
--- a/dom/media/gmp/rlz/COPYING
+++ /dev/null
@@ -1,14 +0,0 @@
-Copyright 2010 Google Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
deleted file mode 100644
--- a/dom/media/gmp/rlz/GMPDeviceBinding.cpp
+++ /dev/null
@@ -1,209 +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 "GMPDeviceBinding.h"
-#include "mozilla/Attributes.h"
-#include "prenv.h"
-
-#include <string>
-
-#ifdef XP_WIN
-#include "windows.h"
-#ifdef MOZ_SANDBOX
-#include <intrin.h>
-#include <assert.h>
-#endif
-#endif
-
-#if defined(HASH_NODE_ID_WITH_DEVICE_ID)
-
-// In order to provide EME plugins with a "device binding" capability,
-// in the parent we generate and store some random bytes as salt for every
-// (origin, urlBarOrigin) pair that uses EME. We store these bytes so
-// that every time we revisit the same origin we get the same salt.
-// We send this salt to the child on startup. The child collects some
-// device specific data and munges that with the salt to create the
-// "node id" that we expose to EME plugins. It then overwrites the device
-// specific data, and activates the sandbox.
-
-#include "rlz/lib/machine_id.h"
-#include "rlz/lib/string_utils.h"
-#include "sha256.h"
-
-#ifdef XP_WIN
-#include "windows.h"
-#ifdef MOZ_SANDBOX
-#include <intrin.h>
-#include <assert.h>
-#endif
-#endif
-
-#ifdef XP_MACOSX
-#include <assert.h>
-#ifdef HASH_NODE_ID_WITH_DEVICE_ID
-#include <unistd.h>
-#include <mach/mach.h>
-#include <mach/mach_vm.h>
-#endif
-#endif
-
-#endif // HASH_NODE_ID_WITH_DEVICE_ID
-
-namespace mozilla {
-namespace gmp {
-
-#if defined(XP_WIN) && defined(HASH_NODE_ID_WITH_DEVICE_ID)
-MOZ_NEVER_INLINE
-static bool
-GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom)
-{
-  // "Top" of the free space on the stack is directly after the memory
-  // holding our return address.
-  uint8_t* top = (uint8_t*)_AddressOfReturnAddress();
-
-  // Look down the stack until we find the guard page...
-  MEMORY_BASIC_INFORMATION memInfo = {0};
-  uint8_t* bottom = top;
-  while (1) {
-    if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
-      return false;
-    }
-    if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) {
-      bottom = (uint8_t*)memInfo.BaseAddress + memInfo.RegionSize;
-#ifdef DEBUG
-      if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) {
-        return false;
-      }
-      assert(!(memInfo.Protect & PAGE_GUARD)); // Should have found boundary.
-#endif
-      break;
-    } else if (memInfo.State != MEM_COMMIT ||
-               (memInfo.AllocationProtect & PAGE_READWRITE) != PAGE_READWRITE) {
-      return false;
-    }
-    bottom = (uint8_t*)memInfo.BaseAddress - 1;
-  }
-  *aOutTop = top;
-  *aOutBottom = bottom;
-  return true;
-}
-#endif
-
-#if defined(XP_MACOSX) && defined(HASH_NODE_ID_WITH_DEVICE_ID)
-static mach_vm_address_t
-RegionContainingAddress(mach_vm_address_t aAddress)
-{
-  mach_port_t task;
-  kern_return_t kr = task_for_pid(mach_task_self(), getpid(), &task);
-  if (kr != KERN_SUCCESS) {
-    return 0;
-  }
-
-  mach_vm_address_t address = aAddress;
-  mach_vm_size_t size;
-  vm_region_basic_info_data_64_t info;
-  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
-  mach_port_t object_name;
-  kr = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64,
-                      reinterpret_cast<vm_region_info_t>(&info), &count,
-                      &object_name);
-  if (kr != KERN_SUCCESS || size == 0
-      || address > aAddress || address + size <= aAddress) {
-    // mach_vm_region failed, or couldn't find region at given address.
-    return 0;
-  }
-
-  return address;
-}
-
-MOZ_NEVER_INLINE
-static bool
-GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom)
-{
-  mach_vm_address_t stackFrame =
-    reinterpret_cast<mach_vm_address_t>(__builtin_frame_address(0));
-  *aOutTop = reinterpret_cast<uint8_t*>(stackFrame);
-  // Kernel code shows that stack is always a single region.
-  *aOutBottom = reinterpret_cast<uint8_t*>(RegionContainingAddress(stackFrame));
-  return *aOutBottom && (*aOutBottom < *aOutTop);
-}
-#endif
-
-#ifdef HASH_NODE_ID_WITH_DEVICE_ID
-static void SecureMemset(void* start, uint8_t value, size_t size)
-{
-  // Inline instructions equivalent to RtlSecureZeroMemory().
-  for (size_t i = 0; i < size; ++i) {
-    volatile uint8_t* p = static_cast<volatile uint8_t*>(start) + i;
-    *p = value;
-  }
-}
-#endif
-
-bool
-CalculateGMPDeviceId(char* aOriginSalt,
-                     uint32_t aOriginSaltLen,
-                     std::string& aOutNodeId)
-{
-#ifdef HASH_NODE_ID_WITH_DEVICE_ID
-  if (aOriginSaltLen > 0) {
-    std::vector<uint8_t> deviceId;
-    int volumeId;
-    if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) {
-      return false;
-    }
-
-    SHA256Context ctx;
-    SHA256_Begin(&ctx);
-    SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen);
-    SHA256_Update(&ctx, deviceId.data(), deviceId.size());
-    SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int));
-    uint8_t digest[SHA256_LENGTH] = {0};
-    unsigned int digestLen = 0;
-    SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH);
-
-    // Overwrite all data involved in calculation as it could potentially
-    // identify the user, so there's no chance a GMP can read it and use
-    // it for identity tracking.
-    SecureMemset(&ctx, 0, sizeof(ctx));
-    SecureMemset(aOriginSalt, 0, aOriginSaltLen);
-    SecureMemset(&volumeId, 0, sizeof(volumeId));
-    SecureMemset(deviceId.data(), '*', deviceId.size());
-    deviceId.clear();
-
-    if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &aOutNodeId)) {
-      return false;
-    }
-
-    if (!PR_GetEnv("MOZ_GMP_DISABLE_NODE_ID_CLEANUP")) {
-      // We've successfully bound the origin salt to node id.
-      // rlz_lib::GetRawMachineId and/or the system functions it
-      // called could have left user identifiable data on the stack,
-      // so carefully zero the stack down to the guard page.
-      uint8_t* top;
-      uint8_t* bottom;
-      if (!GetStackAfterCurrentFrame(&top, &bottom)) {
-        return false;
-      }
-      assert(top >= bottom);
-      // Inline instructions equivalent to RtlSecureZeroMemory().
-      // We can't just use RtlSecureZeroMemory here directly, as in debug
-      // builds, RtlSecureZeroMemory() can't be inlined, and the stack
-      // memory it uses would get wiped by itself running, causing crashes.
-      for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) {
-        *p = 0;
-      }
-    }
-  } else
-#endif
-  {
-    aOutNodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen);
-  }
-  return true;
-}
-
-} // namespace gmp
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/gmp/rlz/GMPDeviceBinding.h
+++ /dev/null
@@ -1,22 +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/. */
-
-#ifndef GMP_DEVICE_BINDING_h_
-#define GMP_DEVICE_BINDING_h_
-
-#include <string>
-
-namespace mozilla {
-namespace gmp {
-
-bool CalculateGMPDeviceId(char* aOriginSalt,
-                          uint32_t aOriginSaltLen,
-                          std::string& aOutNodeId);
-
-} // namespace gmp
-} // namespace mozilla
-
-#endif // GMP_DEVICE_BINDING_h_
deleted file mode 100644
--- a/dom/media/gmp/rlz/README.mozilla
+++ /dev/null
@@ -1,6 +0,0 @@
-Code taken from rlz project: https://code.google.com/p/rlz/
-
-Revision: 134, then with unused code stripped out.
-
-Note: base/ contains wrappers/dummies to provide implementations of the
-Chromium APIs that this code relies upon.
deleted file mode 100644
--- a/dom/media/gmp/rlz/lib/assert.h
+++ /dev/null
@@ -1,14 +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 FAKE_ASSERT_H_
-#define FAKE_ASSERT_H_
-
-#include <assert.h>
-
-#define ASSERT_STRING(x) { assert(false); }
-#define VERIFY(x) { assert(x); };
-
-#endif
deleted file mode 100644
--- a/dom/media/gmp/rlz/lib/machine_id.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-// Use of this source code is governed by an Apache-style license that can be
-// found in the COPYING file.
-
-#ifndef RLZ_LIB_MACHINE_ID_H_
-#define RLZ_LIB_MACHINE_ID_H_
-
-#include <vector>
-
-namespace rlz_lib {
-
-// Retrieves a raw machine identifier string and a machine-specific
-// 4 byte value. GetMachineId() will SHA1 |data|, append |more_data|, compute
-// the Crc8 of that, and return a hex-encoded string of that data.
-bool GetRawMachineId(std::vector<uint8_t>* data, int* more_data);
-
-}  // namespace rlz_lib
-
-#endif  // RLZ_LIB_MACHINE_ID_H_
deleted file mode 100644
--- a/dom/media/gmp/rlz/lib/string_utils.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
-// Use of this source code is governed by an Apache-style license that can be
-// found in the COPYING file.
-//
-// String manipulation functions used in the RLZ library.
-
-#include "rlz/lib/string_utils.h"
-
-namespace rlz_lib {
-
-bool BytesToString(const unsigned char* data,
-                   int data_len,
-                   std::string* string) {
-  if (!string)
-    return false;
-
-  string->clear();
-  if (data_len < 1 || !data)
-    return false;
-
-  static const char kHex[] = "0123456789ABCDEF";
-
-  // Fix the buffer size to begin with to avoid repeated re-allocation.
-  string->resize(data_len * 2);
-  int index = data_len;
-  while (index--) {
-    string->at(2 * index) = kHex[data[index] >> 4];  // high digit
-    string->at(2 * index + 1) = kHex[data[index] & 0x0F];  // low digit
-  }
-
-  return true;
-}
-
-}  // namespace rlz_lib
deleted file mode 100644
--- a/dom/media/gmp/rlz/lib/string_utils.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
-// Use of this source code is governed by an Apache-style license that can be
-// found in the COPYING file.
-//
-// String manipulation functions used in the RLZ library.
-
-#ifndef RLZ_LIB_STRING_UTILS_H_
-#define RLZ_LIB_STRING_UTILS_H_
-
-#include <string>
-
-namespace rlz_lib {
-
-bool BytesToString(const unsigned char* data,
-                   int data_len,
-                   std::string* string);
-
-};  // namespace
-
-#endif  // RLZ_LIB_STRING_UTILS_H_
deleted file mode 100644
--- a/dom/media/gmp/rlz/mac/lib/machine_id_mac.cc
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/network/IOEthernetController.h>
-#include <IOKit/network/IOEthernetInterface.h>
-#include <IOKit/network/IONetworkInterface.h>
-#include <vector>
-#include <string>
-
-// Note: The original machine_id_mac.cc code is in namespace rlz_lib below.
-// It depends on some external files, which would bring in a log of Chromium
-// code if imported as well.
-// Instead only the necessary code has been extracted from the relevant files,
-// and further combined and reduced to limit the maintenance burden.
-
-// [Extracted from base/logging.h]
-#define DCHECK assert
-
-namespace base {
-
-// [Extracted from base/mac/scoped_typeref.h and base/mac/scoped_cftyperef.h]
-template<typename T>
-class ScopedCFTypeRef {
- public:
-  typedef T element_type;
-
-  explicit ScopedCFTypeRef(T object)
-      : object_(object) {
-  }
-
-  ScopedCFTypeRef(const ScopedCFTypeRef<T>& that) = delete;
-  ScopedCFTypeRef(ScopedCFTypeRef<T>&& that) = delete;
-
-  ~ScopedCFTypeRef() {
-    if (object_)
-      CFRelease(object_);
-  }
-
-  ScopedCFTypeRef& operator=(const ScopedCFTypeRef<T>& that) = delete;
-  ScopedCFTypeRef& operator=(ScopedCFTypeRef<T>&& that) = delete;
-
-  operator T() const {
-    return object_;
-  }
-
-  // ScopedCFTypeRef<>::release() is like scoped_ptr<>::release.  It is NOT
-  // a wrapper for CFRelease().
-  T release() {
-    T temp = object_;
-    object_ = NULL;
-    return temp;
-  }
-
- private:
-  T object_;
-};
-
-namespace mac {
-
-// [Extracted from base/mac/scoped_ioobject.h]
-// Just like ScopedCFTypeRef but for io_object_t and subclasses.
-template<typename IOT>
-class ScopedIOObject {
- public:
-  typedef IOT element_type;
-
-  explicit ScopedIOObject(IOT object = IO_OBJECT_NULL)
-      : object_(object) {
-  }
-
-  ~ScopedIOObject() {
-    if (object_)
-      IOObjectRelease(object_);
-  }
-
-  ScopedIOObject(const ScopedIOObject&) = delete;
-  void operator=(const ScopedIOObject&) = delete;
-
-  void reset(IOT object = IO_OBJECT_NULL) {
-    if (object_)
-      IOObjectRelease(object_);
-    object_ = object;
-  }
-
-  operator IOT() const {
-    return object_;
-  }
-
- private:
-  IOT object_;
-};
-
-// [Extracted from base/mac/foundation_util.h]
-template<typename T>
-T CFCast(const CFTypeRef& cf_val);
-
-template<>
-CFDataRef
-CFCast<CFDataRef>(const CFTypeRef& cf_val) {
-  if (cf_val == NULL) {
-    return NULL;
-  }
-  if (CFGetTypeID(cf_val) == CFDataGetTypeID()) {
-    return (CFDataRef)(cf_val);
-  }
-  return NULL;
-}
-
-template<>
-CFStringRef
-CFCast<CFStringRef>(const CFTypeRef& cf_val) {
-  if (cf_val == NULL) {
-    return NULL;
-  }
-  if (CFGetTypeID(cf_val) == CFStringGetTypeID()) {
-    return (CFStringRef)(cf_val);
-  }
-  return NULL;
-}
-
-}  // namespace mac
-
-// [Extracted from base/strings/sys_string_conversions_mac.mm]
-static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
-
-template<typename StringType>
-static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
-                                                   CFStringEncoding encoding) {
-  CFIndex length = CFStringGetLength(cfstring);
-  if (length == 0)
-    return StringType();
-
-  CFRange whole_string = CFRangeMake(0, length);
-  CFIndex out_size;
-  CFIndex converted = CFStringGetBytes(cfstring,
-                                       whole_string,
-                                       encoding,
-                                       0,      // lossByte
-                                       false,  // isExternalRepresentation
-                                       NULL,   // buffer
-                                       0,      // maxBufLen
-                                       &out_size);
-  if (converted == 0 || out_size == 0)
-    return StringType();
-
-  // out_size is the number of UInt8-sized units needed in the destination.
-  // A buffer allocated as UInt8 units might not be properly aligned to
-  // contain elements of StringType::value_type.  Use a container for the
-  // proper value_type, and convert out_size by figuring the number of
-  // value_type elements per UInt8.  Leave room for a NUL terminator.
-  typename StringType::size_type elements =
-      out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
-
-  std::vector<typename StringType::value_type> out_buffer(elements);
-  converted = CFStringGetBytes(cfstring,
-                               whole_string,
-                               encoding,
-                               0,      // lossByte
-                               false,  // isExternalRepresentation
-                               reinterpret_cast<UInt8*>(&out_buffer[0]),
-                               out_size,
-                               NULL);  // usedBufLen
-  if (converted == 0)
-    return StringType();
-
-  out_buffer[elements - 1] = '\0';
-  return StringType(&out_buffer[0], elements - 1);
-}
-
-std::string SysCFStringRefToUTF8(CFStringRef ref)
-{
-  return CFStringToSTLStringWithEncodingT<std::string>(ref,
-                                                       kNarrowStringEncoding);
-}
-
-} // namespace base
-
-
-namespace rlz_lib {
-
-namespace {
-
-// See http://developer.apple.com/library/mac/#technotes/tn1103/_index.html
-
-// The caller is responsible for freeing |matching_services|.
-bool FindEthernetInterfaces(io_iterator_t* matching_services) {
-  base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict(
-      IOServiceMatching(kIOEthernetInterfaceClass));
-  if (!matching_dict)
-    return false;
-
-  base::ScopedCFTypeRef<CFMutableDictionaryRef> primary_interface(
-      CFDictionaryCreateMutable(kCFAllocatorDefault,
-                                0,
-                                &kCFTypeDictionaryKeyCallBacks,
-                                &kCFTypeDictionaryValueCallBacks));
-  if (!primary_interface)
-    return false;
-
-  CFDictionarySetValue(
-      primary_interface, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
-  CFDictionarySetValue(
-      matching_dict, CFSTR(kIOPropertyMatchKey), primary_interface);
-
-  kern_return_t kern_result = IOServiceGetMatchingServices(
-      kIOMasterPortDefault, matching_dict.release(), matching_services);
-
-  return kern_result == KERN_SUCCESS;
-}
-
-bool GetMACAddressFromIterator(io_iterator_t primary_interface_iterator,
-                               uint8_t* buffer, size_t buffer_size) {
-  if (buffer_size < kIOEthernetAddressSize)
-    return false;
-
-  bool success = false;
-
-  bzero(buffer, buffer_size);
-  base::mac::ScopedIOObject<io_object_t> primary_interface;
-  while (primary_interface.reset(IOIteratorNext(primary_interface_iterator)),
-         primary_interface) {
-    io_object_t primary_interface_parent;
-    kern_return_t kern_result = IORegistryEntryGetParentEntry(
-        primary_interface, kIOServicePlane, &primary_interface_parent);
-    base::mac::ScopedIOObject<io_object_t> primary_interface_parent_deleter(
-        primary_interface_parent);
-    success = kern_result == KERN_SUCCESS;
-
-    if (!success)
-      continue;
-
-    base::ScopedCFTypeRef<CFTypeRef> mac_data(
-        IORegistryEntryCreateCFProperty(primary_interface_parent,
-                                        CFSTR(kIOMACAddress),
-                                        kCFAllocatorDefault,
-                                        0));
-    CFDataRef mac_data_data = base::mac::CFCast<CFDataRef>(mac_data);
-    if (mac_data_data) {
-      CFDataGetBytes(
-          mac_data_data, CFRangeMake(0, kIOEthernetAddressSize), buffer);
-    }
-  }
-
-  return success;
-}
-
-bool GetMacAddress(unsigned char* buffer, size_t size) {
-  io_iterator_t primary_interface_iterator;
-  if (!FindEthernetInterfaces(&primary_interface_iterator))
-    return false;
-  bool result = GetMACAddressFromIterator(
-      primary_interface_iterator, buffer, size);
-  IOObjectRelease(primary_interface_iterator);
-  return result;
-}
-
-CFStringRef CopySerialNumber() {
-  base::mac::ScopedIOObject<io_service_t> expert_device(
-      IOServiceGetMatchingService(kIOMasterPortDefault,
-          IOServiceMatching("IOPlatformExpertDevice")));
-  if (!expert_device)
-    return NULL;
-
-  base::ScopedCFTypeRef<CFTypeRef> serial_number(
-      IORegistryEntryCreateCFProperty(expert_device,
-                                      CFSTR(kIOPlatformSerialNumberKey),
-                                      kCFAllocatorDefault,
-                                      0));
-  CFStringRef serial_number_cfstring =
-      base::mac::CFCast<CFStringRef>(serial_number.release());
-  if (!serial_number_cfstring)
-    return NULL;
-
-  return serial_number_cfstring;
-}
-
-}  // namespace
-
-bool GetRawMachineId(std::vector<uint8_t>* data, int* more_data) {
-  uint8_t mac_address[kIOEthernetAddressSize];
-
-  std::string id;
-  if (GetMacAddress(mac_address, sizeof(mac_address))) {
-    id += "mac:";
-    static const char hex[] =
-      { '0', '1', '2', '3', '4', '5', '6', '7',
-        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-    for (int i = 0; i < kIOEthernetAddressSize; ++i) {
-      uint8_t byte = mac_address[i];
-      id += hex[byte >> 4];
-      id += hex[byte & 0xF];
-    }
-  }
-
-  // A MAC address is enough to uniquely identify a machine, but it's only 6
-  // bytes, 3 of which are manufacturer-determined. To make brute-forcing the
-  // SHA1 of this harder, also append the system's serial number.
-  CFStringRef serial = CopySerialNumber();
-  if (serial) {
-    if (!id.empty()) {
-      id += ' ';
-    }
-    id += "serial:";
-    id += base::SysCFStringRefToUTF8(serial);
-    CFRelease(serial);
-  }
-
-  // Get the contents of the string 'id' as a bunch of bytes.
-  data->assign(&id[0], &id[id.size()]);
-
-  // On windows, this is set to the volume id. Since it's not scrambled before
-  // being sent, just set it to 1.
-  *more_data = 1;
-  return true;
-}
-
-}  // namespace rlz_lib
deleted file mode 100644
--- a/dom/media/gmp/rlz/moz.build
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Note: build rlz in its own moz.build, so it doesn't pickup any of
-# Chromium IPC's headers used in the moz.build of the parent file.
-
-Library('rlz')
-
-UNIFIED_SOURCES += [
-    'GMPDeviceBinding.cpp',
-]
-
-if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] in ['WINNT', 'Darwin']:
-    DEFINES['HASH_NODE_ID_WITH_DEVICE_ID'] = 1;
-    UNIFIED_SOURCES += [
-        'lib/string_utils.cc',
-        'sha256.c',
-    ]
-
-if CONFIG['OS_TARGET'] == 'WINNT':
-    UNIFIED_SOURCES += [
-        'win/lib/machine_id_win.cc',
-    ]
-
-if CONFIG['OS_TARGET'] == 'Darwin':
-    UNIFIED_SOURCES += [
-        'mac/lib/machine_id_mac.cc',
-    ]
-    OS_LIBS += [
-        '-framework IOKit',
-    ]
-
-LOCAL_INCLUDES += [
-    '..',
-]
-
-EXPORTS += [
-    'GMPDeviceBinding.h',
-]
deleted file mode 100644
--- a/dom/media/gmp/rlz/sha256.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/* 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/. */
-
-// Stripped down version of security/nss/lib/freebl/sha512.c
-// and related headers.
-
-#include "sha256.h"
-#include "string.h"
-#include "prcpucfg.h"
-#if defined(NSS_X86) || defined(SHA_NO_LONG_LONG)
-#define NOUNROLL512 1
-#undef HAVE_LONG_LONG
-#endif
-
-#define SHA256_BLOCK_LENGTH 64 /* bytes */ 
-
-typedef enum _SECStatus {
-    SECWouldBlock = -2,
-    SECFailure = -1,
-    SECSuccess = 0
-} SECStatus;
-
-/* ============= Common constants and defines ======================= */
-
-#define W ctx->u.w
-#define B ctx->u.b
-#define H ctx->h
-
-#define SHR(x,n) (x >> n)
-#define SHL(x,n) (x << n)
-#define Ch(x,y,z)  ((x & y) ^ (~x & z))
-#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
-#define SHA_MIN(a,b) (a < b ? a : b)
-
-/* Padding used with all flavors of SHA */
-static const PRUint8 pad[240] = { 
-0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-   /* compiler will fill the rest in with zeros */
-};
-
-/* ============= SHA256 implementation ================================== */
-
-/* SHA-256 constants, K256. */
-static const PRUint32 K256[64] = {
-    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 
-    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
-    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 
-    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
-    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 
-    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 
-    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
-    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 
-    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
-    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 
-    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 
-    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
-    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 
-    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
-};
-
-/* SHA-256 initial hash values */
-static const PRUint32 H256[8] = {
-    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 
-    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
-};
-
-#if defined(_MSC_VER)
-#include <stdlib.h>
-#pragma intrinsic(_byteswap_ulong)
-#define SHA_HTONL(x) _byteswap_ulong(x)
-#define BYTESWAP4(x)  x = SHA_HTONL(x)
-#elif defined(__GNUC__) && defined(NSS_X86_OR_X64)
-static __inline__ PRUint32 swap4b(PRUint32 value)
-{
-    __asm__("bswap %0" : "+r" (value));
-    return (value);
-}
-#define SHA_HTONL(x) swap4b(x)
-#define BYTESWAP4(x)  x = SHA_HTONL(x)
-
-#elif defined(__GNUC__) && (defined(__thumb2__) || \
-      (!defined(__thumb__) && \
-      (defined(__ARM_ARCH_6__) || \
-       defined(__ARM_ARCH_6J__) || \
-       defined(__ARM_ARCH_6K__) || \
-       defined(__ARM_ARCH_6Z__) || \
-       defined(__ARM_ARCH_6ZK__) || \
-       defined(__ARM_ARCH_6T2__) || \
-       defined(__ARM_ARCH_7__) || \
-       defined(__ARM_ARCH_7A__) || \
-       defined(__ARM_ARCH_7R__))))
-static __inline__ PRUint32 swap4b(PRUint32 value)
-{
-    PRUint32 ret;
-    __asm__("rev %0, %1" : "=r" (ret) : "r"(value));
-    return ret;
-}
-#define SHA_HTONL(x) swap4b(x)
-#define BYTESWAP4(x)  x = SHA_HTONL(x)
-
-#else
-#define SWAP4MASK  0x00FF00FF
-#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \
-                      ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK))
-#define BYTESWAP4(x)  x = SHA_HTONL(x)
-#endif
-
-#if defined(_MSC_VER)
-#pragma intrinsic (_lrotr, _lrotl) 
-#define ROTR32(x,n) _lrotr(x,n)
-#define ROTL32(x,n) _lrotl(x,n)
-#else
-#define ROTR32(x,n) ((x >> n) | (x << ((8 * sizeof x) - n)))
-#define ROTL32(x,n) ((x << n) | (x >> ((8 * sizeof x) - n)))
-#endif
-
-/* Capitol Sigma and lower case sigma functions */
-#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22))
-#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25))
-#define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3))
-#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10))
-
-void 
-SHA256_Begin(SHA256Context *ctx)
-{
-    memset(ctx, 0, sizeof *ctx);
-    memcpy(H, H256, sizeof H256);
-}
-
-static void
-SHA256_Compress(SHA256Context *ctx)
-{
-  {
-    register PRUint32 t1, t2;
-
-#if defined(IS_LITTLE_ENDIAN)
-    BYTESWAP4(W[0]);
-    BYTESWAP4(W[1]);
-    BYTESWAP4(W[2]);
-    BYTESWAP4(W[3]);
-    BYTESWAP4(W[4]);
-    BYTESWAP4(W[5]);
-    BYTESWAP4(W[6]);
-    BYTESWAP4(W[7]);
-    BYTESWAP4(W[8]);
-    BYTESWAP4(W[9]);
-    BYTESWAP4(W[10]);
-    BYTESWAP4(W[11]);
-    BYTESWAP4(W[12]);
-    BYTESWAP4(W[13]);
-    BYTESWAP4(W[14]);
-    BYTESWAP4(W[15]);
-#endif
-
-#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
-
-    /* prepare the "message schedule"   */
-#ifdef NOUNROLL256
-    {
-	int t;
-	for (t = 16; t < 64; ++t) {
-	    INITW(t);
-	}
-    }
-#else
-    INITW(16);
-    INITW(17);
-    INITW(18);
-    INITW(19);
-
-    INITW(20);
-    INITW(21);
-    INITW(22);
-    INITW(23);
-    INITW(24);
-    INITW(25);
-    INITW(26);
-    INITW(27);
-    INITW(28);
-    INITW(29);
-
-    INITW(30);
-    INITW(31);
-    INITW(32);
-    INITW(33);
-    INITW(34);
-    INITW(35);
-    INITW(36);
-    INITW(37);
-    INITW(38);
-    INITW(39);
-
-    INITW(40);
-    INITW(41);
-    INITW(42);
-    INITW(43);
-    INITW(44);
-    INITW(45);
-    INITW(46);
-    INITW(47);
-    INITW(48);
-    INITW(49);
-
-    INITW(50);
-    INITW(51);
-    INITW(52);
-    INITW(53);
-    INITW(54);
-    INITW(55);
-    INITW(56);
-    INITW(57);
-    INITW(58);
-    INITW(59);
-
-    INITW(60);
-    INITW(61);
-    INITW(62);
-    INITW(63);
-
-#endif
-#undef INITW
-  }
-  {
-    PRUint32 a, b, c, d, e, f, g, h;
-
-    a = H[0];
-    b = H[1];
-    c = H[2];
-    d = H[3];
-    e = H[4];
-    f = H[5];
-    g = H[6];
-    h = H[7];
-
-#define ROUND(n,a,b,c,d,e,f,g,h) \
-    h += S1(e) + Ch(e,f,g) + K256[n] + W[n]; \
-    d += h; \
-    h += S0(a) + Maj(a,b,c); 
-
-#ifdef NOUNROLL256
-    {
-	int t;
-	for (t = 0; t < 64; t+= 8) {
-	    ROUND(t+0,a,b,c,d,e,f,g,h)
-	    ROUND(t+1,h,a,b,c,d,e,f,g)
-	    ROUND(t+2,g,h,a,b,c,d,e,f)
-	    ROUND(t+3,f,g,h,a,b,c,d,e)
-	    ROUND(t+4,e,f,g,h,a,b,c,d)
-	    ROUND(t+5,d,e,f,g,h,a,b,c)
-	    ROUND(t+6,c,d,e,f,g,h,a,b)
-	    ROUND(t+7,b,c,d,e,f,g,h,a)
-	}
-    }
-#else
-    ROUND( 0,a,b,c,d,e,f,g,h)
-    ROUND( 1,h,a,b,c,d,e,f,g)
-    ROUND( 2,g,h,a,b,c,d,e,f)
-    ROUND( 3,f,g,h,a,b,c,d,e)
-    ROUND( 4,e,f,g,h,a,b,c,d)
-    ROUND( 5,d,e,f,g,h,a,b,c)
-    ROUND( 6,c,d,e,f,g,h,a,b)
-    ROUND( 7,b,c,d,e,f,g,h,a)
-
-    ROUND( 8,a,b,c,d,e,f,g,h)
-    ROUND( 9,h,a,b,c,d,e,f,g)
-    ROUND(10,g,h,a,b,c,d,e,f)
-    ROUND(11,f,g,h,a,b,c,d,e)
-    ROUND(12,e,f,g,h,a,b,c,d)
-    ROUND(13,d,e,f,g,h,a,b,c)
-    ROUND(14,c,d,e,f,g,h,a,b)
-    ROUND(15,b,c,d,e,f,g,h,a)
-
-    ROUND(16,a,b,c,d,e,f,g,h)
-    ROUND(17,h,a,b,c,d,e,f,g)
-    ROUND(18,g,h,a,b,c,d,e,f)
-    ROUND(19,f,g,h,a,b,c,d,e)
-    ROUND(20,e,f,g,h,a,b,c,d)
-    ROUND(21,d,e,f,g,h,a,b,c)
-    ROUND(22,c,d,e,f,g,h,a,b)
-    ROUND(23,b,c,d,e,f,g,h,a)
-
-    ROUND(24,a,b,c,d,e,f,g,h)
-    ROUND(25,h,a,b,c,d,e,f,g)
-    ROUND(26,g,h,a,b,c,d,e,f)
-    ROUND(27,f,g,h,a,b,c,d,e)
-    ROUND(28,e,f,g,h,a,b,c,d)
-    ROUND(29,d,e,f,g,h,a,b,c)
-    ROUND(30,c,d,e,f,g,h,a,b)
-    ROUND(31,b,c,d,e,f,g,h,a)
-
-    ROUND(32,a,b,c,d,e,f,g,h)
-    ROUND(33,h,a,b,c,d,e,f,g)
-    ROUND(34,g,h,a,b,c,d,e,f)
-    ROUND(35,f,g,h,a,b,c,d,e)
-    ROUND(36,e,f,g,h,a,b,c,d)
-    ROUND(37,d,e,f,g,h,a,b,c)
-    ROUND(38,c,d,e,f,g,h,a,b)
-    ROUND(39,b,c,d,e,f,g,h,a)
-
-    ROUND(40,a,b,c,d,e,f,g,h)
-    ROUND(41,h,a,b,c,d,e,f,g)
-    ROUND(42,g,h,a,b,c,d,e,f)
-    ROUND(43,f,g,h,a,b,c,d,e)
-    ROUND(44,e,f,g,h,a,b,c,d)
-    ROUND(45,d,e,f,g,h,a,b,c)
-    ROUND(46,c,d,e,f,g,h,a,b)
-    ROUND(47,b,c,d,e,f,g,h,a)
-
-    ROUND(48,a,b,c,d,e,f,g,h)
-    ROUND(49,h,a,b,c,d,e,f,g)
-    ROUND(50,g,h,a,b,c,d,e,f)
-    ROUND(51,f,g,h,a,b,c,d,e)
-    ROUND(52,e,f,g,h,a,b,c,d)
-    ROUND(53,d,e,f,g,h,a,b,c)
-    ROUND(54,c,d,e,f,g,h,a,b)
-    ROUND(55,b,c,d,e,f,g,h,a)
-
-    ROUND(56,a,b,c,d,e,f,g,h)
-    ROUND(57,h,a,b,c,d,e,f,g)
-    ROUND(58,g,h,a,b,c,d,e,f)
-    ROUND(59,f,g,h,a,b,c,d,e)
-    ROUND(60,e,f,g,h,a,b,c,d)
-    ROUND(61,d,e,f,g,h,a,b,c)
-    ROUND(62,c,d,e,f,g,h,a,b)
-    ROUND(63,b,c,d,e,f,g,h,a)
-#endif
-
-    H[0] += a;
-    H[1] += b;
-    H[2] += c;
-    H[3] += d;
-    H[4] += e;
-    H[5] += f;
-    H[6] += g;
-    H[7] += h;
-  }
-#undef ROUND
-}
-
-#undef s0
-#undef s1
-#undef S0
-#undef S1
-
-void 
-SHA256_Update(SHA256Context *ctx, const unsigned char *input,
-		    unsigned int inputLen)
-{
-    unsigned int inBuf = ctx->sizeLo & 0x3f;
-    if (!inputLen)
-    	return;
-
-    /* Add inputLen into the count of bytes processed, before processing */
-    if ((ctx->sizeLo += inputLen) < inputLen)
-    	ctx->sizeHi++;
-
-    /* if data already in buffer, attemp to fill rest of buffer */
-    if (inBuf) {
-    	unsigned int todo = SHA256_BLOCK_LENGTH - inBuf;
-	if (inputLen < todo)
-	    todo = inputLen;
-	memcpy(B + inBuf, input, todo);
-	input    += todo;
-	inputLen -= todo;
-	if (inBuf + todo == SHA256_BLOCK_LENGTH)
-	    SHA256_Compress(ctx);
-    }
-
-    /* if enough data to fill one or more whole buffers, process them. */
-    while (inputLen >= SHA256_BLOCK_LENGTH) {
-    	memcpy(B, input, SHA256_BLOCK_LENGTH);
-	input    += SHA256_BLOCK_LENGTH;
-	inputLen -= SHA256_BLOCK_LENGTH;
-	SHA256_Compress(ctx);
-    }
-    /* if data left over, fill it into buffer */
-    if (inputLen) 
-    	memcpy(B, input, inputLen);
-}
-
-void 
-SHA256_End(SHA256Context *ctx, unsigned char *digest,
-           unsigned int *digestLen, unsigned int maxDigestLen)
-{
-    unsigned int inBuf = ctx->sizeLo & 0x3f;
-    unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf);
-    PRUint32 hi, lo;
-#ifdef SWAP4MASK
-    PRUint32 t1;
-#endif
-
-    hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29);
-    lo = (ctx->sizeLo << 3);
-
-    SHA256_Update(ctx, pad, padLen);
-
-#if defined(IS_LITTLE_ENDIAN)
-    W[14] = SHA_HTONL(hi);
-    W[15] = SHA_HTONL(lo);
-#else
-    W[14] = hi;
-    W[15] = lo;
-#endif
-    SHA256_Compress(ctx);
-
-    /* now output the answer */
-#if defined(IS_LITTLE_ENDIAN)
-    BYTESWAP4(H[0]);
-    BYTESWAP4(H[1]);
-    BYTESWAP4(H[2]);
-    BYTESWAP4(H[3]);
-    BYTESWAP4(H[4]);
-    BYTESWAP4(H[5]);
-    BYTESWAP4(H[6]);
-    BYTESWAP4(H[7]);
-#endif
-    padLen = PR_MIN(SHA256_LENGTH, maxDigestLen);
-    memcpy(digest, H, padLen);
-    if (digestLen)
-	*digestLen = padLen;
-}
-
-void
-SHA256_EndRaw(SHA256Context *ctx, unsigned char *digest,
-	      unsigned int *digestLen, unsigned int maxDigestLen)
-{
-    PRUint32 h[8];
-    unsigned int len;
-#ifdef SWAP4MASK
-    PRUint32 t1;
-#endif
-
-    memcpy(h, ctx->h, sizeof(h));
-
-#if defined(IS_LITTLE_ENDIAN)
-    BYTESWAP4(h[0]);
-    BYTESWAP4(h[1]);
-    BYTESWAP4(h[2]);
-    BYTESWAP4(h[3]);
-    BYTESWAP4(h[4]);
-    BYTESWAP4(h[5]);
-    BYTESWAP4(h[6]);
-    BYTESWAP4(h[7]);
-#endif
-
-    len = PR_MIN(SHA256_LENGTH, maxDigestLen);
-    memcpy(digest, h, len);
-    if (digestLen)
-	*digestLen = len;
-}
-
-SECStatus 
-SHA256_HashBuf(unsigned char *dest, const unsigned char *src, 
-               PRUint32 src_length)
-{
-    SHA256Context ctx;
-    unsigned int outLen;
-
-    SHA256_Begin(&ctx);
-    SHA256_Update(&ctx, src, src_length);
-    SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH);
-    memset(&ctx, 0, sizeof ctx);
-
-    return SECSuccess;
-}
deleted file mode 100644
--- a/dom/media/gmp/rlz/sha256.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* 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/. */
-
-// Stripped down version of security/nss/lib/freebl/blapi.h
-// and related headers.
-
-#ifndef _SHA256_H_
-#define _SHA256_H_
-
-#define SHA256_LENGTH 32 
-
-#include "prtypes.h"	/* for PRUintXX */
-#include "prlong.h"
-
-#ifdef __cplusplus 
-extern "C" {
-#endif
-
-struct SHA256Context {
-  union {
-    PRUint32 w[64];	    /* message schedule, input buffer, plus 48 words */
-    PRUint8  b[256];
-  } u;
-  PRUint32 h[8];		/* 8 state variables */
-  PRUint32 sizeHi,sizeLo;	/* 64-bit count of hashed bytes. */
-};
-
-typedef struct SHA256Context SHA256Context;
-
-extern void
-SHA256_Begin(SHA256Context *ctx);
-
-extern void 
-SHA256_Update(SHA256Context *ctx, const unsigned char *input,
-		    unsigned int inputLen);
-
-extern void
-SHA256_End(SHA256Context *ctx, unsigned char *digest,
-           unsigned int *digestLen, unsigned int maxDigestLen);
-
-#ifdef __cplusplus 
-} /* extern C */
-#endif
-
-#endif /* _SHA256_H_ */
deleted file mode 100644
--- a/dom/media/gmp/rlz/win/lib/machine_id_win.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-// Use of this source code is governed by an Apache-style license that can be
-// found in the COPYING file.
-
-#include <windows.h>
-#include <sddl.h>  // For ConvertSidToStringSidW.
-#include <string>
-#include <vector>
-#include "mozilla/ArrayUtils.h"
-
-#include "rlz/lib/assert.h"
-
-namespace rlz_lib {
-
-namespace {
-
-bool GetSystemVolumeSerialNumber(int* number) {
-  if (!number)
-    return false;
-
-  *number = 0;
-
-  // Find the system root path (e.g: C:\).
-  wchar_t system_path[MAX_PATH + 1];
-  if (!GetSystemDirectoryW(system_path, MAX_PATH))
-    return false;
-
-  wchar_t* first_slash = wcspbrk(system_path, L"\\/");
-  if (first_slash != NULL)
-    *(first_slash + 1) = 0;
-
-  DWORD number_local = 0;
-  if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
-                             NULL, 0))
-    return false;
-
-  *number = (int)number_local;
-  return true;
-}
-
-bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
-  static const DWORD kStartDomainLength = 128;  // reasonable to start with
-
-  std::vector<wchar_t> domain_buffer(kStartDomainLength, 0);
-  DWORD domain_size = kStartDomainLength;
-  DWORD sid_dword_size = sid_size;
-  SID_NAME_USE sid_name_use;
-
-  BOOL success = ::LookupAccountNameW(NULL, account_name, sid,
-                                      &sid_dword_size, &domain_buffer.front(),
-                                      &domain_size, &sid_name_use);
-  if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
-    // We could have gotten the insufficient buffer error because
-    // one or both of sid and szDomain was too small. Check for that
-    // here.
-    if (sid_dword_size > sid_size)
-      return false;
-
-    if (domain_size > kStartDomainLength)
-      domain_buffer.resize(domain_size);
-
-    success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
-                                   &domain_buffer.front(), &domain_size,
-                                   &sid_name_use);
-  }
-
-  return success != FALSE;
-}
-
-std::vector<uint8_t> ConvertSidToBytes(SID* sid) {
-  std::wstring sid_string;
-#if _WIN32_WINNT >= 0x500
-  wchar_t* sid_buffer = NULL;
-  if (ConvertSidToStringSidW(sid, &sid_buffer)) {
-    sid_string = sid_buffer;
-    LocalFree(sid_buffer);
-  }
-#else
-  SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);
-
-  if(sia->Value[0] || sia->Value[1]) {
-    base::SStringPrintf(
-        &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
-        SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1],
-        (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4],
-        (USHORT)sia->Value[5]);
-  } else {
-    ULONG authority = 0;
-    for (int i = 2; i < 6; ++i) {
-      authority <<= 8;
-      authority |= sia->Value[i];
-    }
-    base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
-  }
-
-  int sub_auth_count = *::GetSidSubAuthorityCount(sid);
-  for(int i = 0; i < sub_auth_count; ++i)
-    base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i));
-#endif
-
-  // Get the contents of the string as a bunch of bytes.
-  return std::vector<uint8_t>(
-           reinterpret_cast<uint8_t*>(&sid_string[0]),
-           reinterpret_cast<uint8_t*>(&sid_string[sid_string.size()]));
-}
-
-}  // namespace
-
-bool GetRawMachineId(std::vector<uint8_t>* sid_bytes, int* volume_id) {
-  // Calculate the Windows SID.
-
-  wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
-  DWORD size = mozilla::ArrayLength(computer_name);
-
-  if (!GetComputerNameW(computer_name, &size)) {
-    return false;
-  }
-  char sid_buffer[SECURITY_MAX_SID_SIZE];
-  SID* sid = reinterpret_cast<SID*>(sid_buffer);
-  if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) {
-    *sid_bytes = ConvertSidToBytes(sid);
-  }
-
-  // Get the system drive volume serial number.
-  *volume_id = 0;
-  if (!GetSystemVolumeSerialNumber(volume_id)) {
-    ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
-    *volume_id = 0;
-  }
-
-  return true;
-}
-
-}  // namespace rlz_lib
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -150,22 +150,16 @@ WidevineAdapter::GMPShutdown()
   decltype(::DeinitializeCdmModule)* deinit;
   deinit = (decltype(deinit))(PR_FindFunctionSymbol(mLib, "DeinitializeCdmModule"));
   if (deinit) {
     Log("DeinitializeCdmModule()");
     deinit();
   }
 }
 
-void
-WidevineAdapter::GMPSetNodeId(const char* aNodeId, uint32_t aLength)
-{
-
-}
-
 /* static */
 bool
 WidevineAdapter::Supports(int32_t aModuleVersion,
                           int32_t aInterfaceVersion,
                           int32_t aHostVersion)
 {
   return aModuleVersion == CDM_MODULE_VERSION &&
          aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.h
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.h
@@ -21,17 +21,16 @@ public:
 
   // These are called in place of the corresponding GMP API functions.
   GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override;
   GMPErr GMPGetAPI(const char* aAPIName,
                    void* aHostAPI,
                    void** aPluginAPI,
                    uint32_t aDecryptorId) override;
   void GMPShutdown() override;
-  void GMPSetNodeId(const char* aNodeId, uint32_t aLength) override;
 
   static bool Supports(int32_t aModuleVersion,
                        int32_t aInterfaceVersion,
                        int32_t aHostVersion);
 
 private:
   PRLibrary* mLib = nullptr;
 };
@@ -46,14 +45,11 @@ GMPErr GMPCreateRecord(const char* aReco
                        GMPRecord** aOutRecord,
                        GMPRecordClient* aClient);
 
 // Call on main thread only.
 GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS);
 
 GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime);
 
-GMPErr GMPCreateRecordIterator(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
-                               void* aUserArg);
-
 } // namespace mozilla
 
 #endif // WidevineAdapter_h_
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -15,17 +15,16 @@
 #include "GMPServiceParent.h"
 #include "MediaPrefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/Atomics.h"
 #include "nsNSSComponent.h"
 #include "mozilla/DebugOnly.h"
-#include "GMPDeviceBinding.h"
 #include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus
 #include "mozilla/dom/MediaKeyMessageEventBinding.h" // For MediaKeyMessageType
 
 using namespace std;
 
 using namespace mozilla;
 using namespace mozilla::gmp;
 
@@ -1104,78 +1103,16 @@ class GMPStorageTest : public GMPDecrypt
 
     CreateDecryptor(NS_LITERAL_STRING("http://example15.com"),
                     NS_LITERAL_STRING("http://example16.com"),
                     false,
                     NS_LITERAL_CSTRING("test-op-apis"));
   }
 #endif
 
-  void TestGetRecordNamesInMemoryStorage() {
-    TestGetRecordNames(true);
-  }
-
-  nsCString mRecordNames;
-
-  void AppendIntPadded(nsACString& aString, uint32_t aInt) {
-    if (aInt > 0 && aInt < 10) {
-      aString.AppendLiteral("0");
-    }
-    aString.AppendInt(aInt);
-  }
-
-  void TestGetRecordNames(bool aPrivateBrowsing) {
-    // Create a number of records of different names.
-    const uint32_t num = 100;
-    nsTArray<nsCString> updates(num);
-    for (uint32_t i = 0; i < num; i++) {
-      nsAutoCString response;
-      response.AppendLiteral("stored data");
-      AppendIntPadded(response, i);
-      response.AppendLiteral(" test-data");
-      AppendIntPadded(response, i);
-
-      if (i != 0) {
-        mRecordNames.AppendLiteral(",");
-      }
-      mRecordNames.AppendLiteral("data");
-      AppendIntPadded(mRecordNames, i);
-
-      nsCString& update = *updates.AppendElement();
-      update.AppendLiteral("store data");
-      AppendIntPadded(update, i);
-      update.AppendLiteral(" test-data");
-      AppendIntPadded(update, i);
-
-      nsCOMPtr<nsIRunnable> continuation;
-      if (i + 1 == num) {
-        continuation =
-          NewRunnableMethod(this, &GMPStorageTest::TestGetRecordNames_QueryNames);
-      }
-      Expect(response, continuation.forget());
-    }
-
-    CreateDecryptor(NS_LITERAL_STRING("http://foo.com"),
-                    NS_LITERAL_STRING("http://bar.com"),
-                    aPrivateBrowsing,
-                    Move(updates));
-  }
-
-  void TestGetRecordNames_QueryNames() {
-    nsCString response("record-names ");
-    response.Append(mRecordNames);
-    Expect(response,
-           NewRunnableMethod(this, &GMPStorageTest::SetFinished));
-    Update(NS_LITERAL_CSTRING("retrieve-record-names"));
-  }
-
-  void GetRecordNamesPersistentStorage() {
-    TestGetRecordNames(false);
-  }
-
   void TestLongRecordNames() {
     NS_NAMED_LITERAL_CSTRING(longRecordName,
       "A_"
       "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
       "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
       "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
       "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
       "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
@@ -1207,34 +1144,16 @@ class GMPStorageTest : public GMPDecrypt
     update.AppendLiteral(" ");
     update.Append(data);
     CreateDecryptor(NS_LITERAL_STRING("http://fuz.com"),
                     NS_LITERAL_STRING("http://baz.com"),
                     false,
                     update);
   }
 
-  void TestNodeId() {
-    // Calculate the nodeId, and the device bound nodeId. Start a GMP, and
-    // have it return the device bound nodeId that it's been passed. Assert
-    // they have the same value.
-    const nsString origin = NS_LITERAL_STRING("http://example-fuz-baz.com");
-    nsCString originSalt1 = GetNodeId(origin, origin, false);
-
-    nsCString salt = originSalt1;
-    std::string nodeId;
-    EXPECT_TRUE(CalculateGMPDeviceId(salt.BeginWriting(), salt.Length(), nodeId));
-
-    std::string expected = "node-id " + nodeId;
-    Expect(nsDependentCString(expected.c_str()), NewRunnableMethod(this, &GMPStorageTest::SetFinished));
-
-    CreateDecryptor(originSalt1,
-                    NS_LITERAL_CSTRING("retrieve-node-id"));
-  }
-
   void Expect(const nsCString& aMessage, already_AddRefed<nsIRunnable> aContinuation) {
     mExpected.AppendElement(ExpectedMessage(aMessage, Move(aContinuation)));
   }
 
   void AwaitFinished() {
     while (!mFinished) {
       NS_ProcessNextEvent(nullptr, true);
     }
@@ -1420,27 +1339,12 @@ TEST(GeckoMediaPlugins, GMPStoragePrivat
 
 #if defined(XP_WIN)
 TEST(GeckoMediaPlugins, GMPOutputProtection) {
   RefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestOutputProtection);
 }
 #endif
 
-TEST(GeckoMediaPlugins, GMPStorageGetRecordNamesInMemoryStorage) {
-  RefPtr<GMPStorageTest> runner = new GMPStorageTest();
-  runner->DoTest(&GMPStorageTest::TestGetRecordNamesInMemoryStorage);
-}
-
-TEST(GeckoMediaPlugins, GMPStorageGetRecordNamesPersistentStorage) {
-  RefPtr<GMPStorageTest> runner = new GMPStorageTest();
-  runner->DoTest(&GMPStorageTest::GetRecordNamesPersistentStorage);
-}
-
 TEST(GeckoMediaPlugins, GMPStorageLongRecordNames) {
   RefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestLongRecordNames);
 }
-
-TEST(GeckoMediaPlugins, GMPNodeId) {
-  RefPtr<GMPStorageTest> runner = new GMPStorageTest();
-  runner->DoTest(&GMPStorageTest::TestNodeId);
-}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -70,12 +70,8 @@ LOCAL_INCLUDES += [
     '/security/certverifier',
     '/security/pkix/include',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
-
-USE_LIBS += [
-   'rlz',
-]
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -41,20 +41,16 @@
 #include "AgnosticDecoderModule.h"
 #include "EMEDecoderModule.h"
 
 #include "DecoderDoctorDiagnostics.h"
 
 #include "MP4Decoder.h"
 #include "mozilla/dom/RemoteVideoDecoder.h"
 
-#ifdef XP_WIN
-#include "mozilla/WindowsVersion.h"
-#endif
-
 #include "mp4_demuxer/H264.h"
 
 #include <functional>
 
 namespace mozilla {
 
 extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
 extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
@@ -363,24 +359,17 @@ PDMFactory::CreatePDMs()
 #ifdef MOZ_WIDGET_ANDROID
   if(MediaPrefs::PDMAndroidMediaCodecPreferred() &&
      MediaPrefs::PDMAndroidMediaCodecEnabled()) {
     m = new AndroidDecoderModule();
     StartupPDM(m);
   }
 #endif
 #ifdef XP_WIN
-  if (MediaPrefs::PDMWMFEnabled() && IsVistaOrLater()) {
-    // *Only* use WMF on Vista and later, as if Firefox is run in Windows 95
-    // compatibility mode on Windows 7 (it does happen!) we may crash trying
-    // to startup WMF. So we need to detect the OS version here, as in
-    // compatibility mode IsVistaOrLater() and friends behave as if we're on
-    // the emulated version of Windows. See bug 1279171.
-    // Additionally, we don't want to start the RemoteDecoderModule if we
-    // expect it's not going to work (i.e. on Windows older than Vista).
+  if (MediaPrefs::PDMWMFEnabled()) {
     m = new WMFDecoderModule();
     RefPtr<PlatformDecoderModule> remote = new dom::RemoteDecoderModule(m);
     StartupPDM(remote);
     mWMFFailedToLoad = !StartupPDM(m);
   } else {
     mWMFFailedToLoad = MediaPrefs::DecoderDoctorWMFDisabledIsFailure();
   }
 #endif
--- a/dom/plugins/test/mochitest/test_bug1028200-1.html
+++ b/dom/plugins/test/mochitest/test_bug1028200-1.html
@@ -40,18 +40,22 @@
      * screen element - and therefore exit out of the fullscreen element.
      */
     let load = function testCrashChildPlugin_expectFullScreenElementToBeCancelled() {
       add_task(function* () {
         /* Needed to be able to programatically (without user interaction) enter
          * fullscreen  (has been deemed a security issue otherwise and therefore
          * disabled by default)
          */
-        yield SpecialPowers.pushPrefEnv(
-            { "set": [ ["full-screen-api.allow-trusted-requests-only", false] ] });
+        yield SpecialPowers.pushPrefEnv({
+          "set": [
+            ["full-screen-api.allow-trusted-requests-only", false],
+            ["full-screen-api.unprefix.enabled", true],
+          ],
+        });
       });
 
       add_task(function* () {
         let fullScreenElement = document.getElementById('div1');
         let plugin = document.getElementById('iframe1')
           .contentDocument.getElementById('iframe2')
           .contentDocument.getElementById('plugin1');
 
--- a/dom/plugins/test/mochitest/test_bug1028200-2.html
+++ b/dom/plugins/test/mochitest/test_bug1028200-2.html
@@ -40,18 +40,22 @@
      * screen element - and therefore remain in the fullscreen element.
      */
     let load = function testCrashChildPlugin_expectFullScreenElementToRemain() {
       add_task(function* () {
         /* Needed to be able to programatically (without user interaction) enter
          * fullscreen  (has been deemed a security issue otherwise and therefore
          * disabled by default)
          */
-        yield SpecialPowers.pushPrefEnv(
-            { "set": [ ["full-screen-api.allow-trusted-requests-only", false] ] });
+        yield SpecialPowers.pushPrefEnv({
+          "set": [
+            ["full-screen-api.allow-trusted-requests-only", false],
+            ["full-screen-api.unprefix.enabled", true],
+          ],
+        });
       });
 
       add_task(function* () {
         let fullScreenElement = document.getElementById('div1');
         let plugin = document.getElementById('plugin1');
 
         let fullScreenChange = promiseFullScreenChange();
         fullScreenElement.mozRequestFullScreen();
--- a/dom/tests/mochitest/ajax/offline/offlineTests.js
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -47,17 +47,18 @@ fetch: function(callback)
     callback(this.contents);
     return;
   }
 
   var url = this.urls.shift();
   var self = this;
 
   var cacheStorage = OfflineTest.getActiveStorage();
-  cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, this);
+  cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY,
+                            SpecialPowers.wrapCallbackObject(this));
 }
 };
 
 var OfflineTest = {
 
 _allowedByDefault: false,
 
 _hasSlave: false,
@@ -91,18 +92,16 @@ setupChild: function()
  * Setup the tests.  This will reload the current page in a new window
  * if necessary.
  *
  * @return boolean Whether this window is the slave window
  *                 to actually run the test in.
  */
 setup: function()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
   try {
     this._allowedByDefault = SpecialPowers.getBoolPref("offline-apps.allow_by_default");
   } catch (e) {}
 
   if (this._allowedByDefault) {
     this._masterWindow = window;
 
     return true;
@@ -251,33 +250,33 @@ failEvent: function(e)
 },
 
 // The offline API as specified has no way to watch the load of a resource
 // added with applicationCache.mozAdd().
 waitForAdd: function(url, onFinished) {
   // Check every half second for ten seconds.
   var numChecks = 20;
 
-  var waitForAddListener = {
+  var waitForAddListener = SpecialPowers.wrapCallbackObject({
     onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
     onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
       if (entry) {
         entry.close();
         onFinished();
         return;
       }
 
       if (--numChecks == 0) {
         onFinished();
         return;
       }
 
       setTimeout(OfflineTest.priv(waitFunc), 500);
     }
-  };
+  });
 
   var waitFunc = function() {
     var cacheStorage = OfflineTest.getActiveStorage();
     cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, waitForAddListener);
   }
 
   setTimeout(this.priv(waitFunc), 500);
 },
@@ -375,17 +374,17 @@ checkCache: function(url, expectEntry, c
       this.ok(false, url + " should exist in the offline cache (no session)");
     } else {
       this.ok(true, url + " should not exist in the offline cache (no session)");
     }
     if (callback) setTimeout(this.priv(callback), 0);
     return;
   }
 
-  var _checkCacheListener = {
+  var _checkCacheListener = SpecialPowers.wrapCallbackObject({
     onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
     onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
       if (entry) {
         if (expectEntry) {
           OfflineTest.ok(true, url + " should exist in the offline cache");
         } else {
           OfflineTest.ok(false, url + " should not exist in the offline cache");
         }
@@ -405,17 +404,17 @@ checkCache: function(url, expectEntry, c
             OfflineTest.ok(mustBeValid, url + " should not exist in the offline cache");
           }
         } else {
           OfflineTest.ok(false, "got invalid error for " + url);
         }
       }
       if (callback) setTimeout(OfflineTest.priv(callback), 0);
     }
-  };
+  });
 
   cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, _checkCacheListener);
 },
 
 setSJSState: function(sjsPath, stateQuery)
 {
   var client = new XMLHttpRequest();
   client.open("GET", sjsPath + "?state=" + stateQuery, false);
--- a/dom/tests/mochitest/ajax/offline/test_fallback.html
+++ b/dom/tests/mochitest/ajax/offline/test_fallback.html
@@ -96,18 +96,16 @@ function onFallbackLoad(fallbackIdentifi
 
 function finishTest()
 {
   OfflineTest.teardownAndFinish();
 }
 
 function finalize()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
   var entries = [
     ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/sub-non-existing.html", false],
     ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/sub/non-existing.html", false],
     ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/non-existing.html", false],
     ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace2/non-existing.html", false]
   ];
   OfflineTest.checkCacheEntries(entries, finishTest);
 }
--- a/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html
+++ b/dom/tests/mochitest/ajax/offline/test_lowDeviceStorage.html
@@ -35,17 +35,17 @@ function finish() {
   obs.notifyObservers(updateService, "disk-space-watcher", "free");
 
   OfflineTest.teardownAndFinish();
 }
 
 if (OfflineTest.setup()) {
   obs.notifyObservers(updateService, "disk-space-watcher", "full");
 
-  var updateObserver = {
+  var updateObserver = SpecialPowers.wrapCallbackObject({
     updateStateChanged: function (aUpdate, aState) {
       switch(aState) {
         case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
           errorReceived = true;
           OfflineTest.ok(true, "Expected error. Update canceled");
         break;
         case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
           aUpdate.removeObserver(this);
@@ -63,17 +63,17 @@ if (OfflineTest.setup()) {
         case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
           aUpdate.removeObserver(this);
           OfflineTest.ok(false, "The update was supposed to be canceled");
           finish();
           break;
       }
     },
     applicationCacheAvailable: function() {}
-  };
+  });
 
   var manifest = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest";
   var ioService = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
   var manifestURI = ioService.newURI(manifest, null, null);
   var documentURI = ioService.newURI(document.documentURI, null, null);
   var update = updateService.scheduleUpdate(manifestURI, documentURI, systemPrincipal, window);
   update.addObserver(updateObserver, false);
--- a/dom/tests/mochitest/ajax/offline/test_updateCheck.html
+++ b/dom/tests/mochitest/ajax/offline/test_updateCheck.html
@@ -29,55 +29,55 @@ var manifestURI = Cc["@mozilla.org/netwo
 var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
                     .getService(Ci.nsIOfflineCacheUpdateService);
 
 var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal();
 
 function manifestCached()
 {
   // Run first check for an update
-  updateService.checkForUpdate(manifestURI, systemPrincipal, {
+  updateService.checkForUpdate(manifestURI, systemPrincipal, SpecialPowers.wrapCallbackObject({
     observe: function(subject, topic, data) {
       OfflineTest.is(topic, "offline-cache-update-unavailable", "No update avail");
 
       // Change the manifest content
       OfflineTest.setSJSState(manifest, "second");
 
       // Check we now get notification on update ready
-      updateService.checkForUpdate(manifestURI, systemPrincipal, {
+      updateService.checkForUpdate(manifestURI, systemPrincipal, SpecialPowers.wrapCallbackObject({
         observe: function(subject, topic, data) {
           OfflineTest.is(topic, "offline-cache-update-available", "Update avail (1)");
 
           // Do the check again.  We must get the same result.  Double check is here
           // to make sure we don't overwrite any data in the cache by the check it self.
-          updateService.checkForUpdate(manifestURI, systemPrincipal, {
+          updateService.checkForUpdate(manifestURI, systemPrincipal, SpecialPowers.wrapCallbackObject({
             observe: function(subject, topic, data) {
               OfflineTest.is(topic, "offline-cache-update-available", "Update avail (2)");
 
               // Update the manifest, invokes manifestUpdated()
               applicationCache.onupdateready = OfflineTest.priv(manifestUpdated);
               applicationCache.update();
             }
-          });
+          }));
         }
-      });
+      }));
     }
-  });
+  }));
 }
 
 function manifestUpdated()
 {
   // Check for an update after manifest has been updated
-  updateService.checkForUpdate(manifestURI, systemPrincipal, {
+  updateService.checkForUpdate(manifestURI, systemPrincipal, SpecialPowers.wrapCallbackObject({
     observe: function(subject, topic, data) {
       OfflineTest.is(topic, "offline-cache-update-unavailable", "No update avail (2)");
 
       OfflineTest.teardownAndFinish();
     }
-  });
+  }));
 }
 
 if (OfflineTest.setup()) {
   applicationCache.onerror = OfflineTest.failEvent;
   applicationCache.oncached = OfflineTest.priv(manifestCached);
 }
 
 </script>
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -1095,17 +1095,19 @@ nsXMLContentSink::HandleEndElement(const
     }
     mNotifyLevel = stackLen - 1;
   }
   DidAddContent();
 
   if (content->IsSVGElement(nsGkAtoms::svg)) {
     FlushTags();
     nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
-    if (NS_FAILED(NS_DispatchToMainThread(event))) {
+    if (NS_FAILED(content->OwnerDoc()->Dispatch("nsHtml5SVGLoadDispatcher",
+                                                TaskCategory::Other,
+                                                event.forget()))) {
       NS_WARNING("failed to dispatch svg load dispatcher");
     }
   }
 
   return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
                                                   result;
 }
 
--- a/ipc/app/moz.build
+++ b/ipc/app/moz.build
@@ -22,26 +22,16 @@ else:
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/toolkit/xre',
     '/xpcom/base',
 ]
 
-# We link GMPLoader into plugin-container on desktop so that its code is
-# covered by the desktop DRM vendor's voucher.
-if CONFIG['OS_ARCH'] != 'Linux':
-    SOURCES += [
-        '../../dom/media/gmp/GMPLoader.cpp',
-    ]
-    USE_LIBS += [
-        'rlz',
-    ]
-
 # DELAYLOAD_DLLS in this block ensures that the DLL blocklist is functional
 if CONFIG['OS_ARCH'] == 'WINNT':
     DELAYLOAD_DLLS += [
         'nss3.dll',
     ]
 
     if CONFIG['MOZ_SANDBOX']:
         # For sandbox includes and the include dependencies those have
--- a/ipc/contentproc/plugin-container.cpp
+++ b/ipc/contentproc/plugin-container.cpp
@@ -16,66 +16,21 @@
 #define XRE_DONT_PROTECT_DLL_LOAD
 #include "nsWindowsWMain.cpp"
 #include "nsSetDllDirectory.h"
 #else
 // FIXME/cjones testing
 #include <unistd.h>
 #endif
 
-#include "GMPLoader.h"
-
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "mozilla/sandboxing/SandboxInitialization.h"
 #include "mozilla/sandboxing/sandboxLogging.h"
 #endif
 
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-class WinSandboxStarter : public mozilla::gmp::SandboxStarter {
-public:
-    virtual bool Start(const char *aLibPath) override {
-        if (IsSandboxedProcess()) {
-            mozilla::sandboxing::LowerSandbox();
-        }
-        return true;
-    }
-};
-#endif
-
-#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-class MacSandboxStarter : public mozilla::gmp::SandboxStarter {
-public:
-    bool Start(const char *aLibPath) override {
-      std::string err;
-      bool rv = mozilla::StartMacSandbox(mInfo, err);
-      if (!rv) {
-        fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
-      }
-      return rv;
-    }
-    void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override {
-      mInfo = *aSandboxInfo;
-    }
-private:
-  MacSandboxInfo mInfo;
-};
-#endif
-
-mozilla::UniquePtr<mozilla::gmp::SandboxStarter>
-MakeSandboxStarter()
-{
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
-    return mozilla::MakeUnique<WinSandboxStarter>();
-#elif defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-    return mozilla::MakeUnique<MacSandboxStarter>();
-#else
-    return nullptr;
-#endif
-}
-
 int
 content_process_main(mozilla::Bootstrap* bootstrap, int argc, char* argv[])
 {
     // Check for the absolute minimum number of args we need to move
     // forward here. We expect the last arg to be the child process type.
     if (argc < 1) {
       return 3;
     }
@@ -100,18 +55,12 @@ content_process_main(mozilla::Bootstrap*
     // For plugins, this is done in PluginProcessChild::Init, as we need to
     // avoid it for unsupported plugins.  See PluginProcessChild::Init for
     // the details.
     if (bootstrap->XRE_GetProcessType() != GeckoProcessType_Plugin) {
         mozilla::SanitizeEnvironmentVariables();
         SetDllDirectoryW(L"");
     }
 #endif
-#if !defined(XP_LINUX) && defined(MOZ_PLUGIN_CONTAINER)
-    // On Windows and MacOS, the GMPLoader lives in plugin-container, so that its
-    // code can be covered by an EME/GMP vendor's voucher.
-    if (bootstrap->XRE_GetProcessType() == GeckoProcessType_GMPlugin) {
-        childData.gmpLoader = mozilla::gmp::CreateGMPLoader(MakeSandboxStarter());
-    }
-#endif
+
     nsresult rv = bootstrap->XRE_InitChildProcess(argc, argv, &childData);
     return NS_FAILED(rv);
 }
--- a/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c
@@ -44,16 +44,17 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "ice_util.h"
 #include "nr_crypto.h"
 #include "async_timer.h"
 #include "ice_reg.h"
 
 static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
 static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct);
 static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate);
+static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx);
 
 int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp)
   {
     int r,_status;
     nr_ice_peer_ctx *pctx=0;
 
     if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx))))
       ABORT(R_NO_MEMORY);
@@ -305,16 +306,22 @@ int nr_ice_peer_ctx_parse_trickle_candid
        just re-pair the stream which is inefficient but still
        fine because we suppress duplicate pairing */
     if (needs_pairing) {
       if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label);
         ABORT(r);
       }
 
+      /* Start the remote trickle grace timeout if it hasn't been started by
+         another trickled candidate or from the SDP. */
+      if (!pctx->trickle_grace_period_timer) {
+        nr_ice_peer_ctx_start_trickle_timer(pctx);
+      }
+
       /* Start checks if this stream is not checking yet or if it has checked
          all the available candidates but not had a completed check for all
          components.
 
          Note that this is not compliant with RFC 5245, but consistent with
          the libjingle trickle ICE behavior. Note that we will not restart
          checks if either (a) the stream has failed or (b) all components
          have a successful pair because the switch statement above jumps
@@ -396,19 +403,16 @@ int nr_ice_peer_ctx_pair_candidates(nr_i
         r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label);
         ABORT(R_FAILED);
     }
 
     /* Set this first; if we fail partway through, we do not want to end
      * up in UNPAIRED after creating some pairs. */
     pctx->state = NR_ICE_PEER_STATE_PAIRED;
 
-    /* Start grace period timer for incoming trickle candidates */
-    nr_ice_peer_ctx_start_trickle_timer(pctx);
-
     stream=STAILQ_FIRST(&pctx->peer_streams);
     while(stream){
       if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
         stream))
         ABORT(r);
 
       stream=STAILQ_NEXT(stream,entry);
     }
@@ -427,16 +431,22 @@ int nr_ice_peer_ctx_pair_new_trickle_can
 
     r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label);
     if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream)))
       ABORT(r);
 
     if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand)))
       ABORT(r);
 
+    /* Start the remote trickle grace timeout if it hasn't been started
+       already. */
+    if (!pctx->trickle_grace_period_timer) {
+      nr_ice_peer_ctx_start_trickle_timer(pctx);
+    }
+
     _status=0;
  abort:
     return _status;
   }
 
 int nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *lstream, int component_id)
   {
     int r, _status;
@@ -603,16 +613,20 @@ int nr_ice_peer_ctx_start_checks2(nr_ice
 
       stream=STAILQ_NEXT(stream, entry);
     }
 
     if (!started) {
       r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): peer (%s) no checks to start",pctx->ctx->label,pctx->label);
       ABORT(R_NOT_FOUND);
     }
+    else {
+      /* Start grace period timer for more remote trickle candidates. */
+      nr_ice_peer_ctx_start_trickle_timer(pctx);
+    }
 
     _status=0;
   abort:
     return(_status);
   }
 
 void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
   {
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -593,16 +593,22 @@ public class BrowserApp extends GeckoApp
             // This build does not support the Android version of the device; Exit early.
             super.onCreate(savedInstanceState);
             return;
         }
 
         final SafeIntent intent = new SafeIntent(getIntent());
         final boolean isInAutomation = IntentUtils.getIsInAutomationFromEnvironment(intent);
 
+        if (!isInAutomation && AppConstants.MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE) {
+            // Kick off download of app content as early as possible so that in the best case it's
+            // available before the user starts using the browser.
+            DownloadContentService.startStudy(this);
+        }
+
         // This has to be prepared prior to calling GeckoApp.onCreate, because
         // widget code and BrowserToolbar need it, and they're created by the
         // layout, which GeckoApp takes care of.
         ((GeckoApplication) getApplication()).prepareLightweightTheme();
 
         super.onCreate(savedInstanceState);
 
         final Context appContext = getApplicationContext();
@@ -1765,18 +1771,19 @@ public class BrowserApp extends GeckoApp
                     // Start (this acts as ping if started already) the stumbler lib; if
                     // the stumbler has queued data it will upload it.  Stumbler operates
                     // on its own thread, and startup impact is further minimized by
                     // delaying work (such as upload) a few seconds.  Avoid any potential
                     // startup CPU/thread contention by delaying the pref broadcast.
                     GeckoPreferences.broadcastStumblerPref(BrowserApp.this);
                 }
 
-                if (AppConstants.MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE) {
-                    // TODO: Better scheduling of sync action (Bug 1257492)
+                if (AppConstants.MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE &&
+                        !IntentUtils.getIsInAutomationFromEnvironment(new SafeIntent(getIntent()))) {
+                    // TODO: Better scheduling of DLC actions (Bug 1257492)
                     DownloadContentService.startSync(this);
                     DownloadContentService.startVerification(this);
                 }
 
                 FeedService.setup(this);
                 break;
 
             case "Menu:Open":
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -186,20 +186,16 @@ public class GeckoApplication extends Ap
                     } catch (Exception e) {
                         Log.e(LOG_TAG, "Got exception during startup; ignoring.", e);
                         return;
                     }
                 }
             });
         }
 
-        if (AppConstants.MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE) {
-            DownloadContentService.startStudy(this);
-        }
-
         GeckoAccessibility.setAccessibilityManagerListeners(this);
 
         AudioFocusAgent.getInstance().attachToContext(this);
     }
 
     private class EventListener implements BundleEventListener
     {
         private void onProfileCreate(final String name, final String path) {
--- a/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContent.java
+++ b/mobile/android/base/java/org/mozilla/gecko/dlc/catalog/DownloadContent.java
@@ -5,16 +5,18 @@
 
 package org.mozilla.gecko.dlc.catalog;
 
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.StringDef;
 
+import org.mozilla.gecko.AppConstants;
+
 public class DownloadContent {
     @IntDef({STATE_NONE, STATE_SCHEDULED, STATE_DOWNLOADED, STATE_FAILED, STATE_UPDATED, STATE_DELETED})
     public @interface State {}
     public static final int STATE_NONE = 0;
     public static final int STATE_SCHEDULED = 1;
     public static final int STATE_DOWNLOADED = 2;
     public static final int STATE_FAILED = 3; // Permanently failed for this version of the content
     public static final int STATE_UPDATED = 4;
@@ -132,17 +134,17 @@ public class DownloadContent {
     }
 
     /**
      *Checks whether the content to be downloaded is a known content.
      *Currently it checks whether the type is "Asset Archive" and is of kind
      *"Font" or "Hyphenation Dictionary".
      */
     public boolean isKnownContent() {
-        return ((isFont() || isHyphenationDictionary()) && isAssetArchive());
+        return (((isFont() && AppConstants.MOZ_ANDROID_EXCLUDE_FONTS) || (isHyphenationDictionary() && AppConstants.MOZ_EXCLUDE_HYPHENATION_DICTIONARIES)) && isAssetArchive());
     }
 
     public boolean isAssetArchive() {
         return TYPE_ASSET_ARCHIVE.equals(type);
     }
 
     /* package-private */ int getFailures() {
         return failures;
--- a/mobile/android/base/java/org/mozilla/gecko/home/BookmarksListAdapter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BookmarksListAdapter.java
@@ -57,39 +57,42 @@ class BookmarksListAdapter extends Multi
                 return new RefreshType[size];
             }
         };
     }
 
     public static class FolderInfo implements Parcelable {
         public final int id;
         public final String title;
+        public final int position;
 
         public FolderInfo(int id) {
-            this(id, "");
+            this(id, "", 0);
         }
 
         public FolderInfo(Parcel in) {
-            this(in.readInt(), in.readString());
+            this(in.readInt(), in.readString(), in.readInt());
         }
 
-        public FolderInfo(int id, String title) {
+        public FolderInfo(int id, String title, int position) {
             this.id = id;
             this.title = title;
+            this.position = position;
         }
 
         @Override
         public int describeContents() {
             return 0;
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(id);
             dest.writeString(title);
+            dest.writeInt(position);
         }
 
         public static final Creator<FolderInfo> CREATOR = new Creator<FolderInfo>() {
             @Override
             public FolderInfo createFromParcel(Parcel in) {
                 return new FolderInfo(in);
             }
 
@@ -99,17 +102,19 @@ class BookmarksListAdapter extends Multi
             }
         };
     }
 
     // A listener that knows how to refresh the list for a given folder id.
     // This is usually implemented by the enclosing fragment/activity.
     public static interface OnRefreshFolderListener {
         // The folder id to refresh the list with.
-        public void onRefreshFolder(FolderInfo folderInfo, RefreshType refreshType);
+        public void onRefreshFolder(FolderInfo folderInfo,
+                                    RefreshType refreshType,
+                                    int targetPosition);
     }
 
     /**
      * The type of data a bookmarks folder can display. This can be used to
      * distinguish bookmark folders from "smart folders" that contain non-bookmark
      * entries but still appear in the Bookmarks panel.
      */
     public enum FolderType {
@@ -159,35 +164,38 @@ class BookmarksListAdapter extends Multi
         // If we're already at the root, we can't move to a parent folder.
         // An empty parent stack here means we're still waiting for the
         // initial list of bookmarks and can't go to a parent folder.
         if (mParentStack.size() <= 1) {
             return false;
         }
 
         if (mListener != null) {
+            int targetPosition = mParentStack.peek().position;
             // We pick the second folder in the stack as it represents
             // the parent folder.
-            mListener.onRefreshFolder(mParentStack.get(1), RefreshType.PARENT);
+            mListener.onRefreshFolder(mParentStack.get(1), RefreshType.PARENT, targetPosition);
         }
 
         return true;
     }
 
     /**
      * Moves to child folder, given a folderId.
      *
      * @param folderId The id of the folder to show.
      * @param folderTitle The title of the folder to show.
+     * @param position The current position of the list view, which
+     *                 will be restored when moving back up one level.
      */
-    public void moveToChildFolder(int folderId, String folderTitle) {
-        FolderInfo folderInfo = new FolderInfo(folderId, folderTitle);
+    public void moveToChildFolder(int folderId, String folderTitle, int position) {
+        FolderInfo folderInfo = new FolderInfo(folderId, folderTitle, position);
 
         if (mListener != null) {
-            mListener.onRefreshFolder(folderInfo, RefreshType.CHILD);
+            mListener.onRefreshFolder(folderInfo, RefreshType.CHILD, 0 /* scroll to top of list */);
         }
     }
 
     /**
      * Set a listener that can refresh this adapter.
      *
      * @param listener The listener that can refresh the adapter.
      */
@@ -254,17 +262,17 @@ class BookmarksListAdapter extends Multi
         // Default to returning normal item type.
         return VIEW_TYPE_BOOKMARK_ITEM;
     }
 
     /**
      * Get the title of the folder given a cursor moved to the position.
      *
      * @param context The context of the view.
-     * @param cursor A cursor moved to the required position.
+     * @param c A cursor moved to the required position.
      * @return The title of the folder at the position.
      */
     public String getFolderTitle(Context context, Cursor c) {
         String guid = c.getString(c.getColumnIndexOrThrow(Bookmarks.GUID));
 
         // If we don't have a special GUID, just return the folder title from the DB.
         if (guid == null || guid.length() == 12) {
             return c.getString(c.getColumnIndexOrThrow(Bookmarks.TITLE));
--- a/mobile/android/base/java/org/mozilla/gecko/home/BookmarksListView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BookmarksListView.java
@@ -149,17 +149,17 @@ public class BookmarksListView extends H
             return;
         }
 
         int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE));
         if (type == Bookmarks.TYPE_FOLDER) {
             // If we're clicking on a folder, update adapter to move to that folder
             final int folderId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
             final String folderTitle = adapter.getFolderTitle(parent.getContext(), cursor);
-            adapter.moveToChildFolder(folderId, folderTitle);
+            adapter.moveToChildFolder(folderId, folderTitle, getFirstVisiblePosition());
 
             final List<BookmarksListAdapter.FolderInfo> parentStack = ((BookmarksListAdapter) getAdapter()).getParentStack();
 
             final int baseFolderID;
             if (parentStack.size() > 2) {
                 baseFolderID = parentStack.get(parentStack.size() - 2).id;
             } else {
                 baseFolderID = Bookmarks.FIXED_ROOT_ID;
--- a/mobile/android/base/java/org/mozilla/gecko/home/BookmarksPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BookmarksPanel.java
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
-import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.distribution.PartnerBookmarksProviderProxy;
 import org.mozilla.gecko.home.BookmarksListAdapter.FolderInfo;
 import org.mozilla.gecko.home.BookmarksListAdapter.OnRefreshFolderListener;
@@ -25,17 +24,16 @@ import org.mozilla.gecko.preferences.Gec
 
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.Cursor;
 import android.database.MergeCursor;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.support.annotation.NonNull;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.Loader;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.widget.ImageView;
@@ -51,16 +49,19 @@ public class BookmarksPanel extends Home
     private static final int LOADER_ID_BOOKMARKS_LIST = 0;
 
     // Information about the target bookmarks folder.
     private static final String BOOKMARKS_FOLDER_INFO = "folder_info";
 
     // Refresh type for folder refreshing loader.
     private static final String BOOKMARKS_REFRESH_TYPE = "refresh_type";
 
+    // Position that the list view should be scrolled to after loading has finished.
+    private static final String BOOKMARKS_SCROLL_POSITION = "listview_position";
+
     // List of bookmarks.
     private BookmarksListView mList;
 
     // Adapter for list of bookmarks.
     private BookmarksListAdapter mListAdapter;
 
     // Adapter's parent stack.
     private List<FolderInfo> mSavedParentStack;
@@ -134,21 +135,24 @@ public class BookmarksPanel extends Home
         super.onActivityCreated(savedInstanceState);
 
         final Activity activity = getActivity();
 
         // Setup the list adapter.
         mListAdapter = new BookmarksListAdapter(activity, null, mSavedParentStack);
         mListAdapter.setOnRefreshFolderListener(new OnRefreshFolderListener() {
             @Override
-            public void onRefreshFolder(FolderInfo folderInfo, RefreshType refreshType) {
+            public void onRefreshFolder(FolderInfo folderInfo,
+                                        RefreshType refreshType ,
+                                        int targetPosition) {
                 // Restart the loader with folder as the argument.
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(BOOKMARKS_FOLDER_INFO, folderInfo);
                 bundle.putParcelable(BOOKMARKS_REFRESH_TYPE, refreshType);
+                bundle.putInt(BOOKMARKS_SCROLL_POSITION, targetPosition);
                 getLoaderManager().restartLoader(LOADER_ID_BOOKMARKS_LIST, bundle, mLoaderCallbacks);
             }
         });
         mList.setAdapter(mListAdapter);
 
         // Create callbacks before the initial loader is started.
         mLoaderCallbacks = new CursorLoaderCallbacks();
         loadIfVisible();
@@ -204,28 +208,33 @@ public class BookmarksPanel extends Home
     }
 
     /**
      * Loader for the list for bookmarks.
      */
     private static class BookmarksLoader extends SimpleCursorLoader {
         private final FolderInfo mFolderInfo;
         private final RefreshType mRefreshType;
+        private final int mTargetPosition;
         private final BrowserDB mDB;
 
         public BookmarksLoader(Context context) {
             this(context,
-                 new FolderInfo(Bookmarks.FIXED_ROOT_ID, context.getResources().getString(R.string.bookmarks_title)),
-                 RefreshType.CHILD);
+                 new FolderInfo(Bookmarks.FIXED_ROOT_ID, context.getResources().getString(R.string.bookmarks_title), 0),
+                 RefreshType.CHILD, 0);
         }
 
-        public BookmarksLoader(Context context, FolderInfo folderInfo, RefreshType refreshType) {
+        public BookmarksLoader(Context context,
+                               FolderInfo folderInfo,
+                               RefreshType refreshType,
+                               int targetPosition) {
             super(context);
             mFolderInfo = folderInfo;
             mRefreshType = refreshType;
+            mTargetPosition = targetPosition;
             mDB = BrowserDB.from(context);
         }
 
         @Override
         public Cursor loadCursor() {
             final boolean isRootFolder = mFolderInfo.id == BrowserContract.Bookmarks.FIXED_ROOT_ID;
 
             final ContentResolver contentResolver = getContext().getContentResolver();
@@ -264,30 +273,35 @@ public class BookmarksPanel extends Home
 
         public FolderInfo getFolderInfo() {
             return mFolderInfo;
         }
 
         public RefreshType getRefreshType() {
             return mRefreshType;
         }
+
+        public int getTargetPosition() {
+            return mTargetPosition;
+        }
     }
 
     /**
      * Loader callbacks for the LoaderManager of this fragment.
      */
     private class CursorLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
         @Override
         public Loader<Cursor> onCreateLoader(int id, Bundle args) {
             if (args == null) {
                 return new BookmarksLoader(getActivity());
             } else {
                 FolderInfo folderInfo = (FolderInfo) args.getParcelable(BOOKMARKS_FOLDER_INFO);
                 RefreshType refreshType = (RefreshType) args.getParcelable(BOOKMARKS_REFRESH_TYPE);
-                return new BookmarksLoader(getActivity(), folderInfo, refreshType);
+                final int targetPosition = args.getInt(BOOKMARKS_SCROLL_POSITION);
+                return new BookmarksLoader(getActivity(), folderInfo, refreshType, targetPosition);
             }
         }
 
         @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
             BookmarksLoader bl = (BookmarksLoader) loader;
             mListAdapter.swapCursor(c, bl.getFolderInfo(), bl.getRefreshType());
 
@@ -298,16 +312,20 @@ public class BookmarksPanel extends Home
                 // Bundle likes to store ArrayLists or Arrays, but we've got a generic List (which
                 // is actually an unmodifiable wrapper around a LinkedList). We'll need to do a
                 // LinkedList conversion at the other end, when saving we need to use this awkward
                 // syntax to create an Array.
                 bundle.putParcelableArrayList("parentStack", new ArrayList<FolderInfo>(parentStack));
 
                 mPanelStateChangeListener.onStateChanged(bundle);
             }
+
+            if (mList != null) {
+                mList.setSelection(bl.getTargetPosition());
+            }
             updateUiFromCursor(c);
         }
 
         @Override
         public void onLoaderReset(Loader<Cursor> loader) {
             if (mList != null) {
                 mListAdapter.swapCursor(null);
             }
--- a/mobile/android/themes/core/config.css
+++ b/mobile/android/themes/core/config.css
@@ -38,17 +38,21 @@ body {
     height: 2em;
     border: 1px solid transparent;
     border-image-source: url("chrome://browser/skin/images/textfield.png");
     border-image-slice: 1 1 3 1;
     border-image-width: 1px 1px 3px 1px;
     overflow: hidden;
     display: flex;
     flex-direction: row;
-    float: inline-end;
+    float: right;
+}
+
+#filter-container:dir(rtl) {
+    float: left;
 }
 
 #filter-input {
     -moz-appearance: none;
     border: none;
     background-image: none;
     background-color: transparent;
     display: inline-block;
@@ -74,17 +78,21 @@ body {
 #new-pref-toggle-button {
     background-position: center center;
     background-image: url("chrome://browser/skin/images/config-plus.png");
     background-size: 48px 48px;
     height: 48px;
     width: 48px;
     display: inline-block;
     outline-style: none;
-    float: inline-start;
+    float: left;
+}
+
+#new-pref-toggle-button:dir(rtl) {
+    float: right;
 }
 
 #filter-search-button {
     background-image: url("chrome://browser/skin/images/search.png");
     background-size: 32px 32px;
     height: 32px;
     width: 32px;
     display: inline-block;
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -614,17 +614,19 @@ nsHtml5TreeOperation::DoneCreatingElemen
 {
   aNode->DoneCreatingElement();
 }
 
 void
 nsHtml5TreeOperation::SvgLoad(nsIContent* aNode)
 {
   nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
-  if (NS_FAILED(NS_DispatchToMainThread(event))) {
+  if (NS_FAILED(aNode->OwnerDoc()->Dispatch("nsHtml5SVGLoadDispatcher",
+                                            TaskCategory::Other,
+                                            event.forget()))) {
     NS_WARNING("failed to dispatch svg load dispatcher");
   }
 }
 
 void
 nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
 {
   nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
--- a/security/manager/pki/resources/content/certManager.js
+++ b/security/manager/pki/resources/content/certManager.js
@@ -329,18 +329,17 @@ function backupCerts()
   fp.init(window,
           bundle.getString("chooseP12BackupFileDialog"),
           nsIFilePicker.modeSave);
   fp.appendFilter(bundle.getString("file_browse_PKCS12_spec"),
                   "*.p12");
   fp.appendFilters(nsIFilePicker.filterAll);
   var rv = fp.show();
   if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
-    certdb.exportPKCS12File(null, fp.file, selected_certs.length,
-                            selected_certs);
+    certdb.exportPKCS12File(fp.file, selected_certs.length, selected_certs);
   }
 }
 
 function backupAllCerts()
 {
   // Select all rows, then call doBackup()
   var items = userTreeView.selection.selectAll();
   backupCerts();
@@ -394,17 +393,17 @@ function restoreCerts()
       let interfaceRequestor = {
         getInterface: function() {
           return prompter;
         }
       };
       certdb.importUserCertificate(dataArray, dataArray.length, interfaceRequestor);
     } else {
       // Otherwise, assume it's a PKCS12 file and import it that way.
-      certdb.importPKCS12File(null, fp.file);
+      certdb.importPKCS12File(fp.file);
     }
 
     var certcache = certdb.getCerts();
     userTreeView.loadCertsFromCache(certcache, nsIX509Cert.USER_CERT);
     userTreeView.selection.clearSelection();
     caTreeView.loadCertsFromCache(certcache, nsIX509Cert.CA_CERT);
     caTreeView.selection.clearSelection();
     enableBackupAllButton();
--- a/security/manager/ssl/nsIX509CertDB.idl
+++ b/security/manager/ssl/nsIX509CertDB.idl
@@ -185,38 +185,29 @@ interface nsIX509CertDB : nsISupports {
    *               be imported. See type constants in nsIX509Cert.
    */
   void importCertsFromFile(in nsIFile aFile,
                            in unsigned long aType);
 
   /**
    *  Import a PKCS#12 file containing cert(s) and key(s) into the database.
    *
-   *  @param aToken Optionally limits the scope of
-   *                this function to a token device.
-   *                Can be null to mean any token.
-   *  @param aFile Identifies a file that contains the data
-   *               to be imported.
+   *  @param aFile Identifies a file that contains the data to be imported.
    */
-  void importPKCS12File(in nsISupports aToken,
-                        in nsIFile aFile);
+  void importPKCS12File(in nsIFile aFile);
 
   /**
    *  Export a set of certs and keys from the database to a PKCS#12 file.
    *
-   *  @param aToken Optionally limits the scope of
-   *                this function to a token device.
-   *                Can be null to mean any token.
-   *  @param aFile Identifies a file that will be filled with the data
-   *               to be exported.
+   *  @param aFile Identifies a file that will be filled with the data to be
+   *               exported.
    *  @param count The number of certificates to be exported.
    *  @param aCerts The array of all certificates to be exported.
    */
-  void exportPKCS12File(in nsISupports aToken,
-                        in nsIFile aFile,
+  void exportPKCS12File(in nsIFile aFile,
                         in unsigned long count,
                         [array, size_is(count)] in nsIX509Cert aCerts);
 
   /*
    *  Decode a raw data presentation and instantiate an object in memory.
    *
    *  @param base64 The raw representation of a certificate,
    *                encoded as Base 64.
--- a/security/manager/ssl/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/nsNSSCertificateDB.cpp
@@ -27,17 +27,16 @@
 #include "nsIPrefService.h"
 #include "nsIPrompt.h"
 #include "nsNSSCertHelper.h"
 #include "nsNSSCertTrust.h"
 #include "nsNSSCertificate.h"
 #include "nsNSSComponent.h"
 #include "nsNSSHelper.h"
 #include "nsNSSShutDown.h"
-#include "nsPK11TokenDB.h"
 #include "nsPKCS12Blob.h"
 #include "nsPromiseFlatString.h"
 #include "nsProxyRelease.h"
 #include "nsReadableUtils.h"
 #include "nsThreadUtils.h"
 #include "nspr.h"
 #include "pkix/Time.h"
 #include "pkix/pkixnss.h"
@@ -960,57 +959,42 @@ nsNSSCertificateDB::ImportCertsFromFile(
       MOZ_ASSERT(false, "Unsupported type should have been filtered out");
       break;
   }
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
-nsNSSCertificateDB::ImportPKCS12File(nsISupports* aToken, nsIFile* aFile)
+nsNSSCertificateDB::ImportPKCS12File(nsIFile* aFile)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ENSURE_ARG(aFile);
   nsPKCS12Blob blob;
-  nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken);
-  if (token) {
-    blob.SetToken(token);
-  }
   return blob.ImportFromFile(aFile);
 }
 
 NS_IMETHODIMP
-nsNSSCertificateDB::ExportPKCS12File(nsISupports* aToken,
-                                     nsIFile* aFile,
-                                     uint32_t count,
+nsNSSCertificateDB::ExportPKCS12File(nsIFile* aFile, uint32_t count,
                                      nsIX509Cert** certs)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ENSURE_ARG(aFile);
+  if (count == 0) {
+    return NS_OK;
+  }
   nsPKCS12Blob blob;
-  if (count == 0) return NS_OK;
-  nsCOMPtr<nsIPK11Token> localRef;
-  if (!aToken) {
-    UniquePK11SlotInfo keySlot(PK11_GetInternalKeySlot());
-    if (!keySlot) {
-      return NS_ERROR_FAILURE;
-    }
-    localRef = new nsPK11Token(keySlot.get());
-  } else {
-    localRef = do_QueryInterface(aToken);
-  }
-  blob.SetToken(localRef);
   return blob.ExportToFile(aFile, certs, count);
 }
 
 NS_IMETHODIMP
 nsNSSCertificateDB::FindCertByEmailAddress(const char* aEmailAddress,
                                            nsIX509Cert** _retval)
 {
   nsNSSShutDownPreventionLock locker;
--- a/security/manager/ssl/nsPKCS12Blob.cpp
+++ b/security/manager/ssl/nsPKCS12Blob.cpp
@@ -2,30 +2,23 @@
  * 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 "nsPKCS12Blob.h"
 
 #include "ScopedNSSTypes.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Casting.h"
-#include "nsCRT.h"
-#include "nsCRTGlue.h"
-#include "nsDirectoryServiceDefs.h"
 #include "nsICertificateDialogs.h"
-#include "nsIDirectoryService.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
-#include "nsKeygenHandler.h" // For GetSlotWithMechanism
 #include "nsNSSCertificate.h"
 #include "nsNSSComponent.h"
 #include "nsNSSHelper.h"
-#include "nsNSSShutDown.h"
 #include "nsNetUtil.h"
-#include "nsPK11TokenDB.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "pkix/pkixtypes.h"
 #include "prmem.h"
 #include "prprf.h"
 #include "secerr.h"
 
@@ -38,97 +31,50 @@ extern LazyLogModule gPIPNSSLog;
 #define PIP_PKCS12_BACKUP_OK           2
 #define PIP_PKCS12_USER_CANCELED       3
 #define PIP_PKCS12_NOSMARTCARD_EXPORT  4
 #define PIP_PKCS12_RESTORE_FAILED      5
 #define PIP_PKCS12_BACKUP_FAILED       6
 #define PIP_PKCS12_NSS_ERROR           7
 
 // constructor
-nsPKCS12Blob::nsPKCS12Blob():mCertArray(nullptr),
-                             mTmpFile(nullptr),
-                             mTokenSet(false)
+nsPKCS12Blob::nsPKCS12Blob()
+  : mCertArray(nullptr)
+  , mTmpFile(nullptr)
 {
   mUIContext = new PipUIContext();
 }
 
 // destructor
 nsPKCS12Blob::~nsPKCS12Blob()
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return;
   }
 
   shutdown(ShutdownCalledFrom::Object);
 }
 
-// nsPKCS12Blob::SetToken
-//
-// Set the token to use for import/export
-nsresult
-nsPKCS12Blob::SetToken(nsIPK11Token *token)
-{
- nsNSSShutDownPreventionLock locker;
- if (isAlreadyShutDown()) {
-  return NS_ERROR_NOT_AVAILABLE;
- }
- nsresult rv = NS_OK;
- if (token) {
-   mToken = token;
- } else {
-   PK11SlotInfo *slot;
-   rv = GetSlotWithMechanism(CKM_RSA_PKCS, mUIContext, &slot, locker);
-   if (NS_FAILED(rv)) {
-      mToken = nullptr;
-   } else {
-     mToken = new nsPK11Token(slot);
-     PK11_FreeSlot(slot);
-   }
- }
- mTokenSet = true;
- return rv;
-}
-
 // nsPKCS12Blob::ImportFromFile
 //
-// Given a file handle, read a PKCS#12 blob from that file, decode it,
-// and import the results into the token.
+// Given a file handle, read a PKCS#12 blob from that file, decode it, and
+// import the results into the internal database.
 nsresult
 nsPKCS12Blob::ImportFromFile(nsIFile *file)
 {
   nsNSSShutDownPreventionLock locker;
   nsresult rv = NS_OK;
 
-  if (!mToken) {
-    if (!mTokenSet) {
-      rv = SetToken(nullptr); // Ask the user to pick a slot
-      if (NS_FAILED(rv)) {
-        handleError(PIP_PKCS12_USER_CANCELED);
-        return rv;
-      }
-    }
-  }
-
-  if (!mToken) {
-    handleError(PIP_PKCS12_RESTORE_FAILED);
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  // init slot
-  rv = mToken->Login(true);
-  if (NS_FAILED(rv)) return rv;
-  
   RetryReason wantRetry;
   
   do {
     rv = ImportFromFileHelper(file, im_standard_prompt, wantRetry);
     
-    if (NS_SUCCEEDED(rv) && wantRetry == rr_auto_retry_empty_password_flavors)
-    {
+    if (NS_SUCCEEDED(rv) && wantRetry == rr_auto_retry_empty_password_flavors) {
       rv = ImportFromFileHelper(file, im_try_zero_length_secitem, wantRetry);
     }
   }
   while (NS_SUCCEEDED(rv) && (wantRetry != rr_do_not_retry));
   
   return rv;
 }
 
@@ -136,49 +82,38 @@ nsresult
 nsPKCS12Blob::ImportFromFileHelper(nsIFile *file, 
                                    nsPKCS12Blob::ImportMode aImportMode,
                                    nsPKCS12Blob::RetryReason &aWantRetry)
 {
   nsNSSShutDownPreventionLock locker;
   nsresult rv = NS_OK;
   SECStatus srv = SECSuccess;
   SEC_PKCS12DecoderContext *dcx = nullptr;
-  SECItem unicodePw;
-
-  UniquePK11SlotInfo slot;
-  nsAutoCString tokenName;
-  unicodePw.data = nullptr;
+  SECItem unicodePw = { siBuffer, nullptr, 0  };
 
   aWantRetry = rr_do_not_retry;
 
-  if (aImportMode == im_try_zero_length_secitem)
-  {
+  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
+  if (!slot) {
+    srv = SECFailure;
+    goto finish;
+  }
+
+  if (aImportMode == im_try_zero_length_secitem) {
     unicodePw.len = 0;
-  }
-  else
-  {
+  } else {
     // get file password (unicode)
     rv = getPKCS12FilePassword(&unicodePw);
     if (NS_FAILED(rv)) goto finish;
     if (!unicodePw.data) {
       handleError(PIP_PKCS12_USER_CANCELED);
       return NS_OK;
     }
   }
 
-  rv = mToken->GetTokenName(tokenName);
-  if (NS_FAILED(rv)) {
-    goto finish;
-  }
-  slot = UniquePK11SlotInfo(PK11_FindSlotByName(tokenName.get()));
-  if (!slot) {
-    srv = SECFailure;
-    goto finish;
-  }
-
   // initialize the decoder
   dcx = SEC_PKCS12DecoderStart(&unicodePw, slot.get(), nullptr, nullptr,
                                nullptr, nullptr, nullptr, nullptr);
   if (!dcx) {
     srv = SECFailure;
     goto finish;
   }
   // read input file and feed it to the decoder
@@ -249,43 +184,34 @@ isExtractable(SECKEYPrivateKey *privKey)
   }
   return isExtractable;
 }
 
 // nsPKCS12Blob::ExportToFile
 //
 // Having already loaded the certs, form them into a blob (loading the keys
 // also), encode the blob, and stuff it into the file.
-//
-// TODO: handle slots correctly
-//       mirror "slotToUse" behavior from PSM 1.x
-//       verify the cert array to start off with?
-//       open output file as nsIFileStream object?
-//       set appropriate error codes
 nsresult
 nsPKCS12Blob::ExportToFile(nsIFile *file, 
                            nsIX509Cert **certs, int numCerts)
 {
   nsNSSShutDownPreventionLock locker;
   nsresult rv;
   SECStatus srv = SECSuccess;
   SEC_PKCS12ExportContext *ecx = nullptr;
   SEC_PKCS12SafeInfo *certSafe = nullptr, *keySafe = nullptr;
   SECItem unicodePw;
   nsAutoString filePath;
   int i;
   nsCOMPtr<nsIFile> localFileRef;
-  MOZ_ASSERT(mToken, "Need to set the token before exporting");
   // init slot
 
   bool InformedUserNoSmartcardBackup = false;
   int numCertsExported = 0;
 
-  rv = mToken->Login(true);
-  if (NS_FAILED(rv)) goto finish;
   // get file password (unicode)
   unicodePw.data = nullptr;
   rv = newPKCS12FilePassword(&unicodePw);
   if (NS_FAILED(rv)) goto finish;
   if (!unicodePw.data) {
     handleError(PIP_PKCS12_USER_CANCELED);
     return NS_OK;
   }
--- a/security/manager/ssl/nsPKCS12Blob.h
+++ b/security/manager/ssl/nsPKCS12Blob.h
@@ -1,57 +1,47 @@
 /* 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/. */
 /* $Id: nsPKCS12Blob.h,v 1.16 2006/04/12 15:43:32 benjamin%smedbergs.us Exp $ */
 
-#ifndef _NS_PKCS12BLOB_H_
-#define _NS_PKCS12BLOB_H_
+#ifndef nsPKCS12Blob_h
+#define nsPKCS12Blob_h
 
 #include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsIFile.h"
-#include "nsIPK11TokenDB.h"
-#include "nsNSSHelper.h"
-#include "nsIPK11Token.h"
 #include "nsIMutableArray.h"
-
-#include "nss.h"
-
-#include "pkcs12.h"
-#include "p12plcy.h"
+#include "nsNSSShutDown.h"
+#include "p12.h"
+#include "seccomon.h"
 
 class nsIX509Cert;
+class nsIFile;
 
 //
 // nsPKCS12Blob
 //
 // Class for importing/exporting PKCS#12 blobs
 //
 class nsPKCS12Blob : public nsNSSShutDownObject
 {
 public:
   nsPKCS12Blob();
   virtual ~nsPKCS12Blob();
 
   // Nothing to release.
   virtual void virtualDestroyNSSReference() override {}
 
-  // Set the token to use (default is internal)
-  nsresult SetToken(nsIPK11Token *token);
-
   // PKCS#12 Import
   nsresult ImportFromFile(nsIFile *file);
 
   // PKCS#12 Export
   nsresult ExportToFile(nsIFile *file, nsIX509Cert **certs, int numCerts);
 
 private:
 
-  nsCOMPtr<nsIPK11Token>          mToken;
   nsCOMPtr<nsIMutableArray>       mCertArray;
   nsCOMPtr<nsIInterfaceRequestor> mUIContext;
 
   // local helper functions
   nsresult getPKCS12FilePassword(SECItem *);
   nsresult newPKCS12FilePassword(SECItem *);
   nsresult inputToDecoder(SEC_PKCS12DecoderContext *, nsIFile *);
   nsresult unicodeToItem(const char16_t *, SECItem *);
@@ -72,16 +62,13 @@ private:
   enum RetryReason { rr_do_not_retry, rr_bad_password, rr_auto_retry_empty_password_flavors };
   enum ImportMode { im_standard_prompt, im_try_zero_length_secitem };
   
   nsresult ImportFromFileHelper(nsIFile *file, ImportMode aImportMode, RetryReason &aWantRetry);
 
   // NSPR file I/O for export file
   PRFileDesc *mTmpFile;
 
-  bool        mTokenSet;
-
   static SECItem * nickname_collision(SECItem *, PRBool *, void *);
   static void write_export_file(void *arg, const char *buf, unsigned long len);
-
 };
 
-#endif /* _NS_PKCS12BLOB_H_ */
+#endif // nsPKCS12Blob_h
--- a/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js
+++ b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js
@@ -59,17 +59,17 @@ function doesCertExist(commonName) {
 }
 
 function testImportPKCS12Cert() {
   ok(!doesCertExist(CERT_COMMON_NAME),
      "Cert should not be in the database before import");
 
   // Import and check for success.
   let certFile = do_get_file("test_certDB_import/cert_from_windows.pfx");
-  gCertDB.importPKCS12File(null, certFile);
+  gCertDB.importPKCS12File(certFile);
 
   ok(gGetPKCS12Password, "PKCS12 password should be asked");
 
   ok(doesCertExist(CERT_COMMON_NAME),
      "Cert should now be found in the database");
 }
 
 function run_test() {
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -576,16 +576,25 @@ def remove_linux_pgo_try_talos(config, t
             and test['suite'] == 'talos'
             and config.params['project'] == 'try'
         )
     for test in filter(predicate, tests):
         yield test
 
 
 @transforms.add
+def remove_native_non_try(config, tests):
+    """Remove native-engine jobs if they are not in try branch."""
+    for test in tests:
+        if test['worker-implementation'] != 'native-engine' \
+                or config.params['project'] != 'try':
+            yield test
+
+
+@transforms.add
 def make_task_description(config, tests):
     """Convert *test* descriptions to *task* descriptions (input to
     taskgraph.transforms.task)"""
 
     for test in tests:
         label = '{}-{}-{}'.format(config.kind, test['test-platform'], test['test-name'])
         if test['chunks'] > 1:
             label += '-{}'.format(test['this-chunk'])
--- a/testing/mozharness/configs/mediatests/buildbot_posix_config.py
+++ b/testing/mozharness/configs/mediatests/buildbot_posix_config.py
@@ -31,20 +31,9 @@ config = {
         'run-media-tests',
     ],
     "default_blob_upload_servers": [
          "https://blobupload.elasticbeanstalk.com",
     ],
     "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"),
     "download_minidump_stackwalk": True,
     "download_symbols": "ondemand",
-
-    "suite_definitions": {
-        "media-tests": {
-            "options": [],
-        },
-        "media-youtube-tests": {
-            "options": [
-                "%(test_manifest)s"
-            ],
-        },
-    },
 }
--- a/testing/mozharness/configs/mediatests/buildbot_windows_config.py
+++ b/testing/mozharness/configs/mediatests/buildbot_windows_config.py
@@ -9,18 +9,18 @@ external_tools_path = os.path.join(
 
 config = {
     "virtualenv_python_dll": 'c:/mozilla-build/python27/python27.dll',
     "virtualenv_path": 'venv',
     "exes": {
         'python': 'c:/mozilla-build/python27/python',
         'virtualenv': ['c:/mozilla-build/python27/python', 'c:/mozilla-build/buildbotve/virtualenv.py'],
         'hg': 'c:/mozilla-build/hg/hg',
-        'mozinstall': ['%s/build/venv/scripts/python' % os.getcwd(),
-                       '%s/build/venv/scripts/mozinstall-script.py' % os.getcwd()],
+        'mozinstall': ['{}/build/venv/scripts/python'.format(os.getcwd()),
+                       '{}/build/venv/scripts/mozinstall-script.py'.format(os.getcwd())],
         'tooltool.py': [sys.executable, 'C:/mozilla-build/tooltool.py'],
     },
 
     "find_links": [
         "http://pypi.pvt.build.mozilla.org/pub",
         "http://pypi.pub.build.mozilla.org/pub",
     ],
     "pip_index": False,
@@ -37,20 +37,9 @@ config = {
     ],
     "default_blob_upload_servers": [
          "https://blobupload.elasticbeanstalk.com",
     ],
     "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"),
     "in_tree_config": "config/mozharness/marionette.py",
     "download_minidump_stackwalk": True,
     "download_symbols": "ondemand",
-
-    "suite_definitions": {
-        "media-tests": {
-            "options": [],
-        },
-        "media-youtube-tests": {
-            "options": [
-                "%(test_manifest)s"
-            ],
-        },
-    },
 }
--- a/testing/mozharness/configs/mediatests/jenkins_config.py
+++ b/testing/mozharness/configs/mediatests/jenkins_config.py
@@ -17,30 +17,16 @@ config = {
     'find_links': ['http://pypi.pub.build.mozilla.org/pub'],
     'pip_index': False,
 
     # mozcrash support
     'download_minidump_stackwalk': True,
     'download_symbols': 'ondemand',
     'download_tooltool': True,
 
-    # Default test suite
-    'test_suite': 'media-tests',
-
-    'suite_definitions': {
-        'media-tests': {
-            'options': [],
-        },
-        'media-youtube-tests': {
-            'options': [
-                '%(test_manifest)s'
-            ],
-        },
-    },
-
     'default_actions': [
         'clobber',
         'download-and-extract',
         'create-virtualenv',
         'install',
         'run-media-tests',
     ],
 
--- a/testing/mozharness/configs/mediatests/taskcluster_posix_config.py
+++ b/testing/mozharness/configs/mediatests/taskcluster_posix_config.py
@@ -28,20 +28,9 @@ config = {
 
     "default_actions": [
         'clobber',
         'download-and-extract',
         'create-virtualenv',
         'install',
         'run-media-tests',
     ],
-
-    "suite_definitions": {
-        "media-tests": {
-            "options": [],
-        },
-        "media-youtube-tests": {
-            "options": [
-                "%(test_manifest)s"
-            ],
-        },
-    },
 }
--- a/testing/mozharness/configs/mediatests/taskcluster_windows_config.py
+++ b/testing/mozharness/configs/mediatests/taskcluster_windows_config.py
@@ -31,20 +31,9 @@ config = {
 
     "default_actions": [
         'clobber',
         'download-and-extract',
         'create-virtualenv',
         'install',
         'run-media-tests',
     ],
-
-    "suite_definitions": {
-        "media-tests": {
-            "options": [],
-        },
-        "media-youtube-tests": {
-            "options": [
-                "%(test_manifest)s"
-            ],
-        },
-    },
 }
--- a/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
+++ b/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
@@ -18,16 +18,20 @@ from mozharness.mozilla.testing.unittest
 from mozharness.mozilla.vcstools import VCSToolsScript
 
 BUSTED = 'busted'
 TESTFAILED = 'testfailed'
 UNKNOWN = 'unknown'
 EXCEPTION = 'exception'
 SUCCESS = 'success'
 
+MEDIA_SUITE = 'media-tests'
+YOUTUBE_SUITE = 'media-youtube-tests'
+TWITCH_SUITE = 'media-twitch-tests'
+
 media_test_config_options = [
     [["--media-urls"],
      {"action": "store",
       "dest": "media_urls",
       "help": "Path to ini file that lists media urls for tests.",
       }],
     [["--profile"],
      {"action": "store",
@@ -54,18 +58,21 @@ media_test_config_options = [
      {"dest": "e10s",
       "action": "store_true",
       "default": False,
       "help": "Enable e10s when running marionette tests."
       }],
     [["--suite"],
      {"action": "store",
       "dest": "test_suite",
-      "default": "media-tests",
-      "help": "suite name",
+      "default": MEDIA_SUITE,
+      "help": ("Name of test suite to run. Possible values: "
+               "{} (default), {}, {}".format(MEDIA_SUITE,
+                                             YOUTUBE_SUITE,
+                                             TWITCH_SUITE)),
       }],
     [['--browsermob-script'],
      {'help': 'path to the browsermob-proxy shell script or batch file',
      }],
     [['--browsermob-port'],
      {'help': 'port to run the browsermob proxy on',
      }],
     [["--allow-software-gl-layers"],
@@ -179,17 +186,17 @@ class FirefoxMediaTestsBase(TestingMixin
         super(FirefoxMediaTestsBase, self).download_and_extract(extract_dirs=extract_dirs)
 
     def query_abs_dirs(self):
         if self.abs_dirs:
             return self.abs_dirs
         abs_dirs = super(FirefoxMediaTestsBase, self).query_abs_dirs()
         dirs = {
             'abs_test_install_dir' : os.path.join(abs_dirs['abs_work_dir'],
-                                                    'tests')
+                                                  'tests')
         }
         dirs['external-media-tests'] = os.path.join(dirs['abs_test_install_dir'],
                                                     'external-media-tests')
         abs_dirs.update(dirs)
         self.abs_dirs = abs_dirs
         return self.abs_dirs
 
     def _query_cmd(self):
@@ -204,43 +211,59 @@ class FirefoxMediaTestsBase(TestingMixin
         cmd = [
             self.query_python_path(),
             external_media_harness.runtests.__file__
         ]
 
         cmd += ['--binary', self.binary_path]
         if self.symbols_path:
             cmd += ['--symbols-path', self.symbols_path]
-        if self.media_urls:
-            cmd += ['--urls', self.media_urls]
         if self.profile:
             cmd += ['--profile', self.profile]
         if self.tests:
             cmd.append(self.tests)
         if not self.e10s:
             cmd.append('--disable-e10s')
         if self.browsermob_script:
             cmd += ['--browsermob-script', self.browsermob_script]
         if self.browsermob_port:
             cmd += ['--browsermob-port', self.browsermob_port]
 
         test_suite = self.config.get('test_suite')
-        if test_suite not in self.config["suite_definitions"]:
-            self.fatal("%s is not defined in the config!" % test_suite)
+        if test_suite not in [MEDIA_SUITE,
+                              YOUTUBE_SUITE,
+                              TWITCH_SUITE]:
+            self.fatal("{} is not on of the possibele suites! "
+                       "See the --suites arg for more info"
+                       .format(test_suite))
 
-        test_manifest = None if test_suite != 'media-youtube-tests' else \
-            os.path.join(dirs['external-media-tests'],
-                         'external_media_tests',
-                         'playback', 'youtube', 'manifest.ini')
-        config_fmt_args = {
-            'test_manifest': test_manifest,
-        }
+        if test_suite == YOUTUBE_SUITE:
+            test_manifest = os.path.join(dirs['external-media-tests'],
+                                         'external_media_tests',
+                                         'playback', 'youtube',
+                                         'manifest.ini')
+        elif test_suite == TWITCH_SUITE:
+            test_manifest = os.path.join(dirs['external-media-tests'],
+                                         'external_media_tests',
+                                         'playback', 'twitch',
+                                         'manifest.ini')
+            if not self.media_urls:
+                # The default URLs are for youtube and won't play nice with
+                # the twitch tests, so set URLs to the default twitch ones
+                self.media_urls = os.path.join(dirs['external-media-tests'],
+                                               'external_media_tests', 'urls',
+                                               'twitch', 'default.ini')
+        else:
+            test_manifest = None
 
-        for s in self.config["suite_definitions"][test_suite]["options"]:
-            cmd.append(s % config_fmt_args)
+        if test_manifest:
+            cmd.append(test_manifest)
+
+        if self.media_urls:
+            cmd += ['--urls', self.media_urls]
 
         return cmd
 
     def query_minidump_stackwalk(self):
         """We don't have an extracted test package available to get the manifest file.
 
         So we have to explicitely download the latest version of the manifest from the
         mozilla-central repository and feed it into the query_minidump_stackwalk() method.
@@ -255,17 +278,17 @@ class FirefoxMediaTestsBase(TestingMixin
             url_base = 'https://hg.mozilla.org/mozilla-central/raw-file/default/testing/'
 
             dirs = self.query_abs_dirs()
             manifest_path = os.path.join(dirs['abs_work_dir'], 'releng.manifest')
             try:
                 self.download_file(urlparse.urljoin(url_base, tooltool_manifest),
                                    manifest_path)
             except Exception as e:
-                self.fatal('Download of tooltool manifest file failed: %s' % e.message)
+                self.fatal('Download of tooltool manifest file failed: {}'.format(e.message))
 
         return super(FirefoxMediaTestsBase, self).query_minidump_stackwalk(manifest=manifest_path)
 
     def run_media_tests(self):
         cmd = self._query_cmd()
         self.job_result_parser = JobResultParser(
             config=self.config,
             log_obj=self.log_obj,
--- a/testing/web-platform/manifestupdate.py
+++ b/testing/web-platform/manifestupdate.py
@@ -1,16 +1,23 @@
 import argparse
 import imp
 import os
 import sys
+from collections import defaultdict
 
 from mozlog.structured import commandline
 from wptrunner.wptcommandline import get_test_paths, set_from_config
-from wptrunner.testloader import ManifestLoader
+
+manifest = None
+
+def do_delayed_imports(wpt_dir):
+    global manifest
+    sys.path.insert(0, os.path.join(wpt_dir, "tools", "manifest"))
+    import manifest
 
 def create_parser():
     p = argparse.ArgumentParser()
     p.add_argument("--check-clean", action="store_true",
                    help="Check that updating the manifest doesn't lead to any changes")
     commandline.add_logging_group(p)
 
     return p
@@ -22,68 +29,115 @@ def update(logger, wpt_dir, check_clean=
     kwargs = {"config": os.path.join(wpt_dir, "wptrunner.ini"),
               "tests_root": None,
               "metadata_root": None}
 
     set_from_config(kwargs)
     config = kwargs["config"]
     test_paths = get_test_paths(config)
 
+    do_delayed_imports(wpt_dir)
+
     if check_clean:
-        old_manifests = {}
-        for data in test_paths.itervalues():
-            path = os.path.join(data["metadata_path"], "MANIFEST.json")
-            with open(path) as f:
-                old_manifests[path] = f.readlines()
+        return _check_clean(logger, test_paths)
+
+    return _update(logger, test_paths)
+
 
-    try:
-        ManifestLoader(test_paths, force_manifest_update=True).load()
+def _update(logger, test_paths):
+    for url_base, paths in test_paths.iteritems():
+        manifest_path = os.path.join(paths["metadata_path"], "MANIFEST.json")
+        m = manifest.manifest.load(paths["tests_path"], manifest_path)
+        manifest.update.update(paths["tests_path"], m, working_copy=True)
+        manifest.manifest.write(m, manifest_path)
+    return 0
+
 
-        rv = 0
+def _check_clean(logger, test_paths):
+    manifests_by_path = {}
+    rv = 0
+    for url_base, paths in test_paths.iteritems():
+        tests_path = paths["tests_path"]
+        manifest_path = os.path.join(paths["metadata_path"], "MANIFEST.json")
+        old_manifest = manifest.manifest.load(tests_path, manifest_path)
+        new_manifest = manifest.manifest.Manifest.from_json(tests_path,
+                                                            old_manifest.to_json())
+        manifest.update.update(tests_path, new_manifest, working_copy=True)
+        manifests_by_path[manifest_path] = (old_manifest, new_manifest)
 
-        if check_clean:
-            clean = diff_manifests(logger, old_manifests)
-            if not clean:
-                rv = 1
-    finally:
-        if check_clean:
-            for path, data in old_manifests.iteritems():
-                logger.info("Restoring manifest %s" % path)
-                with open(path, "w") as f:
-                    f.writelines(data)
+    for manifest_path, (old_manifest, new_manifest) in manifests_by_path.iteritems():
+        if not diff_manifests(logger, manifest_path, old_manifest, new_manifest):
+            rv = 1
+    if rv:
+        logger.error("Manifest %s is outdated, use |mach wpt-manifest-update| to fix." % manifest_path)
 
     return rv
 
-def diff_manifests(logger, old_manifests):
-    logger.info("Diffing old and new manifests")
-    import difflib
+
+def diff_manifests(logger, manifest_path, old_manifest, new_manifest):
+    """Lint the differences between old and new versions of a
+    manifest. Differences are considered significant (and so produce
+    lint errors) if they produce a meaningful difference in the actual
+    tests run.
+
+    :param logger: mozlog logger to use for output
+    :param manifest_path: Path to the manifest being linted
+    :param old_manifest: Manifest object representing the initial manifest
+    :param new_manifest: Manifest object representing the updated manifest
+    """
+    logger.info("Diffing old and new manifests %s" % manifest_path)
+    old_items, new_items = defaultdict(set), defaultdict(set)
+    for manifest, items in [(old_manifest, old_items),
+                            (new_manifest, new_items)]:
+        for test_type, path, tests in manifest:
+            for test in tests:
+                test_id = [test.id]
+                test_id.extend(tuple(item) if isinstance(item, list) else item
+                               for item in test.meta_key())
+                if hasattr(test, "references"):
+                    test_id.extend(tuple(item) for item in test.references)
+                test_id = tuple(test_id)
+                items[path].add((test_type, test_id))
+
+    old_paths = set(old_items.iterkeys())
+    new_paths = set(new_items.iterkeys())
+
+    added_paths = new_paths - old_paths
+    deleted_paths = old_paths - new_paths
+
+    common_paths = new_paths & old_paths
 
     clean = True
-    for path, old in old_manifests.iteritems():
-        with open(path) as f:
-            new = f.readlines()
 
-        if old != new:
+    for path in added_paths:
+        clean = False
+        log_error(logger, manifest_path, "%s in source but not in manifest." % path)
+    for path in deleted_paths:
+        clean = False
+        log_error(logger, manifest_path, "%s in manifest but removed from source." % path)
+
+    for path in common_paths:
+        old_tests = old_items[path]
+        new_tests = new_items[path]
+        added_tests = new_tests - old_tests
+        removed_tests = old_tests - new_tests
+        if added_tests or removed_tests:
             clean = False
-            sm = difflib.SequenceMatcher(a=old, b=new)
-            for group in sm.get_grouped_opcodes():
-                logged = False
-                message = []
-                for op, old_0, old_1, new_0, new_1 in group:
-                    if op != "equal" and not logged:
-                        logged = True
-                        logger.lint_error(path=path,
-                                          message="Manifest changed",
-                                          lineno=(old_0 + 1),
-                                          source="\n".join(old[old_0:old_1]),
-                                          linter="wpt-manifest")
-                    if op == "equal":
-                        message.extend(' ' + line for line in old[old_0:old_1])
-                    if op in ('replace', 'delete'):
-                        message.extend('-' + line for line in old[old_0:old_1])
-                    if op in ('replace', 'insert'):
-                        message.extend('+' + line for line in new[new_0:new_1])
-                logger.info("".join(message))
+            log_error(logger, manifest_path, "%s changed test types or metadata" % path)
+
     if clean:
-        logger.info("No differences found")
+        # Manifest currently has some list vs tuple inconsistencies that break
+        # a simple equality comparison.
+        new_paths = {(key, value[0], value[1])
+                     for (key, value) in new_manifest.to_json()["paths"].iteritems()}
+        old_paths = {(key, value[0], value[1])
+                     for (key, value) in old_manifest.to_json()["paths"].iteritems()}
+        if old_paths != new_paths:
+            logger.warning("Manifest %s contains correct tests but file hashes changed; please update" % manifest_path)
 
     return clean
 
+def log_error(logger, manifest_path, msg):
+    logger.lint_error(path=manifest_path,
+                      message=msg,
+                      lineno=0,
+                      source="",
+                      linter="wpt-manifest")
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -601,17 +601,17 @@ var LoginManagerContent = {
       // Exclude ones matching a `notPasswordSelector`, if specified.
       if (fieldOverrideRecipe && fieldOverrideRecipe.notPasswordSelector &&
           element.matches(fieldOverrideRecipe.notPasswordSelector)) {
         log("skipping password field (id/name is", element.id, " / ",
             element.name + ") due to recipe:", fieldOverrideRecipe);
         continue;
       }
 
-      if (skipEmptyFields && !element.value) {
+      if (skipEmptyFields && !element.value.trim()) {
         continue;
       }
 
       pwFields[pwFields.length] = {
                                     index   : i,
                                     element
                                   };
     }
--- a/toolkit/components/passwordmgr/test/unit/test_getPasswordFields.js
+++ b/toolkit/components/passwordmgr/test/unit/test_getPasswordFields.js
@@ -72,18 +72,28 @@ const TESTCASES = [
   {
     description: "2 password fields outside of a <form> with 1 linked via @form + skipEmpty",
     document: `<input id="pw1" type=password><input id="pw2" type=password form="form1">
       <form id="form1"></form>`,
     returnedFieldIDsByFormLike: [[], []],
     skipEmptyFields: true,
   },
   {
+    description: "skipEmptyFields should also skip white-space only fields",
+    document: `<input id="pw-space" type=password value=" ">
+               <input id="pw-tab" type=password value="	">
+               <input id="pw-newline" type=password form="form1" value="
+">
+      <form id="form1"></form>`,
+    returnedFieldIDsByFormLike: [[], []],
+    skipEmptyFields: true,
+  },
+  {
     description: "2 password fields outside of a <form> with 1 linked via @form + skipEmpty with 1 empty",
-    document: `<input id="pw1" type=password value="pass1"><input id="pw2" type=password form="form1">
+    document: `<input id="pw1" type=password value=" pass1 "><input id="pw2" type=password form="form1">
       <form id="form1"></form>`,
     returnedFieldIDsByFormLike: [["pw1"], []],
     skipEmptyFields: true,
     fieldOverrideRecipe: {
       // Ensure a recipe without `notPasswordSelector` doesn't cause a problem.
       hosts: ["localhost:8080"],
     },
   },
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -697,20 +697,29 @@ nsFormFillController::GetUserContextId(u
 ////////////////////////////////////////////////////////////////////////
 //// nsIAutoCompleteSearch
 
 NS_IMETHODIMP
 nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAString &aSearchParam,
                                   nsIAutoCompleteResult *aPreviousResult, nsIAutoCompleteObserver *aListener)
 {
   nsresult rv;
+  nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(mFocusedInputNode);
 
   // If the login manager has indicated it's responsible for this field, let it
   // handle the autocomplete. Otherwise, handle with form history.
-  if (mPwmgrInputs.Get(mFocusedInputNode)) {
+  if (mFocusedInputNode && (mPwmgrInputs.Get(mFocusedInputNode) ||
+                            formControl->GetType() == NS_FORM_INPUT_PASSWORD)) {
+
+    // Handle the case where a password field is focused but
+    // MarkAsLoginManagerField wasn't called because password manager is disabled.
+    if (!mLoginManager) {
+      mLoginManager = do_GetService("@mozilla.org/login-manager;1");
+    }
+
     // XXX aPreviousResult shouldn't ever be a historyResult type, since we're not letting
     // satchel manage the field?
     mLastListener = aListener;
     rv = mLoginManager->AutoCompleteSearchAsync(aSearchString,
                                                 aPreviousResult,
                                                 mFocusedInput,
                                                 this);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -981,39 +990,45 @@ nsFormFillController::MaybeStartControll
   nsCOMPtr<nsIDOMHTMLElement> datalist;
   aInput->GetList(getter_AddRefs(datalist));
   bool hasList = datalist != nullptr;
 
   bool isPwmgrInput = false;
   if (mPwmgrInputs.Get(inputNode))
       isPwmgrInput = true;
 
-  // Don't show autocomplete on password fields regardless of datalist or
-  // autocomplete being enabled as we don't want to show form history on them.
-  // The GetType() check was more readable than !formControl->IsSingleLineTextControl(true)
-  // but this logic should be kept in-sync with that.
-  if (formControl->GetType() == NS_FORM_INPUT_PASSWORD && !isPwmgrInput) {
-    return;
-  }
-
   if (isPwmgrInput || hasList || autocomplete) {
     StartControllingInput(aInput);
   }
 }
 
 nsresult
 nsFormFillController::Focus(nsIDOMEvent* aEvent)
 {
   nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(
     aEvent->InternalDOMEvent()->GetTarget());
   MaybeStartControllingInput(input);
 
+  // Bail if we didn't start controlling the input.
+  if (!mFocusedInputNode) {
+    mContextMenuFiredBeforeFocus = false;
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(mFocusedInputNode);
+  MOZ_ASSERT(formControl);
+
   // If this focus doesn't immediately follow a contextmenu event then show
   // the autocomplete popup
-  if (!mContextMenuFiredBeforeFocus && mPwmgrInputs.Get(mFocusedInputNode)) {
+  if (!mContextMenuFiredBeforeFocus &&
+      (mPwmgrInputs.Get(mFocusedInputNode)
+#ifndef ANDROID
+       || formControl->GetType() == NS_FORM_INPUT_PASSWORD
+#endif
+       )) {
     ShowPopup();
   }
 
   mContextMenuFiredBeforeFocus = false;
   return NS_OK;
 }
 
 nsresult
--- a/toolkit/components/satchel/test/mochitest.ini
+++ b/toolkit/components/satchel/test/mochitest.ini
@@ -10,10 +10,11 @@ support-files =
 [test_bug_787624.html]
 [test_datalist_with_caching.html]
 [test_form_autocomplete.html]
 [test_form_autocomplete_with_list.html]
 [test_form_submission.html]
 [test_form_submission_cap.html]
 [test_form_submission_cap2.html]
 [test_password_autocomplete.html]
+scheme = https
 [test_popup_direction.html]
 [test_popup_enter_event.html]
--- a/toolkit/components/satchel/test/test_password_autocomplete.html
+++ b/toolkit/components/satchel/test/test_password_autocomplete.html
@@ -16,17 +16,24 @@
 <!-- we presumably can't hide the content for this test. -->
 <div id="content">
   <datalist id="datalist1">
     <option>value10</option>
     <option>value11</option>
     <option>value12</option>
   </datalist>
   <form id="form1" onsubmit="return false;">
-    <input  type="password" name="field1" list="datalist1">
+    <!-- Don't set the type to password until rememberSignons is false since we
+         want to test when rememberSignons is false. -->
+    <input  type="to-be-password" name="field1" list="datalist1">
+    <button type="submit">Submit</button>
+  </form>
+  <!-- Same as form1 but with an insecure HTTP action -->
+  <form id="form2" onsubmit="return false;" action="http://mochi.test/">
+    <input  type="to-be-password" name="field1" list="datalist1">
     <button type="submit">Submit</button>
   </form>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /* import-globals-from satchel_common.js */
 
@@ -61,36 +68,42 @@ function expectPopupDoesNotOpen(triggerF
   let popupShown = waitForNextPopup();
   triggerFn();
   return Promise.race([
     popupShown.then(() => Promise.reject("Popup opened unexpectedly.")),
     new Promise(resolve => setTimeout(resolve, POPUP_RESPONSE_WAIT_TIME_MS)),
   ]);
 }
 
-let input = $_(1, "field1");
+add_task(function* test_initialize() {
+  yield SpecialPowers.pushPrefEnv({set: [["signon.rememberSignons", false]]});
 
-add_task(function* test_initialize() {
-  yield SpecialPowers.pushPrefEnv("set", [["signon.rememberSignons", false]]);
+  is(window.location.protocol, "https:", "This test must run on HTTPS");
+
+  // Now that rememberSignons is false, create the password fields.
+  $_(1, "field1").type = "password";
+  $_(2, "field1").type = "password";
 
   yield new Promise(resolve => updateFormHistory([
     { op : "remove" },
     { op : "add", fieldname : "field1", value : "value1" },
     { op : "add", fieldname : "field1", value : "value2" },
     { op : "add", fieldname : "field1", value : "value3" },
     { op : "add", fieldname : "field1", value : "value4" },
     { op : "add", fieldname : "field1", value : "value5" },
     { op : "add", fieldname : "field1", value : "value6" },
     { op : "add", fieldname : "field1", value : "value7" },
     { op : "add", fieldname : "field1", value : "value8" },
     { op : "add", fieldname : "field1", value : "value9" },
   ], resolve));
 });
 
-add_task(function* test_no_form_history() {
+add_task(function* test_secure_noFormHistoryOrWarning() {
+  let input = $_(1, "field1");
+
   // The autocomplete popup should not open under any circumstances on
   // type=password with password manager disabled.
   for (let triggerFn of [
     () => input.focus(),
     () => input.click(),
     () => doKey("down"),
     () => doKey("page_down"),
     () => doKey("return"),
@@ -102,12 +115,26 @@ add_task(function* test_no_form_history(
     // We must wait for the entire timeout for each individual test, because the
     // next event in the list might prevent the popup from opening.
     yield expectPopupDoesNotOpen(triggerFn);
   }
 
   // Close the popup.
   input.blur();
 });
+
+add_task(function* test_insecure_focusWarning() {
+  // Form 2 has an insecure action so should show the warning even if password manager is disabled.
+  let input = $_(2, "field1");
+  let shownPromise = waitForNextPopup();
+  input.focus();
+  yield shownPromise;
+
+  ok(getMenuEntries()[0].includes("Logins entered here could be compromised"),
+     "Check warning is first")
+
+  // Close the popup
+  input.blur();
+});
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5168,16 +5168,93 @@
     "bug_numbers": [1309617],
     "alert_emails": ["gijs@mozilla.com"],
     "expires_in_version": "57",
     "kind": "enumerated",
     "n_values": 5,
     "releaseChannelCollection": "opt-out",
     "description": "Indicates we showed a 'would you like to undo this automatic migration?' notification bar. The bucket indicates which nth day we're on (1st/2nd/3rd, by default - 0 would be indicative the pref didn't get set which shouldn't happen). After 3 days on which the notification gets shown, it will get disabled and never shown again."
   },
+  "FX_STARTUP_MIGRATION_UNDO_BOOKMARKS_ERRORCOUNT": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 100,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how many errors we find when trying to 'undo' bookmarks import. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
+  "FX_STARTUP_MIGRATION_UNDO_LOGINS_ERRORCOUNT": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 100,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how many errors we find when trying to 'undo' login (password) import. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
+  "FX_STARTUP_MIGRATION_UNDO_VISITS_ERRORCOUNT": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 100,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how many errors we find when trying to 'undo' history import. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
+  "FX_STARTUP_MIGRATION_UNDO_BOOKMARKS_MS": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 60000,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how long it took to undo the startup import of bookmarks, in ms. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
+  "FX_STARTUP_MIGRATION_UNDO_LOGINS_MS": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 60000,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how long it took to undo the startup import of logins, in ms. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
+  "FX_STARTUP_MIGRATION_UNDO_VISITS_MS": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 60000,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how long it took to undo the startup import of visits (history), in ms. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
+  "FX_STARTUP_MIGRATION_UNDO_TOTAL_MS": {
+    "bug_numbers": [1333233],
+    "alert_emails": ["gijs@mozilla.com"],
+    "expires_in_version": "58",
+    "keyed": true,
+    "kind": "exponential",
+    "n_buckets": 20,
+    "high": 60000,
+    "releaseChannelCollection": "opt-out",
+    "description": "Indicates how long it took to undo the entirety of the startup undo, in ms. Keys are internal ids of browsers we import from, e.g. 'chrome' or 'ie', etc."
+  },
   "FX_STARTUP_MIGRATION_DATA_RECENCY": {
     "bug_numbers": [1276694],
     "alert_emails": ["gijs@mozilla.com"],
     "expires_in_version": "57",
     "keyed": true,
     "kind": "exponential",
     "n_buckets": 50,
     "high": 8760,
--- a/toolkit/modules/SelectContentHelper.jsm
+++ b/toolkit/modules/SelectContentHelper.jsm
@@ -220,34 +220,39 @@ function buildOptionListForChildren(node
 
       let textContent =
         tagName == "OPTGROUP" ? child.getAttribute("label")
                               : child.text;
       if (textContent == null) {
         textContent = "";
       }
 
+      // Selected options have the :checked pseudo-class, which
+      // we want to disable before calculating the computed
+      // styles since the user agent styles alter the styling
+      // based on :checked.
+      DOMUtils.addPseudoClassLock(child, ":checked", false);
       let cs = getComputedStyles(child);
 
       let info = {
         index: child.index,
         tagName,
         textContent,
         disabled: child.disabled,
         display: cs.display,
         // We need to do this for every option element as each one can have
         // an individual style set for direction
         textDirection: cs.direction,
         tooltip: child.title,
-        // XXX this uses a highlight color when this is the selected element.
-        // We need to suppress such highlighting in the content process to get
-        // the option's correct unhighlighted color here.
-        // We also need to detect default color vs. custom so that a standard
-        // color does not override color: menutext in the parent.
-        // backgroundColor: computedStyle.backgroundColor,
-        // color: computedStyle.color,
+        backgroundColor: cs.backgroundColor,
+        color: cs.color,
         children: tagName == "OPTGROUP" ? buildOptionListForChildren(child) : []
       };
+
+      // We must wait until all computedStyles have been
+      // read before we clear the locks.
+      DOMUtils.clearPseudoClassLocks(child);
+
       result.push(info);
     }
   }
   return result;
 }
--- a/toolkit/modules/SelectParentHelper.jsm
+++ b/toolkit/modules/SelectParentHelper.jsm
@@ -192,16 +192,31 @@ function populateChildren(menulist, opti
     item.style.direction = option.textDirection;
     item.style.fontSize = adjustedTextSize;
     item.hidden = option.display == "none" || (parentElement && parentElement.hidden);
     // Keep track of which options are hidden by page content, so we can avoid showing
     // them on search input
     item.hiddenByContent = item.hidden;
     item.setAttribute("tooltiptext", option.tooltip);
 
+    if (option.backgroundColor && option.backgroundColor != "transparent") {
+      item.style.backgroundColor = option.backgroundColor;
+    }
+
+    if (option.color && option.color != "transparent") {
+      item.style.color = option.color;
+    }
+
+    if ((option.backgroundColor && option.backgroundColor != "transparent") ||
+        (option.color && option.color != "rgb(0, 0, 0)")) {
+      item.setAttribute("customoptionstyling", "true");
+    } else {
+      item.removeAttribute("customoptionstyling");
+    }
+
     element.appendChild(item);
 
     // A disabled optgroup disables all of its child options.
     let isDisabled = isGroupDisabled || option.disabled;
     if (isDisabled) {
       item.setAttribute("disabled", "true");
     }
 
--- a/toolkit/themes/linux/global/menu.css
+++ b/toolkit/themes/linux/global/menu.css
@@ -27,16 +27,20 @@ menuitem[default="true"] {
 }
 
 menu[_moz-menuactive="true"],
 menuitem[_moz-menuactive="true"] {
   color: -moz-menuhovertext;
   background-color: -moz-menuhover;
 }
 
+menuitem[_moz-menuactive="true"][customoptionstyling="true"] {
+  filter: invert(100%);
+}
+
 menu[disabled="true"],
 menuitem[disabled="true"],
 menucaption[disabled="true"] {
   color: GrayText;
 }
 
 menubar > menu {
   padding: 0px 4px;
--- a/toolkit/themes/osx/global/menu.css
+++ b/toolkit/themes/osx/global/menu.css
@@ -130,16 +130,26 @@ menupopup > menucaption {
 }
 
 menu[_moz-menuactive="true"],
 menuitem[_moz-menuactive="true"] {
   color: -moz-mac-menutextselect;
   background-color: Highlight;
 }
 
+menuitem[customoptionstyling="true"] {
+  -moz-appearance: none;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+menuitem[_moz-menuactive="true"][customoptionstyling="true"] {
+  filter: invert(100%);
+}
+
 /* ::::: menu/menuitems in menulist popups ::::: */
 
 menulist > menupopup > menuitem,
 menulist > menupopup > menucaption,
 menulist > menupopup > menu {
   max-width: none;
   font: inherit;
   color: -moz-FieldText;
--- a/toolkit/themes/shared/aboutNetworking.css
+++ b/toolkit/themes/shared/aboutNetworking.css
@@ -10,17 +10,21 @@ html {
 
 body {
   display: flex;
   align-items: stretch;
   height: 100%;
 }
 
 #sectionTitle {
-  float: inline-start;
+  float: left;
+}
+
+#sectionTitle:dir(rtl) {
+  float: right;
 }
 
 #refreshDiv {
   justify-content: flex-end;
   margin-bottom: 0.5em;
 }
 
 #refreshButton {
--- a/toolkit/themes/windows/global/menu.css
+++ b/toolkit/themes/windows/global/menu.css
@@ -199,16 +199,20 @@ menulist > menupopup > menu {
 }
 
 menulist > menupopup > menuitem[_moz-menuactive="true"],
 menulist > menupopup > menu[_moz-menuactive="true"] {
   background-color: highlight;
   color: highlighttext;
 }
 
+menulist > menupopup > menuitem[_moz-menuactive="true"][customoptionstyling="true"] {
+  filter: invert(100%);
+}
+
 menulist > menupopup > menuitem > .menu-iconic-left,
 menulist > menupopup > menucaption > .menu-iconic-left,
 menulist > menupopup > menu > .menu-iconic-left {
   display: none;
 }
 
 menulist > menupopup > menuitem > label,
 menulist > menupopup > menucaption > label,
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -65,17 +65,16 @@
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
 #include "GMPProcessChild.h"
-#include "GMPLoader.h"
 #include "mozilla/gfx/GPUProcessImpl.h"
 
 #include "GeckoProfiler.h"
 
 #include "mozilla/Telemetry.h"
 
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
 #include "mozilla/sandboxTarget.h"
@@ -110,18 +109,16 @@ using mozilla::ipc::IOThreadChild;
 using mozilla::ipc::ProcessChild;
 using mozilla::ipc::ScopedXREEmbed;
 
 using mozilla::plugins::PluginProcessChild;
 using mozilla::dom::ContentProcess;
 using mozilla::dom::ContentParent;
 using mozilla::dom::ContentChild;
 
-using mozilla::gmp::GMPLoader;
-using mozilla::gmp::CreateGMPLoader;
 using mozilla::gmp::GMPProcessChild;
 
 using mozilla::ipc::TestShellParent;
 using mozilla::ipc::TestShellCommandParent;
 using mozilla::ipc::XPCShellEnvironment;
 
 using mozilla::startup::sChildProcessType;
 
@@ -323,42 +320,16 @@ AddContentSandboxLevelAnnotation()
     levelString.AppendInt(level);
     CrashReporter::AnnotateCrashReport(
       NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString);
   }
 }
 #endif /* MOZ_CONTENT_SANDBOX && !MOZ_WIDGET_GONK */
 #endif /* MOZ_CRASHREPORTER */
 
-#if defined (XP_LINUX) && defined(MOZ_GMP_SANDBOX)
-namespace {
-class LinuxSandboxStarter : public mozilla::gmp::SandboxStarter {
-private:
-  LinuxSandboxStarter() { }
-  friend mozilla::detail::UniqueSelector<LinuxSandboxStarter>::SingleObject mozilla::MakeUnique<LinuxSandboxStarter>();
-
-public:
-  static UniquePtr<SandboxStarter> Make() {
-    if (mozilla::SandboxInfo::Get().CanSandboxMedia()) {
-      return MakeUnique<LinuxSandboxStarter>();
-    } else {
-      // Sandboxing isn't possible, but the parent has already
-      // checked that this plugin doesn't require it.  (Bug 1074561)
-      return nullptr;
-    }
-    return nullptr;
-  }
-  virtual bool Start(const char *aLibPath) override {
-    mozilla::SetMediaPluginSandbox(aLibPath);
-    return true;
-  }
-};
-} // anonymous namespace
-#endif // XP_LINUX && MOZ_GMP_SANDBOX
-
 nsresult
 XRE_InitChildProcess(int aArgc,
                      char* aArgv[],
                      const XREChildData* aChildData)
 {
   NS_ENSURE_ARG_MIN(aArgc, 2);
   NS_ENSURE_ARG_POINTER(aArgv);
   NS_ENSURE_ARG_POINTER(aArgv[0]);
@@ -369,36 +340,16 @@ XRE_InitChildProcess(int aArgc,
     mozilla::SandboxEarlyInit(XRE_GetProcessType());
 #endif
 
 #ifdef MOZ_JPROF
   // Call the code to install our handler
   setupProfilingStuff();
 #endif
 
-#ifdef XP_LINUX
-  // On Fennec, the GMPLoader's code resides inside XUL (because for the time
-  // being GMPLoader relies upon NSPR, which we can't use in plugin-container
-  // on Android), so we create it here inside XUL and pass it to the GMP code.
-  //
-  // On desktop Linux, the sandbox code lives in a shared library, and
-  // the GMPLoader is in libxul instead of executables to avoid unwanted
-  // library dependencies.
-  UniquePtr<mozilla::gmp::SandboxStarter> starter;
-#ifdef MOZ_GMP_SANDBOX
-  starter = LinuxSandboxStarter::Make();
-#endif
-  UniquePtr<GMPLoader> loader = CreateGMPLoader(Move(starter));
-  GMPProcessChild::SetGMPLoader(loader.get());
-#else
-  // On non-Linux platforms, the GMPLoader code resides in plugin-container,
-  // and we must forward it through to the GMP code here.
-  GMPProcessChild::SetGMPLoader(aChildData->gmpLoader.get());
-#endif
-
 #if defined(XP_WIN)
   // From the --attach-console support in nsNativeAppSupportWin.cpp, but
   // here we are a content child process, so we always attempt to attach
   // to the parent's (ie, the browser's) console.
   // Try to attach console to the parent process.
   // It will succeed when the parent process is a command line,
   // so that stdio will be displayed in it.
   if (AttachConsole(ATTACH_PARENT_PROCESS)) {
@@ -513,43 +464,43 @@ XRE_InitChildProcess(int aArgc,
 
   if (err != KERN_SUCCESS) {
     NS_WARNING("child task_set_bootstrap_port() failed");
     return NS_ERROR_FAILURE;
   }
 
 #endif
 
-  SetupErrorHandling(aArgv[0]);  
+  SetupErrorHandling(aArgv[0]);
 
 #if defined(MOZ_CRASHREPORTER)
   if (aArgc < 1)
     return NS_ERROR_FAILURE;
   const char* const crashReporterArg = aArgv[--aArgc];
-  
+
 #  if defined(XP_WIN) || defined(XP_MACOSX)
   // on windows and mac, |crashReporterArg| is the named pipe on which the
   // server is listening for requests, or "-" if crash reporting is
   // disabled.
-  if (0 != strcmp("-", crashReporterArg) && 
+  if (0 != strcmp("-", crashReporterArg) &&
       !XRE_SetRemoteExceptionHandler(crashReporterArg)) {
     // Bug 684322 will add better visibility into this condition
     NS_WARNING("Could not setup crash reporting\n");
   }
 #  elif defined(OS_LINUX)
   // on POSIX, |crashReporterArg| is "true" if crash reporting is
   // enabled, false otherwise
-  if (0 != strcmp("false", crashReporterArg) && 
+  if (0 != strcmp("false", crashReporterArg) &&
       !XRE_SetRemoteExceptionHandler(nullptr)) {
     // Bug 684322 will add better visibility into this condition
     NS_WARNING("Could not setup crash reporting\n");
   }
 #  else
 #    error "OOP crash reporting unsupported on this platform"
-#  endif   
+#  endif
 #endif // if defined(MOZ_CRASHREPORTER)
 
   gArgv = aArgv;
   gArgc = aArgc;
 
 #ifdef MOZ_X11
   XInitThreads();
 #endif
@@ -702,17 +653,17 @@ XRE_InitChildProcess(int aArgc,
 #endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
           }
         }
         break;
 
       case GeckoProcessType_IPDLUnitTest:
 #ifdef MOZ_IPDL_TESTS
         process = new IPDLUnitTestProcessChild(parentPID);
-#else 
+#else
         MOZ_CRASH("rebuild with --enable-ipdl-tests");
 #endif
         break;
 
       case GeckoProcessType_GMPlugin:
         process = new gmp::GMPProcessChild(parentPID);
         break;
 
@@ -789,17 +740,17 @@ class MainFunctionRunnable : public Runn
 {
 public:
   NS_DECL_NSIRUNNABLE
 
   MainFunctionRunnable(MainFunction aFunction,
                        void* aData)
   : mFunction(aFunction),
     mData(aData)
-  { 
+  {
     NS_ASSERTION(aFunction, "Don't give me a null pointer!");
   }
 
 private:
   MainFunction mFunction;
   void* mData;
 };
 
@@ -886,33 +837,33 @@ XRE_RunAppShell()
 #if defined(XP_MACOSX)
     {
       // In content processes that want XPCOM (and hence want
       // AppShell), we usually run our hybrid event loop through
       // MessagePump::Run(), by way of nsBaseAppShell::Run().  The
       // Cocoa nsAppShell impl, however, implements its own Run()
       // that's unaware of MessagePump.  That's all rather suboptimal,
       // but oddly enough not a problem... usually.
-      // 
+      //
       // The problem with this setup comes during startup.
       // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
       // service, so we have to init IPC first.  But, IPC also
       // indirectly kinda-depends on XPCOM, because MessagePump
       // schedules work from off-main threads (e.g. IO thread) by
       // using NS_DispatchToMainThread().  If the IO thread receives a
       // Message from the parent before nsThreadManager is
       // initialized, then DispatchToMainThread() will fail, although
       // MessagePump will remember the task.  This race condition
       // isn't a problem when appShell->Run() ends up in
       // MessagePump::Run(), because MessagePump will immediate see it
       // has work to do.  It *is* a problem when we end up in [NSApp
       // run], because it's not aware that MessagePump has work that
       // needs to be processed; that was supposed to be signaled by
       // nsIRunnable(s).
-      // 
+      //
       // So instead of hacking Cocoa nsAppShell or rewriting the
       // event-loop system, we compromise here by processing any tasks
       // that might have been enqueued on MessagePump, *before*
       // MessagePump::ScheduleWork was able to successfully
       // DispatchToMainThread().
       MessageLoop* loop = MessageLoop::current();
       bool couldNest = loop->NestableTasksAllowed();
 
--- a/xpcom/build/XREChildData.h
+++ b/xpcom/build/XREChildData.h
@@ -12,34 +12,21 @@
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "mozilla/sandboxing/loggingTypes.h"
 
 namespace sandbox {
 class TargetServices;
 }
 #endif
 
-namespace mozilla {
-namespace gmp {
-class GMPLoader;
-}
-}
-
 /**
  * Data needed to start a child process.
  */
 struct XREChildData
 {
-#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK)
-  /**
-   * Used to load the GMP binary.
-   */
-  mozilla::UniquePtr<mozilla::gmp::GMPLoader> gmpLoader;
-#endif
-
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
   /**
    * Chromium sandbox TargetServices.
    */
   sandbox::TargetServices* sandboxTargetServices = nullptr;
 
   /**
    * Function to provide a logging function to the chromium sandbox code.
--- a/xpcom/string/nsSubstring.cpp
+++ b/xpcom/string/nsSubstring.cpp
@@ -350,23 +350,22 @@ nsStringBuffer::SizeOfIncludingThisEvenI
 #include "nsXPCOMStrings.h"
 
 static_assert(sizeof(nsStringContainer_base) == sizeof(nsSubstring),
               "internal and external strings must have the same size");
 
 // Provide rust bindings to the nsA[C]String types
 extern "C" {
 
-#ifdef DEBUG
-// This is a no-op on release, let's ensure it gives a linker error.
+// This is a no-op on release, when bug 1335203 is fixed we should ifdef this
+// to ensure using it in release results in a linker error.
 void Gecko_IncrementStringAdoptCount(void* aData)
 {
   MOZ_LOG_CTOR(aData, "StringAdopt", 1);
 }
-#endif
 
 void Gecko_FinalizeCString(nsACString* aThis)
 {
   aThis->~nsACString();
 }
 
 void Gecko_AssignCString(nsACString* aThis, const nsACString* aOther)
 {