Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
authorDaniel Varga <dvarga@mozilla.com>
Sat, 13 Oct 2018 00:55:54 +0300
changeset 489351 4b9cd1b9bacb1631aa96c4fd92aa33b660581928
parent 489316 c55cc49537553ce267068a89e7046c3f90cc3c81 (current diff)
parent 489350 067a1c08f91d13f9ad8b7c73b40b2a9065d24c0e (diff)
child 489352 c35df5c273d64a2f495ca5159a91dbc9a5feec32
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersmerge
milestone64.0a1
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
browser/app/profile/firefox.js
dom/media/MediaManager.cpp
dom/media/MediaStreamGraph.h
dom/media/tests/mochitest/test_getUserMedia_stopAudioStream.html
dom/media/tests/mochitest/test_getUserMedia_stopAudioStreamWithFollowupAudio.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStream.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoStream.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoStreamWithFollowupVideo.html
dom/webidl/LocalMediaStream.webidl
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -6,16 +6,18 @@ config/msvc-stl-wrapper.template.h
 dom/base/test/.*
 dom/bindings/test/.*
 dom/media/gtest/.*
 gfx/testsd/.*
 .*/gtest/ExampleStylesheet.h
 image/test/.*
 ipc/ipdl/test/.*
 ipc/testshell/.*
+# Generated code
+js/src/builtin/intl/TimeZoneDataGenerated.h
 js/src/jsapi-tests/.*
 # See bug 1395584
 js/src/vm/Opcodes.h
 # Ignored because of bug 1342657
 layout/style/nsCSSPropAliasList.h
 # Ignored because of bug 1342657
 layout/style/nsCSSPropList.h
 media/mtransport/test/.*
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -79,16 +79,21 @@ if CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += [
         '/browser/app/winlauncher',
     ]
     DELAYLOAD_DLLS += [
         'oleaut32.dll',
         'ole32.dll',
     ]
 
+if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'Darwin':
+    USE_LIBS += [
+        'mozsandbox',
+    ]
+
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
     # For sandbox includes and the include dependencies those have
     LOCAL_INCLUDES += [
         '/security/sandbox/chromium',
         '/security/sandbox/chromium-shim',
     ]
 
     USE_LIBS += [
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -38,16 +38,20 @@
 #include "mozilla/Sprintf.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
 #ifdef LIBFUZZER
 #include "FuzzerDefs.h"
 #endif
 
+#ifdef XP_MACOSX
+#include "mozilla/Sandbox.h"
+#endif
+
 #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
 #include <cpuid.h>
 #include "mozilla/Unused.h"
 
 static bool
 IsSSE2Available()
 {
   // The rest of the app has been compiled to assume that SSE2 is present
@@ -258,16 +262,26 @@ InitXPCOMGlue()
 // NB: This must be extern, as this value is checked elsewhere
 uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
 #endif
 
 int main(int argc, char* argv[], char* envp[])
 {
   mozilla::TimeStamp start = mozilla::TimeStamp::Now();
 
+#ifdef XP_MACOSX
+  if (argc > 1 && IsArg(argv[1], "contentproc")) {
+    std::string err;
+    if (!mozilla::EarlyStartMacSandboxIfEnabled(argc, argv, err)) {
+      Output("Sandbox error: %s\n", err.c_str());
+      MOZ_CRASH("Sandbox initialization failed");
+    }
+  }
+#endif
+
 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
   // We are launching as a content process, delegate to the appropriate
   // main
   if (argc > 1 && IsArg(argv[1], "contentproc")) {
 #ifdef HAS_DLL_BLOCKLIST
     DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
 #endif
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1021,16 +1021,22 @@ pref("security.sandbox.gpu.level", 0);
 
 // Controls whether we disable win32k for the GMP processes.
 // true means that win32k system calls are not permitted.
 // Note: win32k is currently _not_ disabled due to intermittent test failures,
 // where the GMP process fails very early. See bug 1449348.
 pref("security.sandbox.gmp.win32k-disable", false);
 #endif
 
+#if defined(NIGHTLY_BUILD) && defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+// Start the Mac sandbox immediately during child process startup instead
+// of when messaged by the parent after the message loop is running.
+pref("security.sandbox.content.mac.earlyinit", true);
+#endif
+
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
 // This pref is discussed in bug 1083344, the naming is inspired from its
 // Windows counterpart, but on Mac it's an integer which means:
 // 0 -> "no sandbox" (nightly only)
 // 1 -> "preliminary content sandboxing enabled: write access to
 //       home directory is prevented"
 // 2 -> "preliminary content sandboxing enabled with profile protection:
 //       write access to home directory is prevented, read and write access
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1809,16 +1809,36 @@ var gBrowserInit = {
         Cu.reportError(ex);
       }
     }, {timeout: 10000});
 
     if (Win7Features) {
       scheduleIdleTask(() => Win7Features.onOpenWindow());
     }
 
+    scheduleIdleTask(() => {
+      if (Services.prefs.getBoolPref("privacy.resistFingerprinting")) {
+        return;
+      }
+
+      setTimeout(() => {
+        if (window.closed) {
+          return;
+        }
+
+        let browser = gBrowser.selectedBrowser;
+        let browserBounds = window.windowUtils.getBoundsWithoutFlushing(browser);
+
+        Services.telemetry.keyedScalarAdd(
+          "resistfingerprinting.content_window_size",
+          `${browserBounds.width}x${browserBounds.height}`,
+          1);
+      }, 300 * 1000);
+    });
+
     // This should always go last, since the idle tasks (except for the ones with
     // timeouts) should execute in order. Note that this observer notification is
     // not guaranteed to fire, since the window could close before we get here.
     scheduleIdleTask(() => {
       this.idleTasksFinished = true;
       Services.obs.notifyObservers(window, "browser-idle-startup-tasks-finished");
     });
   },
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2173,17 +2173,17 @@ BrowserGlue.prototype = {
       }
     }
   },
 
   // eslint-disable-next-line complexity
   _migrateUI: function BG__migrateUI() {
     // Use an increasing number to keep track of the current migration state.
     // Completely unrelated to the current Firefox release number.
-    const UI_VERSION = 74;
+    const UI_VERSION = 75;
     const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
 
     let currentUIVersion;
     if (Services.prefs.prefHasUserValue("browser.migration.version")) {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } else {
       // This is a new profile, nothing to migrate.
       Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
@@ -2521,16 +2521,20 @@ BrowserGlue.prototype = {
       for (const filename of ["addons.json", "plugins.json", "gfx.json"]) {
         // Some old versions used to dump without subfolders. Clean them while we are at it.
         const path = OS.Path.join(OS.Constants.Path.profileDir, `blocklists-${filename}`);
         OS.File.remove(path, { ignoreAbsent: true });
       }
     }
 
     if (currentUIVersion < 74) {
+      Services.prefs.clearUserPref("browser.search.region");
+    }
+
+    if (currentUIVersion < 75) {
       // Ensure we try to migrate any live bookmarks the user might have, trying up to
       // 5 times. We set this early, and here, to avoid running the migration on
       // new profile (or, indeed, ever creating the pref there).
       Services.prefs.setIntPref("browser.livebookmarks.migrationAttemptsLeft", 5);
     }
 
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
--- a/browser/components/payments/jar.mn
+++ b/browser/components/payments/jar.mn
@@ -21,9 +21,8 @@ browser.jar:
     res/payments/debugging.html                       (res/debugging.html)
     res/payments/debugging.js                         (res/debugging.js)
     res/payments/formautofill/autofillEditForms.js    (../../../browser/extensions/formautofill/content/autofillEditForms.js)
     res/payments/formautofill/editAddress.xhtml       (../../../browser/extensions/formautofill/content/editAddress.xhtml)
     res/payments/formautofill/editCreditCard.xhtml    (../../../browser/extensions/formautofill/content/editCreditCard.xhtml)
     res/payments/unprivileged-fallbacks.js            (res/unprivileged-fallbacks.js)
     res/payments/mixins/                              (res/mixins/*.js)
     res/payments/PaymentsStore.js                     (res/PaymentsStore.js)
-    res/payments/vendor/                              (res/vendor/*)
--- a/browser/components/urlbar/UrlbarController.jsm
+++ b/browser/components/urlbar/UrlbarController.jsm
@@ -1,18 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["QueryContext", "UrlbarController"];
 
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource:///modules/UrlbarProvidersManager.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+  // BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
+  Services: "resource://gre/modules/Services.jsm",
+  UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
+  UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.jsm",
+  UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
+});
 
 /**
  * QueryContext defines a user's autocomplete input from within the Address Bar.
  * It supplements it with details of how the search results should be obtained
  * and what they consist of.
  */
 class QueryContext {
   /**
@@ -73,24 +79,31 @@ class QueryContext {
  * - onQueryResults(queryContext)
  * - onQueryCancelled(queryContext)
  */
 class UrlbarController {
   /**
    * Initialises the class. The manager may be overridden here, this is for
    * test purposes.
    *
-   * @param {object} [options]
+   * @param {object} options
    *   The initial options for UrlbarController.
+   * @param {object} options.window
+   *   The window this controller is operating within.
    * @param {object} [options.manager]
    *   Optional fake providers manager to override the built-in providers manager.
    *   Intended for use in unit tests only.
    */
   constructor(options = {}) {
+    if (!options.window) {
+      throw new Error("Missing options: window");
+    }
+
     this.manager = options.manager || UrlbarProvidersManager;
+    this.window = options.window;
 
     this._listeners = new Set();
   }
 
   /**
    * Takes a query context and starts the query based on the user input.
    *
    * @param {QueryContext} queryContext The query details.
@@ -120,16 +133,114 @@ class UrlbarController {
    *
    * @param {QueryContext} queryContext The query details.
    */
   receiveResults(queryContext) {
     this._notify("onQueryResults", queryContext);
   }
 
   /**
+   * Handles the case where a url or other text has been entered into the
+   * urlbar. This will either load the URL, or some text that could be a keyword
+   * or a simple value to load via the default search engine.
+   *
+   * @param {Event} event The event that triggered this.
+   * @param {string} text The text that was entered into the urlbar.
+   * @param {string} [openWhere] Where we expect the result to be opened.
+   * @param {object} [openParams]
+   *   The parameters related to how and where the result will be opened.
+   *   For possible properties @see {_loadURL}
+   */
+  handleEnteredText(event, text, openWhere, openParams = {}) {
+    let browser = this.window.gBrowser.selectedBrowser;
+    let where = openWhere || this._whereToOpen(event);
+
+    openParams.postData = null;
+    openParams.allowInheritPrincipal = false;
+
+    // TODO: Work out how we get the user selection behavior, probably via passing
+    // it in, since we don't have the old autocomplete controller to work with.
+    // BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
+    //   event, this.userSelectionBehavior);
+
+    text = text.trim();
+
+    try {
+      new URL(text);
+    } catch (ex) {
+      // TODO: Figure out why we need lastLocationChange here.
+      // TODO: Possibly move getShortcutOrURIAndPostData into a utility function
+      // in a jsm (there's nothing window specific about it).
+      // let lastLocationChange = browser.lastLocationChange;
+      // getShortcutOrURIAndPostData(text).then(data => {
+      //   if (where != "current" ||
+      //       browser.lastLocationChange == lastLocationChange) {
+      //     params.postData = data.postData;
+      //     params.allowInheritPrincipal = data.mayInheritPrincipal;
+      //     this._loadURL(data.url, browser, where,
+      //                   openUILinkParams);
+      //   }
+      // });
+      return;
+    }
+
+    this._loadURL(text, browser, where, openParams);
+  }
+
+  /**
+   * Opens a specific result that has been selected.
+   *
+   * @param {Event} event The event that triggered this.
+   * @param {UrlbarMatch} result The result that was selected.
+   * @param {string} [openWhere] Where we expect the result to be opened.
+   * @param {object} [openParams]
+   *   The parameters related to how and where the result will be opened.
+   *   For possible properties @see {_loadURL}
+   */
+  resultSelected(event, result, openWhere, openParams = {}) {
+    // TODO: Work out how we get the user selection behavior, probably via passing
+    // it in, since we don't have the old autocomplete controller to work with.
+    // BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
+    //   event, this.userSelectionBehavior);
+
+    let where = openWhere || this._whereToOpen(event);
+    openParams.postData = null;
+    openParams.allowInheritPrincipal = false;
+    let browser = this.window.gBrowser.selectedBrowser;
+    let url = result.url;
+
+    switch (result.type) {
+      case UrlbarUtils.MATCH_TYPE.TAB_SWITCH: {
+        // TODO: Implement handleRevert or equivalent on the input.
+        // this.input.handleRevert();
+        let prevTab = this.window.gBrowser.selectedTab;
+        let loadOpts = {
+          adoptIntoActiveWindow: UrlbarPrefs.get("switchTabs.adoptIntoActiveWindow"),
+        };
+
+        if (this.window.switchToTabHavingURI(url, false, loadOpts) &&
+            this.window.isTabEmpty(prevTab)) {
+          this.window.gBrowser.removeTab(prevTab);
+        }
+        return;
+
+        // TODO: How to handle meta chars?
+        // Once we get here, we got a TAB_SWITCH match but the user
+        // bypassed it by pressing shift/meta/ctrl. Those modifiers
+        // might otherwise affect where we open - we always want to
+        // open in the current tab.
+        // where = "current";
+
+      }
+    }
+
+    this._loadURL(url, browser, where, openParams);
+  }
+
+  /**
    * Adds a listener for query actions and results.
    *
    * @param {object} listener The listener to add.
    * @throws {TypeError} Throws if the listener is not an object.
    */
   addQueryListener(listener) {
     if (!listener || typeof listener != "object") {
       throw new TypeError("Expected listener to be an object");
@@ -164,9 +275,118 @@ class UrlbarController {
     for (let listener of this._listeners) {
       try {
         listener[name](...params);
       } catch (ex) {
         Cu.reportError(ex);
       }
     }
   }
+
+  /**
+   * Loads the url in the appropriate place.
+   *
+   * @param {string} url
+   *   The URL to open.
+   * @param {object} browser
+   *   The browser to open it in.
+   * @param {string} openUILinkWhere
+   *   Where we expect the result to be opened.
+   * @param {object} params
+   *   The parameters related to how and where the result will be opened.
+   *   Further supported paramters are listed in utilityOverlay.js#openUILinkIn.
+   * @param {object} params.triggeringPrincipal
+   *   The principal that the action was triggered from.
+   * @param {nsIInputStream} [params.postData]
+   *   The POST data associated with a search submission.
+   * @param {boolean} [params.allowInheritPrincipal]
+   *   If the principal may be inherited
+   */
+  _loadURL(url, browser, openUILinkWhere, params) {
+    // TODO: These should probably be set by the input field.
+    // this.value = url;
+    // browser.userTypedValue = url;
+    if (this.window.gInitialPages.includes(url)) {
+      browser.initialPageLoadedFromURLBar = url;
+    }
+    try {
+      // TODO: Move function to PlacesUIUtils.
+      this.window.addToUrlbarHistory(url);
+    } catch (ex) {
+      // Things may go wrong when adding url to session history,
+      // but don't let that interfere with the loading of the url.
+      Cu.reportError(ex);
+    }
+
+    params.allowThirdPartyFixup = true;
+
+    if (openUILinkWhere == "current") {
+      params.targetBrowser = browser;
+      params.indicateErrorPageLoad = true;
+      params.allowPinnedTabHostChange = true;
+      params.allowPopups = url.startsWith("javascript:");
+    } else {
+      params.initiatingDoc = this.window.document;
+    }
+
+    // Focus the content area before triggering loads, since if the load
+    // occurs in a new tab, we want focus to be restored to the content
+    // area when the current tab is re-selected.
+    browser.focus();
+
+    if (openUILinkWhere != "current") {
+      // TODO: Implement handleRevert or equivalent on the input.
+      // this.input.handleRevert();
+    }
+
+    try {
+      this.window.openTrustedLinkIn(url, openUILinkWhere, params);
+    } catch (ex) {
+      // This load can throw an exception in certain cases, which means
+      // we'll want to replace the URL with the loaded URL:
+      if (ex.result != Cr.NS_ERROR_LOAD_SHOWED_ERRORPAGE) {
+        // TODO: Implement handleRevert or equivalent on the input.
+        // this.input.handleRevert();
+      }
+    }
+
+    // TODO This should probably be handed via input.
+    // Ensure the start of the URL is visible for usability reasons.
+    // this.selectionStart = this.selectionEnd = 0;
+  }
+
+  /**
+   * Determines where a URL/page should be opened.
+   *
+   * @param {Event} event the event triggering the opening.
+   * @returns {"current" | "tabshifted" | "tab" | "save" | "window"}
+   */
+  _whereToOpen(event) {
+    let isMouseEvent = event instanceof this.window.MouseEvent;
+    let reuseEmpty = !isMouseEvent;
+    let where = undefined;
+    if (!isMouseEvent && event && event.altKey) {
+      // We support using 'alt' to open in a tab, because ctrl/shift
+      // might be used for canonizing URLs:
+      where = event.shiftKey ? "tabshifted" : "tab";
+    } else if (!isMouseEvent && this._ctrlCanonizesURLs && event && event.ctrlKey) {
+      // If we're allowing canonization, and this is a key event with ctrl
+      // pressed, open in current tab to allow ctrl-enter to canonize URL.
+      where = "current";
+    } else {
+      where = this.window.whereToOpenLink(event, false, false);
+    }
+    if (this.openInTab) {
+      if (where == "current") {
+        where = "tab";
+      } else if (where == "tab") {
+        where = "current";
+      }
+      reuseEmpty = true;
+    }
+    if (where == "tab" &&
+        reuseEmpty &&
+        this.window.isTabEmpty(this.window.gBrowser.selectedTab)) {
+      where = "current";
+    }
+    return where;
+  }
 }
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -39,17 +39,19 @@ class UrlbarInput {
    *   Intended for use in unit tests only.
    */
   constructor(options = {}) {
     this.textbox = options.textbox;
     this.textbox.clickSelectsAll = UrlbarPrefs.get("clickSelectsAll");
 
     this.panel = options.panel;
     this.window = this.textbox.ownerGlobal;
-    this.controller = options.controller || new UrlbarController();
+    this.controller = options.controller || new UrlbarController({
+      window: this.window,
+    });
     this.view = new UrlbarView(this);
     this.valueIsTyped = false;
     this.userInitiatedFocus = false;
     this.isPrivate = PrivateBrowsingUtils.isWindowPrivate(this.window);
 
     // Forward textbox methods and properties.
     const METHODS = ["addEventListener", "removeEventListener",
       "setAttribute", "hasAttribute", "removeAttribute", "getAttribute",
@@ -93,16 +95,17 @@ class UrlbarInput {
     this.inputField.addEventListener("blur", this);
     this.inputField.addEventListener("focus", this);
     this.inputField.addEventListener("mousedown", this);
     this.inputField.addEventListener("mouseover", this);
     this.inputField.addEventListener("overflow", this);
     this.inputField.addEventListener("underflow", this);
     this.inputField.addEventListener("scrollend", this);
     this.inputField.addEventListener("select", this);
+    this.inputField.addEventListener("keyup", this);
 
     this.inputField.controllers.insertControllerAt(0, new CopyCutController(this));
   }
 
   /**
    * Shortens the given value, usually by removing http:// and trailing slashes,
    * such that calling nsIURIFixup::createFixupURI with the result will produce
    * the same URI.
@@ -151,29 +154,89 @@ class UrlbarInput {
     try {
       return Services.uriFixup.createExposableURI(uri);
     } catch (ex) {}
 
     return uri;
   }
 
   /**
-   * Passes DOM events for the textbox to the _on<event type> methods.
+   * Passes DOM events for the textbox to the _on_<event type> methods.
    * @param {Event} event
    *   DOM event from the <textbox>.
    */
   handleEvent(event) {
     let methodName = "_on_" + event.type;
     if (methodName in this) {
       this[methodName](event);
     } else {
       throw "Unrecognized urlbar event: " + event.type;
     }
   }
 
+  /**
+   * Handles an event which would cause a url or text to be opened.
+   * XXX the name is currently handleCommand which is compatible with
+   * urlbarBindings. However, it is no longer called automatically by autocomplete,
+   * See _on_keyup.
+   *
+   * @param {Event} event The event triggering the open.
+   * @param {string} [openWhere] Where we expect the result to be opened.
+   * @param {object} [openParams]
+   *   The parameters related to where the result will be opened.
+   * @param {object} [triggeringPrincipal]
+   *   The principal that the action was triggered from.
+   */
+  handleCommand(event, openWhere, openParams, triggeringPrincipal) {
+    let isMouseEvent = event instanceof this.window.MouseEvent;
+    if (isMouseEvent && event.button == 2) {
+      // Do nothing for right clicks.
+      return;
+    }
+
+    // TODO: Hook up one-off button handling.
+    // Determine whether to use the selected one-off search button.  In
+    // one-off search buttons parlance, "selected" means that the button
+    // has been navigated to via the keyboard.  So we want to use it if
+    // the triggering event is not a mouse click -- i.e., it's a Return
+    // key -- or if the one-off was mouse-clicked.
+    // let selectedOneOff = this.popup.oneOffSearchButtons.selectedButton;
+    // if (selectedOneOff &&
+    //     isMouseEvent &&
+    //     event.originalTarget != selectedOneOff) {
+    //   selectedOneOff = null;
+    // }
+    //
+    // // Do the command of the selected one-off if it's not an engine.
+    // if (selectedOneOff && !selectedOneOff.engine) {
+    //   selectedOneOff.doCommand();
+    //   return;
+    // }
+
+    let url = this.value;
+    if (!url) {
+      return;
+    }
+
+    this.controller.handleEnteredText(event, url);
+
+    this.view.close();
+  }
+
+  /**
+   * Called by the view when a result is selected.
+   *
+   * @param {Event} event The event that selected the result.
+   * @param {UrlbarMatch} result The result that was selected.
+   */
+  resultSelected(event, result) {
+    // TODO: Set the input value to the target url.
+    this.controller.resultSelected(event, result);
+  }
+
   // Getters and Setters below.
 
   get focused() {
     return this.textbox.getAttribute("focused") == "true";
   }
 
   get value() {
     return this.inputField.value;
@@ -410,16 +473,25 @@ class UrlbarInput {
 
   _on_scrollend(event) {
     this._updateTextOverflow();
   }
 
   _on_TabSelect(event) {
     this.controller.tabContextChanged();
   }
+
+  _on_keyup(event) {
+    // TODO: We may have an autoFill entry, so we should use that instead.
+    // TODO: We should have an input bufferrer so that we can use search results
+    // if appropriate.
+    if (event.key == "Enter") {
+      this.handleCommand(event);
+    }
+  }
 }
 
 /**
  * Handles copy and cut commands for the urlbar.
  */
 class CopyCutController {
   /**
    * @param {UrlbarInput} urlbar
--- a/browser/components/urlbar/UrlbarPrefs.jsm
+++ b/browser/components/urlbar/UrlbarPrefs.jsm
@@ -103,16 +103,20 @@ const PREF_URLBAR_DEFAULTS = new Map([
   ["suggest.history.onlyTyped", false],
 
   // Results will include switch-to-tab results when this is true.
   ["suggest.openpage", true],
 
   // Results will include search suggestions when this is true.
   ["suggest.searches", false],
 
+  // When using switch to tabs, if set to true this will move the tab into the
+  // active window.
+  ["switchTabs.adoptIntoActiveWindow", false],
+
   // Remove redundant portions from URLs.
   ["trimURLs", true],
 
   // Results will include a built-in set of popular domains when this is true.
   ["usepreloadedtopurls.enabled", true],
 
   // After this many days from the profile creation date, the built-in set of
   // popular domains will no longer be included in the results.
--- a/browser/components/urlbar/UrlbarView.jsm
+++ b/browser/components/urlbar/UrlbarView.jsm
@@ -70,46 +70,51 @@ class UrlbarView {
 
     this._rows.firstElementChild.toggleAttribute("selected", true);
   }
 
   /**
    * Closes the autocomplete results popup.
    */
   close() {
+    this.panel.hidePopup();
   }
 
   // UrlbarController listener methods.
   onQueryStarted(queryContext) {
     this._rows.textContent = "";
   }
 
   onQueryResults(queryContext) {
     // XXX For now, clear the results for each set received. We should really
     // be updating the existing list.
     this._rows.textContent = "";
-    for (let result of queryContext.results) {
-      this._addRow(result);
+    this._queryContext = queryContext;
+    for (let resultIndex in queryContext.results) {
+      this._addRow(resultIndex);
     }
     this.open();
   }
 
   // Private methods below.
 
   _getBoundsWithoutFlushing(element) {
     return this.window.windowUtils.getBoundsWithoutFlushing(element);
   }
 
   _createElement(name) {
     return this.document.createElementNS("http://www.w3.org/1999/xhtml", name);
   }
 
-  _addRow(result) {
+  _addRow(resultIndex) {
+    let result = this._queryContext.results[resultIndex];
     let item = this._createElement("div");
     item.className = "urlbarView-row";
+    item.addEventListener("click", this);
+    item.setAttribute("resultIndex", resultIndex);
     if (result.type == UrlbarUtils.MATCH_TYPE.TAB_SWITCH) {
       item.setAttribute("action", "switch-to-tab");
     }
 
     let content = this._createElement("span");
     content.className = "urlbarView-row-inner";
     item.appendChild(content);
 
@@ -134,9 +139,36 @@ class UrlbarView {
     } else {
       secondary.classList.add("urlbarView-url");
       secondary.textContent = result.url;
     }
     content.appendChild(secondary);
 
     this._rows.appendChild(item);
   }
+
+  /**
+   * Passes DOM events for the view to the _on_<event type> methods.
+   * @param {Event} event
+   *   DOM event from the <view>.
+   */
+  handleEvent(event) {
+    let methodName = "_on_" + event.type;
+    if (methodName in this) {
+      this[methodName](event);
+    } else {
+      throw "Unrecognized urlbar event: " + event.type;
+    }
+  }
+
+  _on_click(event) {
+    let row = event.target;
+    while (!row.classList.contains("urlbarView-row")) {
+      row = row.parentNode;
+    }
+    let resultIndex = row.getAttribute("resultIndex");
+    let result = this._queryContext.results[resultIndex];
+    if (result) {
+      this.urlbar.resultSelected(event, result);
+    }
+    this.close();
+  }
 }
--- a/browser/components/urlbar/tests/browser/browser.ini
+++ b/browser/components/urlbar/tests/browser/browser.ini
@@ -1,8 +1,11 @@
 # 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/.
 
 [DEFAULT]
+support-files =
+  head.js
 
+[browser_UrlbarController_resultOpening.js]
 [browser_UrlbarInput_unit.js]
 support-files = empty.xul
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/browser/browser_UrlbarController_resultOpening.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * These tests unit test the result/url loading functionality of UrlbarController.
+ */
+
+"use strict";
+
+let controller;
+
+add_task(async function setup() {
+  sandbox = sinon.sandbox.create();
+
+  controller = new UrlbarController({
+    window,
+  });
+
+  registerCleanupFunction(async () => {
+    sandbox.restore();
+  });
+});
+
+add_task(function test_handleEnteredText_url() {
+  sandbox.stub(window, "openTrustedLinkIn");
+
+  const event = new KeyboardEvent("keyup", {key: "Enter"});
+  // Additional spaces in the url to check that we trim correctly.
+  controller.handleEnteredText(event, " https://example.com ");
+
+  Assert.ok(window.openTrustedLinkIn.calledOnce,
+    "Should have triggered opening the url.");
+
+  let args = window.openTrustedLinkIn.args[0];
+
+  Assert.equal(args[0], "https://example.com",
+    "Should have triggered opening with the correct url");
+  Assert.equal(args[1], "current",
+    "Should be opening in the current browser");
+  Assert.deepEqual(args[2], {
+    allowInheritPrincipal: false,
+    allowPinnedTabHostChange: true,
+    allowPopups: false,
+    allowThirdPartyFixup: true,
+    indicateErrorPageLoad: true,
+    postData: null,
+    targetBrowser: gBrowser.selectedBrowser,
+  }, "Should have the correct additional parameters for opening");
+
+  sandbox.restore();
+});
+
+add_task(function test_resultSelected_switchtab() {
+  sandbox.stub(window, "switchToTabHavingURI").returns(true);
+  sandbox.stub(window, "isTabEmpty").returns(false);
+  sandbox.stub(window.gBrowser, "removeTab");
+
+  const event = new MouseEvent("click", {button: 0});
+  const url = "https://example.com/1";
+  const result = new UrlbarMatch(UrlbarUtils.MATCH_TYPE.TAB_SWITCH, {url});
+
+  controller.resultSelected(event, result);
+
+  Assert.ok(window.switchToTabHavingURI.calledOnce,
+    "Should have triggered switching to the tab");
+
+  let args = window.switchToTabHavingURI.args[0];
+
+  Assert.equal(args[0], url, "Should have passed the expected url");
+  Assert.ok(!args[1], "Should not attempt to open a new tab");
+  Assert.deepEqual(args[2], {
+    adoptIntoActiveWindow: UrlbarPrefs.get("switchTabs.adoptIntoActiveWindow"),
+  }, "Should have the correct additional parameters for opening");
+
+  sandbox.restore();
+});
--- a/browser/components/urlbar/tests/browser/browser_UrlbarInput_unit.js
+++ b/browser/components/urlbar/tests/browser/browser_UrlbarInput_unit.js
@@ -4,30 +4,20 @@
 /**
  * These tests unit test the functionality of UrlbarController by stubbing out the
  * model and providing stubs to be called.
  */
 
 "use strict";
 
 let fakeController;
-let sandbox;
 let generalListener;
 let input;
 let inputOptions;
 
-ChromeUtils.import("resource:///modules/UrlbarController.jsm", this);
-
-/* global sinon */
-Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
-
-registerCleanupFunction(function() {
-  delete window.sinon;
-});
-
 /**
  * Asserts that the query context has the expected values.
  *
  * @param {QueryContext} context
  * @param {object} expectedValues The expected values for the QueryContext.
  */
 function assertContextMatches(context, expectedValues) {
   Assert.ok(context instanceof QueryContext,
@@ -64,17 +54,19 @@ function checkStartQueryCall(stub, expec
     Assert.deepEqual(queryContext[name],
      value, `Should have the correct value for queryContext.${name}`);
   }
 }
 
 add_task(async function setup() {
   sandbox = sinon.sandbox.create();
 
-  fakeController = new UrlbarController();
+  fakeController = new UrlbarController({
+    window,
+  });
 
   sandbox.stub(fakeController, "startQuery");
   sandbox.stub(PrivateBrowsingUtils, "isWindowPrivate").returns(false);
 
   // Open a new window, so we don't affect other tests by adding extra
   // UrbarInput wrappers around the urlbar.
   let gTestRoot = getRootDirectory(gTestPath);
 
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/browser/head.js
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * These tests unit test the result/url loading functionality of UrlbarController.
+ */
+
+"use strict";
+
+let sandbox;
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+  Services: "resource://gre/modules/Services.jsm",
+  QueryContext: "resource:///modules/UrlbarController.jsm",
+  UrlbarController: "resource:///modules/UrlbarController.jsm",
+  UrlbarMatch: "resource:///modules/UrlbarMatch.jsm",
+  UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
+});
+
+/* global sinon */
+Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
+
+registerCleanupFunction(function() {
+  delete window.sinon;
+});
--- a/browser/components/urlbar/tests/unit/test_UrlbarController_integration.js
+++ b/browser/components/urlbar/tests/unit/test_UrlbarController_integration.js
@@ -25,17 +25,19 @@ function assertContextMatches(context, e
 
   for (let [key, value] of Object.entries(expectedValues)) {
     Assert.equal(context[key], value,
       `Should have the expected value for ${key} in the QueryContext`);
   }
 }
 
 add_task(async function setup() {
-  controller = new UrlbarController();
+  controller = new UrlbarController({
+    window: {},
+  });
 });
 
 add_task(async function test_basic_search() {
   const context = createContext(TEST_URL);
 
   registerBasicTestProvider([match]);
 
   let startedPromise = promiseControllerNotification(controller, "onQueryStarted");
--- a/browser/components/urlbar/tests/unit/test_UrlbarController_unit.js
+++ b/browser/components/urlbar/tests/unit/test_UrlbarController_unit.js
@@ -41,16 +41,17 @@ add_task(function setup() {
   generalListener = {
     onQueryStarted: sandbox.stub(),
     onQueryResults: sandbox.stub(),
     onQueryCancelled: sandbox.stub(),
   };
 
   controller = new UrlbarController({
     manager: fPM,
+    window: {},
   });
   controller.addQueryListener(generalListener);
 });
 
 add_task(function test_add_and_remove_listeners() {
   Assert.throws(() => controller.addQueryListener(null),
     /Expected listener to be an object/,
     "Should throw for a null listener");
--- a/browser/components/urlbar/tests/unit/test_providersManager.js
+++ b/browser/components/urlbar/tests/unit/test_providersManager.js
@@ -3,17 +3,19 @@
 
 "use strict";
 
 add_task(async function test_providers() {
   let match = new UrlbarMatch(UrlbarUtils.MATCH_TYPE.TAB_SWITCH, { url: "http://mozilla.org/foo/" });
   registerBasicTestProvider([match]);
 
   let context = createContext();
-  let controller = new UrlbarController();
+  let controller = new UrlbarController({
+    window: {},
+  });
   let resultsPromise = promiseControllerNotification(controller, "onQueryResults");
 
   await UrlbarProvidersManager.startQuery(context, controller);
   // Sanity check that this doesn't throw. It should be a no-op since we await
   // for startQuery.
   UrlbarProvidersManager.cancelQuery(context);
 
   let params = await resultsPromise;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -189,16 +189,17 @@
 #ifdef XP_WIN
 #include <process.h>
 #define getpid _getpid
 #include "mozilla/widget/AudioSession.h"
 #include "mozilla/audio/AudioNotificationReceiver.h"
 #endif
 
 #if defined(XP_MACOSX)
+#include "nsMacUtilsImpl.h"
 #include <CoreServices/CoreServices.h>
 // Info.plist key associated with the developer repo path
 #define MAC_DEV_REPO_KEY "MozillaDeveloperRepoPath"
 // Info.plist key associated with the developer repo object directory
 #define MAC_DEV_OBJ_KEY "MozillaDeveloperObjPath"
 #endif /* XP_MACOSX */
 
 #ifdef MOZ_X11
@@ -1518,120 +1519,16 @@ ContentChild::RecvReinitRenderingForDevi
     if (tabChild->GetLayersId().IsValid()) {
       tabChild->ReinitRenderingForDeviceReset();
     }
   }
   return IPC_OK();
 }
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
-
-#include <stdlib.h>
-
-static bool
-GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath, nsCString &aAppDir)
-{
-  nsAutoCString appPath;
-  nsAutoCString appBinaryPath(
-    (CommandLine::ForCurrentProcess()->argv()[0]).c_str());
-
-  nsAutoCString::const_iterator start, end;
-  appBinaryPath.BeginReading(start);
-  appBinaryPath.EndReading(end);
-  if (RFindInReadable(NS_LITERAL_CSTRING(".app/Contents/MacOS/"), start, end)) {
-    end = start;
-    ++end; ++end; ++end; ++end;
-    appBinaryPath.BeginReading(start);
-    appPath.Assign(Substring(start, end));
-  } else {
-    return false;
-  }
-
-  nsCOMPtr<nsIFile> app, appBinary;
-  nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appPath),
-                                true, getter_AddRefs(app));
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appBinaryPath),
-                       true, getter_AddRefs(appBinary));
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-
-  nsCOMPtr<nsIFile> appDir;
-  nsCOMPtr<nsIProperties> dirSvc =
-    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
-  if (!dirSvc) {
-    return false;
-  }
-  rv = dirSvc->Get(NS_GRE_DIR,
-                   NS_GET_IID(nsIFile), getter_AddRefs(appDir));
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-  bool exists;
-  rv = appDir->Exists(&exists);
-  if (NS_FAILED(rv) || !exists) {
-    return false;
-  }
-
-  // appDir points to .app/Contents/Resources, for our purposes we want
-  // .app/Contents.
-  nsCOMPtr<nsIFile> appDirParent;
-  rv = appDir->GetParent(getter_AddRefs(appDirParent));
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-
-  rv = app->Normalize();
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-  app->GetNativePath(aAppPath);
-
-  rv = appBinary->Normalize();
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-  appBinary->GetNativePath(aAppBinaryPath);
-
-  rv = appDirParent->Normalize();
-  if (NS_FAILED(rv)) {
-    return false;
-  }
-  appDirParent->GetNativePath(aAppDir);
-
-  return true;
-}
-
-// This function is only used in an |#ifdef DEBUG| path.
-#ifdef DEBUG
-// Given a path to a file, return the directory which contains it.
-static nsAutoCString
-GetDirectoryPath(const char *aPath) {
-  nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
-  if (!file ||
-      NS_FAILED(file->InitWithNativePath(nsDependentCString(aPath)))) {
-    MOZ_CRASH("Failed to create or init an nsIFile");
-  }
-  nsCOMPtr<nsIFile> directoryFile;
-  if (NS_FAILED(file->GetParent(getter_AddRefs(directoryFile))) ||
-      !directoryFile) {
-    MOZ_CRASH("Failed to get parent for an nsIFile");
-  }
-  directoryFile->Normalize();
-  nsAutoCString directoryPath;
-  if (NS_FAILED(directoryFile->GetNativePath(directoryPath))) {
-    MOZ_CRASH("Failed to get path for an nsIFile");
-  }
-  return directoryPath;
-}
-#endif // DEBUG
-
 extern "C" {
 CGError
 CGSSetDenyWindowServerConnections(bool);
 void CGSShutdownServerConnections();
 };
 
 static bool
 StartMacOSContentSandbox()
@@ -1653,19 +1550,19 @@ StartMacOSContentSandbox()
         "security.sandbox.content.mac.disconnect-windowserver")) {
     CGError result = CGSSetDenyWindowServerConnections(true);
     MOZ_DIAGNOSTIC_ASSERT(result == kCGErrorSuccess);
 #if !MOZ_DIAGNOSTIC_ASSERT_ENABLED
     Unused << result;
 #endif
   }
 
-  nsAutoCString appPath, appBinaryPath, appDir;
-  if (!GetAppPaths(appPath, appBinaryPath, appDir)) {
-    MOZ_CRASH("Error resolving child process path");
+  nsAutoCString appPath;
+  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
+    MOZ_CRASH("Error resolving child process app path");
   }
 
   ContentChild* cc = ContentChild::GetSingleton();
 
   nsresult rv;
   nsCOMPtr<nsIFile> profileDir;
   cc->GetProfileDir(getter_AddRefs(profileDir));
   nsCString profileDirPath;
@@ -1681,19 +1578,19 @@ StartMacOSContentSandbox()
 
   MacSandboxInfo info;
   info.type = MacSandboxType_Content;
   info.level = sandboxLevel;
   info.hasFilePrivileges = isFileProcess;
   info.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
                    PR_GetEnv("MOZ_SANDBOX_LOGGING");
   info.appPath.assign(appPath.get());
-  info.appBinaryPath.assign(appBinaryPath.get());
-  info.appDir.assign(appDir.get());
   info.hasAudio = !Preferences::GetBool("media.cubeb.sandbox");
+  info.hasWindowServer = !Preferences::GetBool(
+      "security.sandbox.content.mac.disconnect-windowserver");
 
   // These paths are used to whitelist certain directories used by the testing
   // system. They should not be considered a public API, and are only intended
   // for use in automation.
   nsAutoCString testingReadPath1;
   Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
                           testingReadPath1);
   if (!testingReadPath1.IsEmpty()) {
@@ -1737,17 +1634,18 @@ StartMacOSContentSandbox()
 #ifdef DEBUG
   // When a content process dies intentionally (|NoteIntentionalCrash|), for
   // tests it wants to log that it did this. Allow writing to this location
   // that the testrunner wants.
   char *bloatLog = PR_GetEnv("XPCOM_MEM_BLOAT_LOG");
   if (bloatLog != nullptr) {
     // |bloatLog| points to a specific file, but we actually write to a sibling
     // of that path.
-    nsAutoCString bloatDirectoryPath = GetDirectoryPath(bloatLog);
+    nsAutoCString bloatDirectoryPath =
+      nsMacUtilsImpl::GetDirectoryPath(bloatLog);
     info.debugWriteDir.assign(bloatDirectoryPath.get());
   }
 #endif // DEBUG
 
   std::string err;
   if (!mozilla::StartMacSandbox(info, err)) {
     NS_WARNING(err.c_str());
     MOZ_CRASH("sandbox_init() failed");
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -105,25 +105,27 @@
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TelemetryIPC.h"
 #include "mozilla/WebBrowserPersistDocumentParent.h"
 #include "mozilla/widget/ScreenManager.h"
 #include "mozilla/Unused.h"
 #include "mozilla/HangDetails.h"
 #include "nsAnonymousTemporaryFile.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "nsAppRunner.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsCExternalHandlerService.h"
 #include "nsCOMPtr.h"
 #include "nsChromeRegistryChrome.h"
 #include "nsConsoleMessage.h"
 #include "nsConsoleService.h"
 #include "nsContentUtils.h"
 #include "nsDebugImpl.h"
+#include "nsDirectoryService.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsEmbedCID.h"
 #include "nsFrameLoader.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
 #include "nsICookie.h"
@@ -209,16 +211,20 @@
 #include "nsLayoutStylesheetCache.h"
 
 #include "mozilla/Sprintf.h"
 
 #ifdef MOZ_WEBRTC
 #include "signaling/src/peerconnection/WebrtcGlobalParent.h"
 #endif
 
+#if defined(XP_MACOSX)
+#include "nsMacUtilsImpl.h"
+#endif
+
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #if defined(XP_LINUX)
 #include "mozilla/Hal.h"
 #endif
 
@@ -604,16 +610,20 @@ static const char* sObserverTopics[] = {
   "cacheservice:empty-cache",
   "intl:app-locales-changed",
   "intl:requested-locales-changed",
   "cookie-changed",
   "private-cookie-changed",
   "clear-site-data-reload-needed",
 };
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+bool ContentParent::sEarlySandboxInit = false;
+#endif
+
 // PreallocateProcess is called by the PreallocatedProcessManager.
 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::PreallocateProcess()
 {
   RefPtr<ContentParent> process =
     new ContentParent(/* aOpener = */ nullptr,
                       NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
@@ -2125,16 +2135,130 @@ ContentParent::DestroyTestShell(TestShel
 
 TestShellParent*
 ContentParent::GetTestShellSingleton()
 {
   PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent());
   return static_cast<TestShellParent*>(p);
 }
 
+#ifdef XP_MACOSX
+void
+ContentParent::AppendSandboxParams(std::vector<std::string> &aArgs)
+{
+  nsCOMPtr<nsIProperties>
+    directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
+  if (!directoryService) {
+    MOZ_CRASH("Failed to get the directory service");
+  }
+
+  // Indicates the child should startup the sandbox
+  aArgs.push_back("-sbStartup");
+
+  // The content sandbox level
+  int contentSandboxLevel =
+    Preferences::GetInt("security.sandbox.content.level");
+  std::ostringstream os;
+  os << contentSandboxLevel;
+  std::string contentSandboxLevelString = os.str();
+  aArgs.push_back("-sbLevel");
+  aArgs.push_back(contentSandboxLevelString);
+
+  // Sandbox logging
+  if (Preferences::GetBool("security.sandbox.logging.enabled") ||
+      PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
+    aArgs.push_back("-sbLogging");
+  }
+
+  // For file content processes
+  if (GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE)) {
+    aArgs.push_back("-sbAllowFileAccess");
+  }
+
+  // Audio access
+  if (!Preferences::GetBool("media.cubeb.sandbox")) {
+    aArgs.push_back("-sbAllowAudio");
+  }
+
+  // Windowserver access
+  if (!Preferences::GetBool("security.sandbox.content.mac.disconnect-windowserver")) {
+    aArgs.push_back("-sbAllowWindowServer");
+  }
+
+  // .app path (normalized)
+  nsAutoCString appPath;
+  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
+    MOZ_CRASH("Failed to get app dir paths");
+  }
+  aArgs.push_back("-sbAppPath");
+  aArgs.push_back(appPath.get());
+
+  // TESTING_READ_PATH1
+  nsAutoCString testingReadPath1;
+  Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
+                          testingReadPath1);
+  if (!testingReadPath1.IsEmpty()) {
+    aArgs.push_back("-sbTestingReadPath");
+    aArgs.push_back(testingReadPath1.get());
+  }
+
+  // TESTING_READ_PATH2
+  nsAutoCString testingReadPath2;
+  Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
+                          testingReadPath2);
+  if (!testingReadPath2.IsEmpty()) {
+    aArgs.push_back("-sbTestingReadPath");
+    aArgs.push_back(testingReadPath2.get());
+  }
+
+  // TESTING_READ_PATH3, TESTING_READ_PATH4. In development builds,
+  // these are used to whitelist the repo dir and object dir respectively.
+  nsresult rv;
+  if (mozilla::IsDevelopmentBuild()) {
+    // Repo dir
+    nsCOMPtr<nsIFile> repoDir;
+    rv = mozilla::GetRepoDir(getter_AddRefs(repoDir));
+    if (NS_FAILED(rv)) {
+      MOZ_CRASH("Failed to get path to repo dir");
+    }
+    nsCString repoDirPath;
+    Unused << repoDir->GetNativePath(repoDirPath);
+    aArgs.push_back("-sbTestingReadPath");
+    aArgs.push_back(repoDirPath.get());
+
+    // Object dir
+    nsCOMPtr<nsIFile> objDir;
+    rv = mozilla::GetObjDir(getter_AddRefs(objDir));
+    if (NS_FAILED(rv)) {
+      MOZ_CRASH("Failed to get path to build object dir");
+    }
+    nsCString objDirPath;
+    Unused << objDir->GetNativePath(objDirPath);
+    aArgs.push_back("-sbTestingReadPath");
+    aArgs.push_back(objDirPath.get());
+  }
+
+  // DEBUG_WRITE_DIR
+#ifdef DEBUG
+  // When a content process dies intentionally (|NoteIntentionalCrash|), for
+  // tests it wants to log that it did this. Allow writing to this location
+  // that the testrunner wants.
+  char *bloatLog = PR_GetEnv("XPCOM_MEM_BLOAT_LOG");
+  if (bloatLog != nullptr) {
+    // |bloatLog| points to a specific file, but we actually write to a sibling
+    // of that path.
+    nsAutoCString bloatDirectoryPath =
+      nsMacUtilsImpl::GetDirectoryPath(bloatLog);
+    aArgs.push_back("-sbDebugWriteDir");
+    aArgs.push_back(bloatDirectoryPath.get());
+  }
+#endif // DEBUG
+}
+#endif // XP_MACOSX
+
 bool
 ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */)
 {
   AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
 
   if (!ContentProcessManager::GetSingleton()) {
     // Shutdown has begun, we shouldn't spawn any more child processes.
     return false;
@@ -2213,16 +2337,25 @@ ContentParent::LaunchSubprocess(ProcessP
   nsPrintfCString schedulerPrefs = Scheduler::GetPrefs();
   extraArgs.push_back("-schedulerPrefs");
   extraArgs.push_back(schedulerPrefs.get());
 
   if (gSafeMode) {
     extraArgs.push_back("-safeMode");
   }
 
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  // If we're launching a middleman process for a
+  // recording or replay, start the sandbox later.
+  if (sEarlySandboxInit && IsContentSandboxEnabled() &&
+      !IsRecordingOrReplaying()) {
+    AppendSandboxParams(extraArgs);
+  }
+#endif
+
   nsCString parentBuildID(mozilla::PlatformBuildID());
   extraArgs.push_back("-parentBuildID");
   extraArgs.push_back(parentBuildID.get());
 
   // Specify whether the process is recording or replaying an execution.
   if (mRecordReplayState != eNotRecordingOrReplaying) {
     nsPrintfCString buf("%d", mRecordReplayState == eRecording
                               ? (int) recordreplay::ProcessKind::MiddlemanRecording
@@ -2332,16 +2465,27 @@ ContentParent::ContentParent(ContentPare
   // channel. Generally only applies to the situation where we get caught in
   // a deadlock with the plugin process when sending CPOWs.
   GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
 
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   bool isFile = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE);
   mSubprocess = new ContentProcessHost(this, isFile);
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  // sEarlySandboxInit is statically initialized to false.
+  // Once we've set it to true due to the pref, avoid checking the
+  // pref on subsequent calls. As a result, changing the earlyinit
+  // pref requires restarting the browser to take effect.
+  if (!ContentParent::sEarlySandboxInit) {
+    ContentParent::sEarlySandboxInit =
+      Preferences::GetBool("security.sandbox.content.mac.earlyinit");
+  }
+#endif
 }
 
 ContentParent::~ContentParent()
 {
   if (mForceKillTimer) {
     mForceKillTimer->Cancel();
   }
 
@@ -2602,16 +2746,25 @@ ContentParent::InitInternal(ProcessPrior
   MaybeFileDesc brokerFd = void_t();
   // XXX: Checking the pref here makes it possible to enable/disable sandboxing
   // during an active session. Currently the pref is only used for testing
   // purpose. If the decision is made to permanently rely on the pref, this
   // should be changed so that it is required to restart firefox for the change
   // of value to take effect.
   shouldSandbox = IsContentSandboxEnabled();
 
+#ifdef XP_MACOSX
+  // If the sandbox was initialized during content process
+  // startup, we must not send the SetProcessSandbox message.
+  // If early startup was pref'd off or the process is a
+  // middleman process, send SetProcessSandbox now.
+  shouldSandbox = shouldSandbox &&
+    (!sEarlySandboxInit || IsRecordingOrReplaying());
+#endif
+
 #ifdef XP_LINUX
   if (shouldSandbox) {
     MOZ_ASSERT(!mSandboxBroker);
     bool isFileProcess = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE);
     UniquePtr<SandboxBroker::Policy> policy =
       sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
     if (policy) {
       brokerFd = FileDescriptor();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1257,16 +1257,18 @@ public:
 
   virtual mozilla::ipc::IPCResult
   RecvStoreUserInteractionAsPermission(const Principal& aPrincipal) override;
 
   // Notify the ContentChild to enable the input event prioritization when
   // initializing.
   void MaybeEnableRemoteInputEventQueue();
 
+  void AppendSandboxParams(std::vector<std::string>& aArgs);
+
 public:
   void SendGetFilesResponseAndForget(const nsID& aID,
                                      const GetFilesResponseResult& aResult);
 
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
                                const MaybeFileDesc& aDMDFile) override;
@@ -1382,16 +1384,23 @@ private:
   nsTHashtable<nsCStringHashKey> mActivePermissionKeys;
 
   nsTArray<nsCString> mBlobURLs;
 
   UniquePtr<mozilla::ipc::CrashReporterHost> mCrashReporter;
 
   static uint64_t sNextTabParentId;
   static nsDataHashtable<nsUint64HashKey, TabParent*> sNextTabParents;
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+  // When set to true, indicates that content processes should
+  // initialize their sandbox during startup instead of waiting
+  // for the SetProcessSandbox IPDL message.
+  static bool sEarlySandboxInit;
+#endif
 };
 
 } // namespace dom
 } // namespace mozilla
 
 class ParentIdleListener : public nsIObserver
 {
   friend class mozilla::dom::ContentParent;
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -9,16 +9,17 @@
 #include "ContentProcess.h"
 #include "base/shared_memory.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Scheduler.h"
 #include "mozilla/recordreplay/ParentIPC.h"
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
 #include <stdlib.h>
+#include "mozilla/Sandbox.h"
 #endif
 
 #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/SandboxSettings.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceDefs.h"
 #endif
@@ -291,17 +292,26 @@ ContentProcess::Init(int aArgc, char* aA
                 *parentBuildID,
                 IOThreadChild::channel(),
                 *childID,
                 *isForBrowser);
 
   mXREEmbed.Start();
 #if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
   mContent.SetProfileDir(profileDir);
-#endif
+#if defined(DEBUG)
+  // For WebReplay middleman processes, the sandbox is
+  // started after receiving the SetProcessSandbox message.
+  if (IsContentSandboxEnabled() &&
+      Preferences::GetBool("security.sandbox.content.mac.earlyinit") &&
+      !recordreplay::IsMiddleman()) {
+    AssertMacSandboxEnabled();
+  }
+#endif /* DEBUG */
+#endif /* XP_MACOSX && MOZ_CONTENT_SANDBOX */
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
   SetUpSandboxEnvironment();
 #endif
 
   return true;
 }
 
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaManager.h"
 
 #include "AllocationHandle.h"
+#include "AudioDeviceInfo.h"
 #include "MediaStreamGraph.h"
 #include "MediaTimer.h"
 #include "mozilla/dom/MediaStreamTrack.h"
 #include "mozilla/dom/MediaDeviceInfo.h"
 #include "MediaStreamListener.h"
 #include "nsArray.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -579,19 +579,26 @@ GLContextEGL::CreateGLContext(CreateCont
     std::vector<EGLint> robustness_attribs;
     std::vector<EGLint> rbab_attribs; // RBAB: Robust Buffer Access Behavior
     if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
         if (egl->IsExtensionSupported(GLLibraryEGL::EXT_create_context_robustness)) {
             robustness_attribs = required_attribs;
             robustness_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
             robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
 
-            rbab_attribs = robustness_attribs;
-            rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
-            rbab_attribs.push_back(LOCAL_EGL_TRUE);
+            // Don't enable robust buffer access on Adreno 630 devices.
+            // It causes the linking of some shaders to fail. See bug 1485441.
+            nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+            nsAutoString renderer;
+            gfxInfo->GetAdapterDeviceID(renderer);
+            if (renderer.Find("Adreno (TM) 630") == -1) {
+                rbab_attribs = robustness_attribs;
+                rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
+                rbab_attribs.push_back(LOCAL_EGL_TRUE);
+            }
         } else if (egl->IsExtensionSupported(GLLibraryEGL::KHR_create_context)) {
             robustness_attribs = required_attribs;
             robustness_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
             robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
 
             rbab_attribs = robustness_attribs;
             rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
             rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -518,20 +518,29 @@ CompositorBridgeParent::StopAndClearReso
         lts->mParent = nullptr;
       });
     }
     for (const RefPtr<WebRenderBridgeParent>& bridge : indirectBridgeParents) {
       bridge->Destroy();
     }
     indirectBridgeParents.clear();
 
+    RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
     // Ensure we are not holding the sIndirectLayerTreesLock here because we
     // are going to block on WR threads in order to shut it down properly.
     mWrBridge->Destroy();
     mWrBridge = nullptr;
+
+    if (api) {
+      // Make extra sure we are done cleaning WebRender up before continuing.
+      // After that we wont have a way to talk to a lot of the webrender parts.
+      api->FlushSceneBuilder();
+      api = nullptr;
+    }
+
     if (mAsyncImageManager) {
       mAsyncImageManager->Destroy();
       // WebRenderAPI should be already destructed
       mAsyncImageManager = nullptr;
     }
   }
 
   if (mCompositor) {
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1841,23 +1841,16 @@ WebRenderBridgeParent::ClearResources()
   }
   mActiveAnimations.clear();
   std::queue<CompositorAnimationIdsForEpoch>().swap(mCompositorAnimationsToDelete); // clear queue
 
   if (IsRootWebRenderBridgeParent()) {
     mCompositorScheduler->Destroy();
   }
 
-  // Before tearing down mApi we should make sure the above transaction has been
-  // flushed back to the render backend thread. Otherwise the cleanup messages
-  // that the WebRenderAPI destructor triggers can race ahead of the transaction
-  // (because it goes directly to the RB thread, bypassing the scene builder
-  // thread) and clear caches etc. that are still in use.
-  FlushSceneBuilds();
-
   mAnimStorage = nullptr;
   mCompositorScheduler = nullptr;
   mAsyncImageManager = nullptr;
   mApi = nullptr;
   mCompositorBridge = nullptr;
 }
 
 bool
--- a/gfx/src/FontPropertyTypes.h
+++ b/gfx/src/FontPropertyTypes.h
@@ -48,25 +48,22 @@ namespace mozilla {
  * get created, particularly when styles are animated or set to arbitrary
  * values (e.g. by sliders in the UI), which should reduce pressure on
  * graphics resources and improve cache hit rates.
  */
 template<class InternalType, unsigned FractionBits, int Min, int Max>
 class FontPropertyValue
 {
 public:
-  // Ugh. We need a default constructor to allow this type to be used in the
-  // union in nsCSSValue. Furthermore we need the default and copy
-  // constructors to be "trivial" (i.e. the compiler implemented defaults that
-  // do no initialization).
-  // Annoyingly we can't make the default implementations constexpr (at least
-  // in clang). That would be nice to do in order to allow the methods of
-  // subclasses that always return the same value (e.g., FontWeight::Thin())
-  // to also be constexpr. :/
-  FontPropertyValue() = default;
+  // Initialize to the minimum value by default.
+  constexpr FontPropertyValue()
+    : FontPropertyValue(Min)
+  {
+  }
+
   explicit FontPropertyValue(const FontPropertyValue& aOther) = default;
   FontPropertyValue& operator=(const FontPropertyValue& aOther) = default;
 
   bool operator==(const FontPropertyValue& aOther) const
   {
     return mValue == aOther.mValue;
   }
   bool operator!=(const FontPropertyValue& aOther) const
@@ -105,31 +102,31 @@ public:
   }
 
   static constexpr const float kMin = float(Min);
   static constexpr const float kMax = float(Max);
 
 protected:
   // Construct from a floating-point or integer value, checking that it is
   // within the allowed range and converting to fixed-point representation.
-  explicit FontPropertyValue(float aValue)
+  explicit constexpr FontPropertyValue(float aValue)
     : mValue(std::round(aValue * kScale))
   {
     MOZ_ASSERT(aValue >= kMin && aValue <= kMax);
   }
-  explicit FontPropertyValue(int aValue)
+  explicit constexpr FontPropertyValue(int aValue)
     : mValue(aValue << kFractionBits)
   {
     MOZ_ASSERT(aValue >= Min && aValue <= Max);
   }
 
   // Construct directly from a fixed-point value of type T, with no check;
   // note that there may be special "flag" values that are outside the normal
   // min/max range (e.g. for font-style:italic, distinct from oblique angle).
-  explicit FontPropertyValue(InternalType aValue)
+  explicit constexpr FontPropertyValue(InternalType aValue)
     : mValue(aValue)
   {
   }
 
   // This is protected as it may not be the most appropriate accessor for a
   // given instance to expose. It's up to each individual property to provide
   // public accessors that forward to this as required.
   float ToFloat() const { return mValue * kInverseScale; }
@@ -151,61 +148,59 @@ protected:
  * 'normal', 'bold' aliased to 400, 700 respectively; relative keywords
  * 'lighter', 'bolder' (not currently handled here).
  *
  * We use an unsigned 10.6 fixed-point value (range 0.0 - 1023.984375)
  */
 class FontWeight final : public FontPropertyValue<uint16_t,6,1,1000>
 {
 public:
-  // See comment in FontPropertyValue regarding requirement for a trivial
-  // default constructor.
-  FontWeight() = default;
+  constexpr FontWeight() = default;
 
-  explicit FontWeight(float aValue)
+  explicit constexpr FontWeight(float aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   /**
    * CSS font weights can have fractional values, but this constructor exists
    * for convenience when writing constants such as FontWeight(700) in code.
    */
-  explicit FontWeight(int aValue)
+  explicit constexpr FontWeight(int aValue)
     : FontPropertyValue(aValue)
   {
   }
 
-  static FontWeight Normal()
+  static constexpr FontWeight Normal()
   {
     return FontWeight(kNormal);
   }
 
-  static FontWeight Thin()
+  static constexpr FontWeight Thin()
   {
     return FontWeight(kThin);
   }
 
-  static FontWeight Bold()
+  static constexpr FontWeight Bold()
   {
     return FontWeight(kBold);
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   bool IsBold() const { return mValue >= kBoldThreshold; }
 
   float ToFloat() const { return FontPropertyValue::ToFloat(); }
   int ToIntRounded() const { return FontPropertyValue::ToIntRounded(); }
 
   typedef uint16_t InternalType;
 
 private:
   friend class WeightRange;
 
-  explicit FontWeight(InternalType aValue)
+  explicit constexpr FontWeight(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   static const InternalType kNormal        = 400u << kFractionBits;
   static const InternalType kBold          = 700u << kFractionBits;
   static const InternalType kBoldThreshold = 600u << kFractionBits;
   static const InternalType kThin          = 100u << kFractionBits;
@@ -224,58 +219,56 @@ private:
  * 0.0 - 1023.984375).
  *
  * We arbitrarily limit here to 1000%. (If that becomes a problem, we
  * could reduce the number of fractional bits and increase the limit.)
  */
 class FontStretch final : public FontPropertyValue<uint16_t,6,0,1000>
 {
 public:
-  // See comment in FontPropertyValue regarding requirement for a trivial
-  // default constructor.
-  FontStretch() = default;
+  constexpr FontStretch() = default;
 
-  explicit FontStretch(float aPercent)
+  explicit constexpr FontStretch(float aPercent)
     : FontPropertyValue(aPercent)
   {
   }
 
-  static FontStretch Normal()
+  static constexpr FontStretch Normal()
   {
     return FontStretch(kNormal);
   }
-  static FontStretch UltraCondensed()
+  static constexpr FontStretch UltraCondensed()
   {
     return FontStretch(kUltraCondensed);
   }
-  static FontStretch ExtraCondensed()
+  static constexpr FontStretch ExtraCondensed()
   {
     return FontStretch(kExtraCondensed);
   }
-  static FontStretch Condensed()
+  static constexpr FontStretch Condensed()
   {
     return FontStretch(kCondensed);
   }
-  static FontStretch SemiCondensed()
+  static constexpr FontStretch SemiCondensed()
   {
     return FontStretch(kSemiCondensed);
   }
-  static FontStretch SemiExpanded()
+  static constexpr FontStretch SemiExpanded()
   {
     return FontStretch(kSemiExpanded);
   }
-  static FontStretch Expanded()
+  static constexpr FontStretch Expanded()
   {
     return FontStretch(kExpanded);
   }
-  static FontStretch ExtraExpanded()
+  static constexpr FontStretch ExtraExpanded()
   {
     return FontStretch(kExtraExpanded);
   }
-  static FontStretch UltraExpanded()
+  static constexpr FontStretch UltraExpanded()
   {
     return FontStretch(kUltraExpanded);
   }
 
   // The style system represents percentages in the 0.0..1.0 range, and
   // FontStretch does it in the 0.0..100.0 range.
   //
   // TODO(emilio): We should consider changing this class to deal with the same
@@ -288,17 +281,17 @@ public:
   bool IsNormal() const { return mValue == kNormal; }
   float Percentage() const { return ToFloat(); }
 
   typedef uint16_t InternalType;
 
 private:
   friend class StretchRange;
 
-  explicit FontStretch(InternalType aValue)
+  explicit constexpr FontStretch(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   static const InternalType kUltraCondensed =  50u << kFractionBits;
   static const InternalType kExtraCondensed = (62u << kFractionBits) + kPointFive;
   static const InternalType kCondensed      =  75u << kFractionBits;
   static const InternalType kSemiCondensed  = (87u << kFractionBits) + kPointFive;
@@ -319,54 +312,52 @@ private:
  * - Other values represent 'oblique <angle>'
  * - Note that 'oblique 0deg' is distinct from 'normal' (should it be?)
  */
 class FontSlantStyle final : public FontPropertyValue<int16_t,8,-90,90>
 {
 public:
   const static constexpr float kDefaultAngle = 14.0;
 
-  // See comment in FontPropertyValue regarding requirement for a trivial
-  // default constructor.
-  FontSlantStyle() = default;
+  constexpr FontSlantStyle() = default;
 
-  static FontSlantStyle Normal()
+  static constexpr FontSlantStyle Normal()
   {
     return FontSlantStyle(kNormal);
   }
 
-  static FontSlantStyle Italic()
+  static constexpr FontSlantStyle Italic()
   {
     return FontSlantStyle(kItalic);
   }
 
-  static FontSlantStyle Oblique(float aAngle = kDefaultAngle)
+  static constexpr FontSlantStyle Oblique(float aAngle = kDefaultAngle)
   {
     return FontSlantStyle(aAngle);
   }
 
   // Create from a string as generated by ToString. This is for internal use
   // when serializing/deserializing entries for the startupcache, and is not
   // intended to parse arbitrary (untrusted) strings.
   static FontSlantStyle FromString(const char* aString)
   {
     if (strcmp(aString, "normal") == 0) {
       return Normal();
-    } else if (strcmp(aString, "italic") == 0) {
+    }
+    if (strcmp(aString, "italic") == 0) {
       return Italic();
-    } else {
-      if (mozilla::IsAsciiDigit(aString[0]) && strstr(aString, "deg")) {
-        float angle = strtof(aString, nullptr);
-        return Oblique(angle);
-      }
-      // Not recognized as an oblique angle; maybe it's from a startup-cache
-      // created by an older version. The style field there used a simple 0/1
-      // for normal/italic respectively.
-      return aString[0] == '0' ? Normal() : Italic();
+    }
+    if (mozilla::IsAsciiDigit(aString[0]) && strstr(aString, "deg")) {
+      float angle = strtof(aString, nullptr);
+      return Oblique(angle);
     }
+    // Not recognized as an oblique angle; maybe it's from a startup-cache
+    // created by an older version. The style field there used a simple 0/1
+    // for normal/italic respectively.
+    return aString[0] == '0' ? Normal() : Italic();
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   bool IsItalic() const { return mValue == kItalic; }
   bool IsOblique() const { return mValue != kItalic && mValue != kNormal; }
 
   float ObliqueAngle() const
   {
@@ -393,22 +384,22 @@ public:
     }
   }
 
   typedef int16_t InternalType;
 
 private:
   friend class SlantStyleRange;
 
-  explicit FontSlantStyle(InternalType aConstant)
+  explicit constexpr FontSlantStyle(InternalType aConstant)
     : FontPropertyValue(aConstant)
   {
   }
 
-  explicit FontSlantStyle(float aAngle)
+  explicit constexpr FontSlantStyle(float aAngle)
     : FontPropertyValue(aAngle)
   {
   }
 
   static const InternalType kNormal = INT16_MIN;
   static const InternalType kItalic = INT16_MAX;
 };
 
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -4,21 +4,33 @@
  * 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 "../contentproc/plugin-container.cpp"
 
 #include "mozilla/Bootstrap.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
+#ifdef XP_MACOSX
+#include "mozilla/Sandbox.h"
+#endif
+
 using namespace mozilla;
 
 int
 main(int argc, char *argv[])
 {
+#ifdef XP_MACOSX
+  std::string err;
+  if (!mozilla::EarlyStartMacSandboxIfEnabled(argc, argv, err)) {
+    fprintf(stderr, "Sandbox error: %s\n", err.c_str());
+    MOZ_CRASH("Sandbox initialization failed");
+  }
+#endif
+
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
 #endif
 
   Bootstrap::UniquePtr bootstrap = GetBootstrap();
   if (!bootstrap) {
     return 2;
   }
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -544,16 +544,22 @@ AddAppDirToCommandLine(std::vector<std::
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
       // Full path to the profile dir
       nsCOMPtr<nsIFile> profileDir;
       rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
                                  NS_GET_IID(nsIFile),
                                  getter_AddRefs(profileDir));
       if (NS_SUCCEEDED(rv)) {
+        // If the profile doesn't exist, normalization will
+        // fail. But we don't return an error here because some
+        // tests require startup with a missing profile dir.
+        // For users, almost universally, the profile will be in
+        // the home directory and normalization isn't required.
+        mozilla::Unused << profileDir->Normalize();
         nsAutoCString path;
         MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
         aCmdLine.push_back("-profile");
         aCmdLine.push_back(path.get());
       }
 #endif
     }
   }
--- a/mobile/android/modules/Sanitizer.jsm
+++ b/mobile/android/modules/Sanitizer.jsm
@@ -1,34 +1,38 @@
 /* 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/. */
 
 /* globals LoadContextInfo, FormHistory, Accounts */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Integration.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Accounts: "resource://gre/modules/Accounts.jsm",
-  DownloadIntegration: "resource://gre/modules/DownloadIntegration.jsm",
   Downloads: "resource://gre/modules/Downloads.jsm",
   EventDispatcher: "resource://gre/modules/Messaging.jsm",
   FormHistory: "resource://gre/modules/FormHistory.jsm",
   OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
   Task: "resource://gre/modules/Task.jsm",
   TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetters(this, {
   quotaManagerService: ["@mozilla.org/dom/quota-manager-service;1", "nsIQuotaManagerService"],
 });
 
+/* global DownloadIntegration */
+Integration.downloads.defineModuleGetter(this, "DownloadIntegration",
+            "resource://gre/modules/DownloadIntegration.jsm");
+
 
 var EXPORTED_SYMBOLS = ["Sanitizer"];
 
 function Sanitizer() {}
 Sanitizer.prototype = {
   clearItem: function(aItemName, startTime, clearUnfinishedDownloads) {
     // Only a subset of items support deletion with startTime.
     // Those who do not will be rejected with error message.
--- a/security/sandbox/mac/Sandbox.h
+++ b/security/sandbox/mac/Sandbox.h
@@ -40,40 +40,50 @@ typedef struct _MacSandboxPluginInfo {
 
 typedef struct _MacSandboxInfo {
   _MacSandboxInfo()
     : type(MacSandboxType_Default)
     , level(0)
     , hasFilePrivileges(false)
     , hasSandboxedProfile(false)
     , hasAudio(false)
+    , hasWindowServer(false)
     , shouldLog(true)
   {
   }
   _MacSandboxInfo(const struct _MacSandboxInfo& other) = default;
 
   MacSandboxType type;
   int32_t level;
   bool hasFilePrivileges;
   bool hasSandboxedProfile;
   bool hasAudio;
+  bool hasWindowServer;
   MacSandboxPluginInfo pluginInfo;
   std::string appPath;
   std::string appBinaryPath;
   std::string appDir;
   std::string profileDir;
   std::string debugWriteDir;
 
   std::string testingReadPath1;
   std::string testingReadPath2;
   std::string testingReadPath3;
   std::string testingReadPath4;
 
+  std::string parentPort;
+  std::string crashServerPort;
+
   bool shouldLog;
 } MacSandboxInfo;
 
 namespace mozilla {
 
 bool StartMacSandbox(MacSandboxInfo const &aInfo, std::string &aErrorMessage);
+bool EarlyStartMacSandboxIfEnabled(int aArgc, char** aArgv,
+                                   std::string &aErrorMessage);
+#ifdef DEBUG
+void AssertMacSandboxEnabled();
+#endif /* DEBUG */
 
 } // namespace mozilla
 
 #endif // mozilla_Sandbox_h
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -10,16 +10,18 @@
 // linking to nsCocoaFeatures.mm in XUL.
 
 #include "Sandbox.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+#include <iostream>
+#include <sstream>
 #include <vector>
 
 #include "mozilla/Assertions.h"
 
 // XXX There are currently problems with the /usr/include/sandbox.h file on
 // some/all of the Macs in Mozilla's build system. Further,
 // sandbox_init_with_parameters is not included in the header.  For the time
 // being (until this problem is resolved), we refer directly to what we need
@@ -219,26 +221,32 @@ bool StartMacSandbox(MacSandboxInfo cons
       params.push_back("SANDBOX_LEVEL_2");
       params.push_back(aInfo.level == 2 ? "TRUE" : "FALSE");
       params.push_back("SANDBOX_LEVEL_3");
       params.push_back(aInfo.level == 3 ? "TRUE" : "FALSE");
       params.push_back("MAC_OS_MINOR");
       params.push_back(macOSMinor.c_str());
       params.push_back("APP_PATH");
       params.push_back(aInfo.appPath.c_str());
-      params.push_back("APP_BINARY_PATH");
-      params.push_back(aInfo.appBinaryPath.c_str());
-      params.push_back("APP_DIR");
-      params.push_back(aInfo.appDir.c_str());
       params.push_back("PROFILE_DIR");
       params.push_back(aInfo.profileDir.c_str());
       params.push_back("HOME_PATH");
       params.push_back(getenv("HOME"));
       params.push_back("HAS_SANDBOXED_PROFILE");
       params.push_back(aInfo.hasSandboxedProfile ? "TRUE" : "FALSE");
+      params.push_back("HAS_WINDOW_SERVER");
+      params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE");
+      if (!aInfo.parentPort.empty()) {
+        params.push_back("PARENT_PORT");
+        params.push_back(aInfo.parentPort.c_str());
+      }
+      if (!aInfo.crashServerPort.empty()) {
+        params.push_back("CRASH_PORT");
+        params.push_back(aInfo.crashServerPort.c_str());
+      }
       if (!aInfo.testingReadPath1.empty()) {
         params.push_back("TESTING_READ_PATH1");
         params.push_back(aInfo.testingReadPath1.c_str());
       }
       if (!aInfo.testingReadPath2.empty()) {
         params.push_back("TESTING_READ_PATH2");
         params.push_back(aInfo.testingReadPath2.c_str());
       }
@@ -317,9 +325,191 @@ bool StartMacSandbox(MacSandboxInfo cons
   }
   if (rv) {
     return false;
   }
 
   return true;
 }
 
+/*
+ * Fill |aInfo| with content sandbox params parsed from the provided
+ * command line arguments. Return false if any sandbox parameters needed
+ * for early startup of the sandbox are not present in the arguments.
+ */
+bool
+GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo)
+{
+  // Ensure we find these paramaters in the command
+  // line arguments. Return false if any are missing.
+  bool foundSandboxLevel = false;
+  bool foundValidSandboxLevel = false;
+  bool foundParentPort = false;
+  bool foundAppPath = false;
+
+  // Read access directories used in testing
+  int nTestingReadPaths = 0;
+  std::string testingReadPaths[MAX_TESTING_READ_PATHS] = {};
+
+  // Collect sandbox params from CLI arguments
+  for (int i = 0; i < aArgc; i++) {
+
+    if ((strcmp(aArgv[i], "-sbLevel") == 0) && (i + 1 < aArgc)) {
+      std::stringstream ss(aArgv[i+1]);
+      int level = 0;
+      ss >> level;
+      foundSandboxLevel = true;
+      aInfo.level = level;
+      foundValidSandboxLevel = level > 0 && level <= 3 ? true : false;
+      if (!foundValidSandboxLevel) {
+        break;
+      }
+      i++;
+      continue;
+    }
+
+    if (strcmp(aArgv[i], "-sbLogging") == 0) {
+      aInfo.shouldLog = true;
+      continue;
+    }
+
+    if (strcmp(aArgv[i], "-sbAllowFileAccess") == 0) {
+      aInfo.hasFilePrivileges = true;
+      continue;
+    }
+
+    if (strcmp(aArgv[i], "-sbAllowAudio") == 0) {
+      aInfo.hasAudio = true;
+      continue;
+    }
+
+    if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) {
+      aInfo.hasWindowServer = true;
+      continue;
+    }
+
+    if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) {
+      foundAppPath = true;
+      aInfo.appPath.assign(aArgv[i+1]);
+      i++;
+      continue;
+    }
+
+    if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) {
+      MOZ_ASSERT(nTestingReadPaths < MAX_TESTING_READ_PATHS);
+      testingReadPaths[nTestingReadPaths] = aArgv[i+1];
+      nTestingReadPaths++;
+      i++;
+      continue;
+    }
+
+    if ((strcmp(aArgv[i], "-profile") == 0) && (i + 1 < aArgc)) {
+      aInfo.hasSandboxedProfile = true;
+      aInfo.profileDir.assign(aArgv[i+1]);
+      i++;
+      continue;
+    }
+
+#ifdef DEBUG
+    if ((strcmp(aArgv[i], "-sbDebugWriteDir") == 0) && (i + 1 < aArgc)) {
+      aInfo.debugWriteDir.assign(aArgv[i+1]);
+      i++;
+      continue;
+    }
+#endif // DEBUG
+
+    // Handle positional arguments
+    if (strstr(aArgv[i], "org.mozilla.machname") != NULL) {
+      foundParentPort = true;
+      aInfo.parentPort.assign(aArgv[i]);
+      continue;
+    }
+
+    if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) {
+      aInfo.crashServerPort.assign(aArgv[i]);
+      continue;
+    }
+  }
+
+  if (!foundSandboxLevel) {
+    fprintf(stderr, "Content sandbox disabled due to "
+                    "missing sandbox CLI level parameter.\n");
+    return false;
+  }
+
+  if (!foundValidSandboxLevel) {
+    fprintf(stderr, "Content sandbox disabled due to invalid"
+                    "sandbox level (%d)\n", aInfo.level);
+    return false;
+  }
+
+  if (!foundParentPort) {
+    fprintf(stderr, "Content sandbox disabled due to "
+                    "missing sandbox CLI parent port parameter.\n");
+    return false;
+  }
+
+  if (!foundAppPath) {
+    fprintf(stderr, "Content sandbox disabled due to "
+                    "missing sandbox CLI app path parameter.\n");
+    return false;
+  }
+
+  aInfo.testingReadPath1 = testingReadPaths[0];
+  aInfo.testingReadPath2 = testingReadPaths[1];
+  aInfo.testingReadPath3 = testingReadPaths[2];
+  aInfo.testingReadPath4 = testingReadPaths[3];
+
+  return true;
+}
+
+/*
+ * Returns true if no errors were encountered or if early sandbox startup is
+ * not enabled for this process. Returns false if an error was encountered.
+ */
+bool
+EarlyStartMacSandboxIfEnabled(int aArgc, char** aArgv,
+                              std::string &aErrorMessage)
+{
+  bool earlyStartupEnabled = false;
+
+  // Check for the -sbStartup CLI parameter which
+  // indicates we should start the sandbox now.
+  for (int i = 0; i < aArgc; i++) {
+    if (strcmp(aArgv[i], "-sbStartup") == 0) {
+      earlyStartupEnabled = true;
+      break;
+    }
+  }
+
+  // The sandbox will be started later when/if parent
+  // sends the sandbox startup message. Return true
+  // indicating no errors occurred.
+  if (!earlyStartupEnabled) {
+    return true;
+  }
+
+  MacSandboxInfo info;
+  info.type = MacSandboxType_Content;
+  if (!GetContentSandboxParamsFromArgs(aArgc, aArgv, info)) {
+    return false;
+  }
+
+  return StartMacSandbox(info, aErrorMessage);
+}
+
+#ifdef DEBUG
+/*
+ * Ensures that a process sandbox is enabled by attempting to enable
+ * a new sandbox policy and ASSERT'ing that this fails. This depends
+ * on sandbox_init() failing when called again after a sandbox has
+ * already been successfully enabled.
+ */
+void
+AssertMacSandboxEnabled()
+{
+  char *errorbuf = NULL;
+  int rv = sandbox_init("(version 1)(deny default)", 0, &errorbuf);
+  MOZ_ASSERT(rv != 0);
+}
+#endif /* DEBUG */
+
 } // namespace mozilla
--- a/security/sandbox/mac/SandboxPolicies.h
+++ b/security/sandbox/mac/SandboxPolicies.h
@@ -1,16 +1,18 @@
 /* -*- 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 mozilla_SandboxPolicies_h
 #define mozilla_SandboxPolicies_h
 
+#define MAX_TESTING_READ_PATHS 4
+
 namespace mozilla {
 
 static const char pluginSandboxRules[] = R"SANDBOX_LITERAL(
   (version 1)
 
   (define should-log (param "SHOULD_LOG"))
   (define plugin-binary-path (param "PLUGIN_BINARY_PATH"))
   (define app-path (param "APP_PATH"))
@@ -45,26 +47,27 @@ static const char contentSandboxRules[] 
   (version 1)
 
   (define should-log (param "SHOULD_LOG"))
   (define sandbox-level-1 (param "SANDBOX_LEVEL_1"))
   (define sandbox-level-2 (param "SANDBOX_LEVEL_2"))
   (define sandbox-level-3 (param "SANDBOX_LEVEL_3"))
   (define macosMinorVersion (string->number (param "MAC_OS_MINOR")))
   (define appPath (param "APP_PATH"))
-  (define appBinaryPath (param "APP_BINARY_PATH"))
-  (define appdir-path (param "APP_DIR"))
   (define hasProfileDir (param "HAS_SANDBOXED_PROFILE"))
   (define profileDir (param "PROFILE_DIR"))
+  (define hasWindowServer (param "HAS_WINDOW_SERVER"))
   (define home-path (param "HOME_PATH"))
   (define debugWriteDir (param "DEBUG_WRITE_DIR"))
   (define testingReadPath1 (param "TESTING_READ_PATH1"))
   (define testingReadPath2 (param "TESTING_READ_PATH2"))
   (define testingReadPath3 (param "TESTING_READ_PATH3"))
   (define testingReadPath4 (param "TESTING_READ_PATH4"))
+  (define parentPort (param "PARENT_PORT"))
+  (define crashPort (param "CRASH_PORT"))
 
   (if (string=? should-log "TRUE")
     (deny default)
     (deny default (with no-log)))
   (debug deny)
   ; These are not included in (deny default)
   (deny process-info*)
   ; This isn't available in some older macOS releases.
@@ -76,22 +79,22 @@ static const char contentSandboxRules[] 
   (if (defined? 'file-map-executable)
     (deny file-map-executable))
 
   (if (defined? 'file-map-executable)
     (allow file-map-executable file-read*
       (subpath "/System")
       (subpath "/usr/lib")
       (subpath "/Library/GPUBundles")
-      (subpath appdir-path))
+      (subpath appPath))
     (allow file-read*
         (subpath "/System")
         (subpath "/usr/lib")
         (subpath "/Library/GPUBundles")
-        (subpath appdir-path)))
+        (subpath appPath)))
 
   ; Allow read access to standard system paths.
   (allow file-read*
     (require-all (file-mode #o0004)
       (require-any
         (subpath "/Library/Filesystems/NetFSPlugins")
         (subpath "/usr/share"))))
 
@@ -180,16 +183,24 @@ static const char contentSandboxRules[] 
   (define (allow-shared-list domain)
     (allow file-read*
            (home-regex (string-append "/Library/Preferences/" (regex-quote domain)))))
 
   (allow ipc-posix-shm-read-data ipc-posix-shm-write-data
     (ipc-posix-name-regex #"^CFPBS:"))
 
   (allow signal (target self))
+  (if (string? parentPort)
+    (allow mach-lookup (global-name parentPort)))
+  (if (string? crashPort)
+    (allow mach-lookup (global-name crashPort)))
+  (if (string=? hasWindowServer "TRUE")
+    (allow mach-lookup (global-name "com.apple.windowserver.active")))
+  (allow mach-lookup (global-name "com.apple.coreservices.launchservicesd"))
+  (allow mach-lookup (global-name "com.apple.lsd.mapdb"))
 
   (if (>= macosMinorVersion 13)
     (allow mach-lookup
       ; bug 1392988
       (xpc-service-name "com.apple.coremedia.videodecoder")
       (xpc-service-name "com.apple.coremedia.videoencoder")))
 
 ; bug 1312273
@@ -225,19 +236,17 @@ static const char contentSandboxRules[] 
       (literal "/")
       (literal "/private/tmp")
       (literal "/private/var/tmp")
       (home-literal "/.CFUserTextEncoding")
       (home-literal "/Library/Preferences/com.apple.DownloadAssessment.plist")
       (home-subpath "/Library/Colors")
       (home-subpath "/Library/Keyboard Layouts")
       (home-subpath "/Library/Input Methods")
-      (home-subpath "/Library/Spelling")
-      (literal appPath)
-      (literal appBinaryPath))
+      (home-subpath "/Library/Spelling"))
 
   (if (defined? 'file-map-executable)
     (begin
       (when testingReadPath1
         (allow file-read* file-map-executable (subpath testingReadPath1)))
       (when testingReadPath2
         (allow file-read* file-map-executable (subpath testingReadPath2)))
       (when testingReadPath3
--- a/taskcluster/taskgraph/actions/create_interactive.py
+++ b/taskcluster/taskgraph/actions/create_interactive.py
@@ -47,16 +47,18 @@ SCOPE_WHITELIST = [
     # this is not actually secret, and just about everything needs it
     re.compile(r'^secrets:get:project/taskcluster/gecko/hgfingerprint$'),
     # public downloads are OK
     re.compile(r'^docker-worker:relengapi-proxy:tooltool.download.public$'),
     # level-appropriate secrets are generally necessary to run a task; these
     # also are "not that secret" - most of them are built into the resulting
     # binary and could be extracted by someone with `strings`.
     re.compile(r'^secrets:get:project/releng/gecko/build/level-[0-9]/\*'),
+    # ptracing is generally useful for interactive tasks, too!
+    re.compile(r'^docker-worker:feature:allowPtrace$'),
 ]
 
 
 def context(params):
     # available for any docker-worker tasks at levels 1, 2; and for
     # test tasks on level 3 (level-3 builders are firewalled off)
     if int(params['level']) < 3:
         return [{'worker-implementation': 'docker-worker'}]
--- a/testing/mozharness/configs/builds/releng_base_android_64_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_android_64_builds.py
@@ -46,17 +46,16 @@ config = {
     ],
     'vcs_share_base': '/builds/hg-shared',
     'objdir': 'obj-firefox',
     'multi_locale': True,
     #########################################################################
 
 
     #########################################################################
-    'base_name': 'Android 2.3 %(branch)s',
     'platform': 'android',
     'stage_platform': 'android',
     'enable_max_vsize': False,
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
--- a/testing/mozharness/configs/builds/releng_base_linux_32_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_linux_32_builds.py
@@ -31,17 +31,16 @@ config = {
          'min_scm_level': 2, 'default': 'try-build-has-no-secrets'},
     ],
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 32 bit specific ######
-    'base_name': 'Linux_%(branch)s',
     'platform': 'linux',
     'stage_platform': 'linux',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_base_linux_64_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_linux_64_builds.py
@@ -30,17 +30,16 @@ config = {
          'min_scm_level': 2, 'default': 'try-build-has-no-secrets'},
     ],
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'Linux_x86-64_%(branch)s',
     'platform': 'linux64',
     'stage_platform': 'linux64',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_base_mac_64_cross_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_mac_64_cross_builds.py
@@ -20,17 +20,16 @@ config = {
     ],
     'enable_check_test': False,
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'OS X 10.7 %(branch)s',
     'platform': 'macosx64',
     'stage_platform': 'macosx64',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
         'TOOLTOOL_CACHE': '/builds/worker/tooltool-cache',
--- a/testing/mozharness/configs/builds/releng_base_windows_32_mingw_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_windows_32_mingw_builds.py
@@ -25,17 +25,16 @@ config = {
          'min_scm_level': 2, 'default': 'try-build-has-no-secrets'},
     ],
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 32 bit specific ######
-    'base_name': 'WINNT_5.2_MINGW_%(branch)s',
     'platform': 'win32-mingw32',
     'stage_platform': 'win32-mingw32',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_base_windows_64_mingw_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_windows_64_mingw_builds.py
@@ -25,17 +25,16 @@ config = {
          'min_scm_level': 2, 'default': 'try-build-has-no-secrets'},
     ],
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'WINNT_6.1_MINGW_%(branch)s',
     'platform': 'win64-mingw32',
     'stage_platform': 'win64-mingw32',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_aarch64.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_aarch64.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'Android aarch64 API 21+ %(branch)s',
     'stage_platform': 'android-aarch64',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-aarch64/nightly',
     'multi_locale_config_platform': 'android',
     'artifact_flag_build_variant_in_try': 'aarch64-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'Android armv7 api-16+ %(branch)s',
     'stage_platform': 'android-api-16',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/nightly',
     'multi_locale_config_platform': 'android',
     'artifact_flag_build_variant_in_try': 'api-16-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_artifact.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'Android armv7 api-16+ %(branch)s Artifact build',
     'stage_platform': 'android-api-16',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/nightly-artifact',
     'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
     'multi_locale_config_platform': 'android',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug.py
@@ -1,8 +1,7 @@
 config = {
-    'base_name': 'Android armv7 api-16+ %(branch)s debug',
     'stage_platform': 'android-api-16-debug',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/debug',
     'multi_locale_config_platform': 'android',
     'debug_build': True,
     'artifact_flag_build_variant_in_try': 'api-16-debug-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug_artifact.py
@@ -1,8 +1,7 @@
 config = {
-    'base_name': 'Android armv7 api-16+ %(branch)s debug Artifact build',
     'stage_platform': 'android-api-16-debug',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/debug-artifact',
     'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
     'multi_locale_config_platform': 'android',
     'debug_build': True,
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug_ccov.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug_ccov.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android armv7 api-16+ %(branch)s debug coverage',
     'stage_platform': 'android-api-16-debug-ccov',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/debug-ccov',
     'multi_locale_config_platform': 'android',
     'debug_build': True,
     'postflight_build_mach_commands': [
         ['android',
          'archive-geckoview',
         ],
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_gradle_dependencies.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_gradle_dependencies.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android armv7 api-16+ Gradle dependencies %(branch)s',
     'stage_platform': 'android-api-16-gradle-dependencies',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-gradle-dependencies/nightly',
     'multi_locale_config_platform': 'android',
      # gradle-dependencies doesn't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'gradle-dependencies',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_partner_sample1.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_partner_sample1.py
@@ -1,8 +1,7 @@
 config = {
-    'base_name': 'Android armv7 api-16+ partner Sample1 %(branch)s',
     'stage_platform': 'android-api-16-partner-sample1',
     'src_mozconfig': None,  # use manifest to determine mozconfig src
     'src_mozconfig_manifest': 'partner/mozconfigs/mozconfig1.json',
     'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
     'multi_locale_config_platform': 'android',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_without_google_play_services.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_without_google_play_services.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'Android armv7 api-16+ %(branch)s --without-google-play-services',
     'stage_platform': 'android-api-16',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/nightly-without-google-play-services',
     'multi_locale_config_platform': 'android',
     'artifact_flag_build_variant_in_try': None, # There's no artifact equivalent.
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_checkstyle.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_checkstyle.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android checkstyle %(branch)s',
     'stage_platform': 'android-checkstyle',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
     'multi_locale_config_platform': 'android',
     # checkstyle doesn't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'checkstyle',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_findbugs.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_findbugs.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android findbugs %(branch)s',
     'stage_platform': 'android-findbugs',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
     'multi_locale_config_platform': 'android',
     # findbugs doesn't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'findbugs',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_geckoview_docs.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_geckoview_docs.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android GeckoView docs %(branch)s',
     'stage_platform': 'android-geckoview-docs',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
     'multi_locale_config_platform': 'android',
     # geckoview-docs doesn't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'geckoview-docs',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_lint.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_lint.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android lint %(branch)s',
     'stage_platform': 'android-lint',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
     'multi_locale_config_platform': 'android',
     # lint doesn't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'lint',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_test.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_test.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android armv7 unit tests %(branch)s',
     'stage_platform': 'android-test',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
     'multi_locale_config_platform': 'android',
     # unit tests don't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'test',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_test_ccov.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_test_ccov.py
@@ -1,10 +1,9 @@
 config = {
-    'base_name': 'Android armv7 unit test code coverage %(branch)s',
     'stage_platform': 'android-test-ccov',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
     'multi_locale_config_platform': 'android',
     # unit tests don't produce a package. So don't collect package metrics.
     'disable_package_metrics': True,
     'postflight_build_mach_commands': [
         ['android',
          'test-ccov',
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86.py
@@ -1,6 +1,5 @@
 config = {
-    'base_name': 'Android 4.2 x86 %(branch)s build',
     'stage_platform': 'android-x86',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-x86/nightly',
     'artifact_flag_build_variant_in_try': 'x86-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_64.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_64.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'Android x86-64 API 21+ %(branch)s',
     'stage_platform': 'android-x86_64',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-x86_64/nightly',
     'multi_locale_config_platform': 'android',
     'artifact_flag_build_variant_in_try': 'x86_64-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_64_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_64_artifact.py
@@ -1,6 +1,5 @@
 config = {
-    'base_name': 'Android 5.0 x86-64 %(branch)s Artifact build',
     'stage_platform': 'android-x86_64',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-x86_64/nightly-artifact',
     'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android-x86/releng.manifest',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_artifact.py
@@ -1,6 +1,5 @@
 config = {
-    'base_name': 'Android 4.2 x86 %(branch)s Artifact build',
     'stage_platform': 'android-x86',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-x86/nightly-artifact',
     'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android-x86/releng.manifest',
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_fuzzing_debug.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_x86_fuzzing_debug.py
@@ -1,6 +1,5 @@
 config = {
-    'base_name': 'Android 4.2 x86 %(branch)s debug fuzzing build',
     'stage_platform': 'android-x86-fuzzing-debug',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-x86/debug-fuzzing',
     'debug_build': True,
 }
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_artifact.py
@@ -16,17 +16,16 @@ config = {
     # decides whether we want to use moz_sign_cmd in env
     'vcs_share_base': '/builds/hg-shared',
     # allows triggering of dependent jobs when --artifact try syntax is detected
     #########################################################################
 
 
     #########################################################################
     ###### 32 bit specific ######
-    'base_name': 'Linux_%(branch)s_Artifact_build',
     'platform': 'linux',
     'stage_platform': 'linux',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug_artifact.py
@@ -18,17 +18,16 @@ config = {
     # debug specific
     'debug_build': True,
     # allows triggering of test jobs when --artifact try syntax is detected
     #########################################################################
 
 
     #########################################################################
     ###### 32 bit specific ######
-    'base_name': 'Linux_%(branch)s_Artifact_build',
     'platform': 'linux',
     'stage_platform': 'linux-debug',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_devedition.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_devedition.py
@@ -1,5 +1,4 @@
 config = {
     'mozconfig_variant': 'devedition',
-    'base_name': 'Linux_%(branch)_devedition',
     'stage_platform': 'linux-devedition',
 }
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_artifact.py
@@ -17,17 +17,16 @@ config = {
     ],
     'vcs_share_base': '/builds/hg-shared',
     # allows triggering of dependent jobs when --artifact try syntax is detected
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'Linux_x86-64_%(branch)s_Artifact_build',
     'platform': 'linux64',
     'stage_platform': 'linux64',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug_artifact.py
@@ -11,17 +11,16 @@ config = {
     'debug_build': True,
     # decides whether we want to use moz_sign_cmd in env
     # allows triggering of test jobs when --artifact try syntax is detected
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'Linux_x86-64_%(branch)s_Artifact_build',
     'platform': 'linux64',
     'stage_platform': 'linux64-debug',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_devedition.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_devedition.py
@@ -1,5 +1,4 @@
 config = {
     'mozconfig_variant': 'devedition',
-    'base_name': 'Linux_x86-64_%(branch)_devedition',
     'stage_platform': 'linux64-devedition',
 }
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_searchfox_and_debug.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_searchfox_and_debug.py
@@ -9,17 +9,16 @@ config = {
     'app_ini_path': '%(obj_dir)s/dist/bin/application.ini',
     # decides whether we want to use moz_sign_cmd in env
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'Linux_x86-64_%(branch)s_Searchfox',
     'platform': 'linux64',
     'stage_platform': 'linux64-searchfox-opt',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py
+++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py
@@ -9,17 +9,16 @@ config = {
     'app_ini_path': '%(obj_dir)s/dist/bin/application.ini',
     # decides whether we want to use moz_sign_cmd in env
     'vcs_share_base': '/builds/hg-shared',
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'Linux_x86-64_%(branch)s_Static_Analysis',
     'platform': 'linux64',
     'stage_platform': 'linux64-st-an-opt',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'DISPLAY': ':2',
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
--- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_artifact.py
@@ -11,17 +11,16 @@ config = {
     # decides whether we want to use moz_sign_cmd in env
     'vcs_share_base': '/builds/hg-shared',
     # allows triggering of dependent jobs when --artifact try syntax is detected
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'OS X 10.7 %(branch)s_Artifact_build',
     'platform': 'macosx64',
     'stage_platform': 'macosx64',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'CHOWN_ROOT': '~/bin/chown_root',
         'CHOWN_REVERT': '~/bin/chown_revert',
--- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug_artifact.py
@@ -13,17 +13,16 @@ config = {
     # debug specific
     'debug_build': True,
     # allows triggering of test jobs when --artifact try syntax is detected
     #########################################################################
 
 
     #########################################################################
     ###### 64 bit specific ######
-    'base_name': 'OS X 10.7 %(branch)s_Artifact_build',
     'platform': 'macosx64',
     'stage_platform': 'macosx64-debug',
     'env': {
         'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
         'HG_SHARE_BASE_DIR': '/builds/hg-shared',
         'MOZ_OBJDIR': '%(abs_obj_dir)s',
         'TINDERBOX_OUTPUT': '1',
         'TOOLTOOL_CACHE': '/builds/tooltool_cache',
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_artifact.py
@@ -1,4 +1,3 @@
 config = {
-    'base_name': 'WINNT_5.2_%(branch)s_Artifact_build',
     'mozconfig_variant': 'artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug_artifact.py
@@ -1,4 +1,3 @@
 config = {
-    'base_name': 'WINNT_5.2_%(branch)s_Artifact_build',
     'mozconfig_variant': 'debug-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_mingwclang.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_mingwclang.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'WINNT_5.2_MINGWCLANG_%(branch)s',
     'platform': 'win32-mingwclang',
     'stage_platform': 'win32-mingwclang',
     'mozconfig_platform': 'win32',
     'mozconfig_variant': 'mingwclang',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_artifact.py
@@ -1,4 +1,3 @@
 config = {
-    'base_name': 'WINNT_6.1_x86-64_%(branch)s_Artifact_build',
     'mozconfig_variant': 'artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug_artifact.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug_artifact.py
@@ -1,4 +1,3 @@
 config = {
-    'base_name': 'WINNT_6.1_x86-64_%(branch)s_Artifact_build',
     'mozconfig_variant': 'debug-artifact',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_mingwclang.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_mingwclang.py
@@ -1,7 +1,6 @@
 config = {
-    'base_name': 'WINNT_6.1_MINGWCLANG_%(branch)s',
     'platform': 'win64-mingwclang',
     'stage_platform': 'win64-mingwclang',
     'mozconfig_platform': 'win64',
     'mozconfig_variant': 'mingwclang',
 }
--- a/testing/mozharness/configs/builds/taskcluster_base_win32.py
+++ b/testing/mozharness/configs/builds/taskcluster_base_win32.py
@@ -1,12 +1,11 @@
 import os
 
 config = {
-    'base_name': 'WINNT_5.2_%(branch)s',
     'platform': 'win32',
     'env': {
         'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe',
     },
     "check_test_env": {
         'MINIDUMP_STACKWALK': '%(abs_src_dir)s\\win32-minidump_stackwalk.exe',
         'MINIDUMP_SAVE_PATH': os.path.join(os.getcwd(), 'public', 'build'),
     },
--- a/testing/mozharness/configs/builds/taskcluster_base_win64.py
+++ b/testing/mozharness/configs/builds/taskcluster_base_win64.py
@@ -1,12 +1,11 @@
 import os
 
 config = {
-    'base_name': 'WINNT_6.1_x86-64_%(branch)s',
     'platform': 'win64',
     'env': {
         'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe',
     },
     "check_test_env": {
         'MINIDUMP_STACKWALK': '%(abs_src_dir)s\\win32-minidump_stackwalk.exe',
         'MINIDUMP_SAVE_PATH': os.path.join(os.getcwd(), 'public', 'build'),
     },
--- a/testing/mozharness/configs/builds/taskcluster_sub_win32/addondevel.py
+++ b/testing/mozharness/configs/builds/taskcluster_sub_win32/addondevel.py
@@ -1,6 +1,4 @@
 config = {
-    # decides whether we want to use moz_sign_cmd in en+
-    'base_name': 'WINNT 5.2 add-on-devel %(branch)s',
     'stage_platform': 'win32-add-on-devel',
     'mozconfig_variant': 'add-on-devel',
 }
--- a/testing/mozharness/configs/builds/taskcluster_sub_win64/addondevel.py
+++ b/testing/mozharness/configs/builds/taskcluster_sub_win64/addondevel.py
@@ -1,5 +1,4 @@
 config = {
-    'base_name': 'WINNT 6.1 x86-64 add-on-devel %(branch)s',
     'stage_platform': 'win64-add-on-devel',
     'mozconfig_variant': 'add-on-devel',
 }
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -2183,16 +2183,33 @@ memoryreporter:
     expires: "66"
     kind: uint
     notification_emails:
       - memshrink-telemetry-alerts@mozilla.com
     release_channel_collection: opt-out
     record_in_processes:
       - 'content'
 
+resistfingerprinting:
+  content_window_size:
+    bug_numbers:
+      - 1489493
+    description: >
+      The size (in pixels) of the content windows for innerWidth and innerHeight.
+    expires: "66"
+    kind: uint
+    keyed: true
+    notification_emails:
+      - tihuang@mozilla.com
+      - tom@mozilla.com
+      - ettseng@mozilla.com
+    release_channel_collection: opt-out
+    record_in_processes:
+      - 'main'
+
 # The following section is for probes testing the Telemetry system. They will not be
 # submitted in pings and are only used for testing.
 telemetry.test:
   unsigned_int_kind:
     bug_numbers:
       - 1276190
     description: >
       This is a test uint type with a really long description, maybe spanning even multiple
--- a/toolkit/components/url-classifier/tests/mochitest/chrome.ini
+++ b/toolkit/components/url-classifier/tests/mochitest/chrome.ini
@@ -10,16 +10,17 @@ support-files =
   gethash.sjs
   classifierCommon.js
   classifierHelper.js
   head.js
   threathit.sjs
   fastblock.html
   redirect_tracker.sjs
   fastblock_iframe.html
+  fastblock_slow_iframe.html
   !/toolkit/components/url-classifier/tests/mochitest/classifierFrame.html
   !/toolkit/components/url-classifier/tests/mochitest/cleanWorker.js
   !/toolkit/components/url-classifier/tests/mochitest/good.js
   !/toolkit/components/url-classifier/tests/mochitest/evil.css
   !/toolkit/components/url-classifier/tests/mochitest/evil.css^headers^
   !/toolkit/components/url-classifier/tests/mochitest/evil.js
   !/toolkit/components/url-classifier/tests/mochitest/evil.js^headers^
   !/toolkit/components/url-classifier/tests/mochitest/evilWorker.js
@@ -64,9 +65,8 @@ skip-if = verify
 [test_classifier_changetablepref_bug1395411.html]
 [test_reporturl.html]
 skip-if = verify
 [test_trackingprotection_bug1312515.html]
 [test_advisory_link.html]
 [test_threathit_report.html]
 skip-if = verify
 [test_fastblock_bug1477046.html]
-skip-if = (os == 'win' && os_version == "6.1") || (os == 'mac') # Bug 1495110
--- a/toolkit/components/url-classifier/tests/mochitest/fastblock.html
+++ b/toolkit/components/url-classifier/tests/mochitest/fastblock.html
@@ -3,17 +3,17 @@
 <head>
   <title></title>
 </head>
 <body>
   <!-- Tracking iframe contains some trackers -->
   <iframe id="fastIFrame" data-touched="not sure" src="http://tracking.example.org/chrome/toolkit/components/url-classifier/tests/mochitest/fastblock_iframe.html" onload="this.dataset.touched='yes';" onerror="this.dataset.touched='no';"></iframe>
 
   <!-- A slow tracking iframe containing some trackers -->
-  <iframe id="slowIFrame" data-touched="not sure" src="http://tracking.example.org/chrome/toolkit/components/url-classifier/tests/mochitest/fastblock_iframe.html?slow" onload="this.dataset.touched='yes';"></iframe>
+  <iframe id="slowIFrame" data-touched="not sure" src="http://tracking.example.org/chrome/toolkit/components/url-classifier/tests/mochitest/fastblock_slow_iframe.html" onload="this.dataset.touched='yes';"></iframe>
 
   <!-- A fast tracker that redirects to become a slow tracker -->
   <script id="redirectScript"src="http://example.com/chrome/toolkit/components/url-classifier/tests/mochitest/redirect_tracker.sjs" onload="this.dataset.touched='yes';" onerror="this.dataset.touched='no';"></script>
 
   <!-- Tracking URL -->
   <script id="goodScript" data-touched="not sure" src="http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/good.js" onload="this.dataset.touched='yes';" onerror="this.dataset.touched='no';"></script>
 
   <!-- Tracking Annotation -->
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/mochitest/fastblock_slow_iframe.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+
+  <!-- Tracking URL -->
+  <script id="goodSlowIFrameScript" data-touched="not sure" src="http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/good.js?slowiframe" onload="this.dataset.touched='yes';" onerror="this.dataset.touched='no';"></script>
+
+  <!-- Tracking Annotation -->
+  <script id="fastSlowIFrameScript" data-touched="not sure" src="http://itisatracker.org/tests/toolkit/components/url-classifier/tests/mochitest/evil.js?slowiframe" onload="this.dataset.touched='yes';" onerror="this.dataset.touched='no';"></script>
+
+  <!-- Tracking Annotation -->
+  <script id="slowSlowIFrameScript" data-touched="not sure" src="http://itisatracker.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js?slowiframe" onload="this.dataset.touched='yes';" onerror="this.dataset.touched='no';"></script>
+
+</body>
+</html>
--- a/toolkit/components/url-classifier/tests/mochitest/test_fastblock_bug1477046.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_fastblock_bug1477046.html
@@ -1,49 +1,49 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=1477046
 
-------------------------------------------
-| ID               | Tracker | FastBlock |
--------------------+---------+------------
-| fastblock.html   | No      | N/A       |
--------------------+---------+------------
-| goodScript       | No      | N/A       |
-| fastScript       | Yes     | No        |
-| slowScript       | Yes     | Yes       |
-| redirectScript   | Yes     | Yes       |
--------------------+---------+------------
-| fastIFrame       | Yes     | No        |
--------------------+---------+------------
-| goodIFrameScript | No      | N/A       |
-| fastIFrameScript | Yes     | No        |
-| slowIFrameScript | Yes     | Yes       |
--------------------+---------+------------
-| slowIFrame       | Yes     | Yes       |
--------------------+---------+------------
-| goodIFrameScript | No      | N/A       |
-| fastIFrameScript | Yes     | N/A       |
-| slowIFrameScript | Yes     | N/A       |
--------------------+---------+------------
-|          (load event fires)            |
--------------------+---------+------------
-| badIFrame        | Yes     | No        |
--------------------+---------+------------
-| goodIFrameScript | No      | N/A       |
-| fastIFrameScript | Yes     | No        |
-| slowIFrameScript | Yes     | No        |
--------------------+---------+------------
-| goodIFrame       | No      | N/A       |
--------------------+---------+------------
-| goodIFrameScript | No      | N/A       |
-| fastIFrameScript | Yes     | No        |
-| slowIFrameScript | Yes     | No        |
-------------------------------------------
+----------------------------------------------
+| ID                   | Tracker | FastBlock |
+-----------------------+---------+------------
+| fastblock.html       | No      | N/A       |
+-----------------------+---------+------------
+| goodScript           | No      | N/A       |
+| fastScript           | Yes     | No        |
+| slowScript           | Yes     | Yes       |
+| redirectScript       | Yes     | Yes       |
+-----------------------+---------+------------
+| fastIFrame           | Yes     | No        |
+-----------------------+---------+------------
+| goodIFrameScript     | No      | N/A       |
+| fastIFrameScript     | Yes     | No        |
+| slowIFrameScript     | Yes     | Yes       |
+-----------------------+---------+------------
+| slowIFrame           | Yes     | Yes       |
+-----------------------+---------+------------
+| goodSlowIFrameScript | No      | N/A       |
+| fastSlowIFrameScript | Yes     | N/A       |
+| slowSlowIFrameScript | Yes     | N/A       |
+-----------------------+---------+------------
+|            (load event fires)              |
+-----------------------+---------+------------
+| badIFrame            | Yes     | No        |
+-----------------------+---------+------------
+| goodIFrameScript     | No      | N/A       |
+| fastIFrameScript     | Yes     | No        |
+| slowIFrameScript     | Yes     | No        |
+-----------------------+---------+------------
+| goodIFrame           | No      | N/A       |
+-----------------------+---------+------------
+| goodIFrameScript     | No      | N/A       |
+| fastIFrameScript     | Yes     | No        |
+| slowIFrameScript     | Yes     | No        |
+----------------------------------------------
 
 -->
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 1477046</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
 </head>
@@ -76,19 +76,21 @@ const gValidHosts = [
   "itisatracker.org",
   "trackertest.org",
   "tracking.example.com",
   "tracking.example.org",
 ];
 const gSlowTrackers = [
   "http://tracking.example.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js",
   "http://itisatracker.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js",
+  "http://tracking.example.org/chrome/toolkit/components/url-classifier/tests/mochitest/fastblock_slow_iframe.html",
   "http://tracking.example.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js?iframe",
   "http://itisatracker.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js?iframe",
-  "http://tracking.example.org/chrome/toolkit/components/url-classifier/tests/mochitest/fastblock_iframe.html?slow",
+  "http://tracking.example.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js?slowiframe",
+  "http://itisatracker.org/tests/toolkit/components/url-classifier/tests/mochitest/trackingRequest.js?slowiframe",
 ];
 const gRedirectTracker =
   "http://example.com/chrome/toolkit/components/url-classifier/tests/mochitest/redirect_tracker.sjs";
 
 const gInfiniteTimeout = 300000;
 const gDebug = false;
 
 function log(aMsg) {
@@ -371,20 +373,20 @@ async function testFastBlock(aWindow) {
   let browser = aWindow.gBrowser.selectedBrowser;
   let results = await ContentTask.spawn(browser, {}, () => {
     let iframe = content.document.getElementById("fastIFrame").contentDocument;
     return {
       goodScript: content.document.getElementById("goodScript").dataset.touched,
       fastScript: content.document.getElementById("fastScript").dataset.touched,
       slowScript: content.document.getElementById("slowScript").dataset.touched,
       fastIFrame: content.document.getElementById("fastIFrame").dataset.touched,
-      slowIFrame: content.document.getElementById("slowIFrame").dataset.touched,
       goodIFrameScript: iframe.getElementById("goodIFrameScript").dataset.touched,
       fastIFrameScript: iframe.getElementById("fastIFrameScript").dataset.touched,
       slowIFrameScript: iframe.getElementById("slowIFrameScript").dataset.touched,
+      slowIFrame: content.document.getElementById("slowIFrame").dataset.touched,
       redirectScript: content.document.getElementById("redirectScript").dataset.touched,
       numTrackersFound: content.document.numTrackersFound,
       numTrackersBlocked: content.document.numTrackersBlocked,
     };
   });
 
   let { goodScript,
         fastScript,
@@ -457,52 +459,62 @@ async function testFastBlock(aWindow) {
   is(results.numTrackersFound, 12, "12 trackers found");
   is(results.numTrackersBlocked, 4, "4 tracker blocked");
 }
 
 async function testNoFastBlock(aWindow) {
   log("testNoFastBlock");
   let browser = aWindow.gBrowser.selectedBrowser;
   let results = await ContentTask.spawn(browser, {}, () => {
-    let iframe = content.document.getElementById("fastIFrame").contentDocument;
+    let fastIframe = content.document.getElementById("fastIFrame").contentDocument;
+    let slowIframe = content.document.getElementById("slowIFrame").contentDocument;
     return {
       goodScript: content.document.getElementById("goodScript").dataset.touched,
       fastScript: content.document.getElementById("fastScript").dataset.touched,
       slowScript: content.document.getElementById("slowScript").dataset.touched,
       fastIFrame: content.document.getElementById("fastIFrame").dataset.touched,
+      goodIFrameScript: fastIframe.getElementById("goodIFrameScript").dataset.touched,
+      fastIFrameScript: fastIframe.getElementById("fastIFrameScript").dataset.touched,
+      slowIFrameScript: fastIframe.getElementById("slowIFrameScript").dataset.touched,
       slowIFrame: content.document.getElementById("slowIFrame").dataset.touched,
-      goodIFrameScript: iframe.getElementById("goodIFrameScript").dataset.touched,
-      fastIFrameScript: iframe.getElementById("fastIFrameScript").dataset.touched,
-      slowIFrameScript: iframe.getElementById("slowIFrameScript").dataset.touched,
+      goodSlowIFrameScript: slowIframe.getElementById("goodSlowIFrameScript").dataset.touched,
+      fastSlowIFrameScript: slowIframe.getElementById("fastSlowIFrameScript").dataset.touched,
+      slowSlowIFrameScript: slowIframe.getElementById("slowSlowIFrameScript").dataset.touched,
       numTrackersFound: content.document.numTrackersFound,
       numTrackersBlocked: content.document.numTrackersBlocked,
     };
   });
 
   let { goodScript,
         fastScript,
         slowScript,
         fastIFrame,
-        slowIFrame,
         goodIFrameScript,
         fastIFrameScript,
         slowIFrameScript,
+        slowIFrame,
+        goodSlowIFrameScript,
+        fastSlowIFrameScript,
+        slowSlowIFrameScript,
         numTrackersFound,
         numTrackersBlocked,
   } = results;
 
   is(goodScript, "yes", "is not a tracker");
   is(fastScript, "yes", "FastBlock is disabled");
   is(slowScript, "yes", "FastBlock is disabled");
   is(fastIFrame, "yes", "fast iframe loaded");
-  is(slowIFrame, "yes", "FastBlock is disabled");
   is(goodIFrameScript, "yes", "is not a tracker");
   is(fastIFrameScript, "yes", "FastBlock is disabled");
   is(slowIFrameScript, "yes", "FastBlock is disabled");
-  is(numTrackersFound, 7, "7 trackers found");
+  is(slowIFrame, "yes", "FastBlock is disabled");
+  is(goodSlowIFrameScript, "yes", "is not a tracker");
+  is(fastSlowIFrameScript, "yes", "FastBlock is disabled");
+  is(slowSlowIFrameScript, "yes", "FastBlock is disabled");
+  is(numTrackersFound, 9, "9 trackers found");
   is(numTrackersBlocked, 0, "no tracker blocked");
 
   let iframeLoaded = await addIFrame(aWindow, gBadIFramePage, "badIFrame");
   ok(iframeLoaded, "tracking iframe is loaded");
 
   results = await ContentTask.spawn(browser, log, (LOG) => {
     let iframe = content.document.getElementById("badIFrame").contentDocument;
     return {
@@ -515,17 +527,17 @@ async function testNoFastBlock(aWindow) 
     };
   });
 
   is(results.badIFrame, "yes", "FastBlock is disabled");
   is(results.goodIFrameScript, "yes", "is not a tracker");
   is(results.fastIFrameScript, "yes", "FastBlock is disabled");
   is(results.slowIFrameScript, "yes", "FastBlock is disabled");
 
-  is(results.numTrackersFound, 10, "10 trackers found");
+  is(results.numTrackersFound, 12, "12 trackers found");
   is(results.numTrackersBlocked, 0, "0 tracker blocked");
 
   let goodIFrameLoaded = await addIFrame(aWindow, gGoodIFramePage, "goodIFrame");
   ok(goodIFrameLoaded, "non tracking iframe is loaded");
 
   results = await ContentTask.spawn(browser, {}, () => {
     let iframe = content.document.getElementById("goodIFrame").contentDocument;
     return {
@@ -538,17 +550,17 @@ async function testNoFastBlock(aWindow) 
     };
   });
 
   is(results.goodIFrame, "yes", "non tracking iframe is loaded");
   is(results.goodIFrameScript, "yes", "is not a tracker");
   is(results.fastIFrameScript, "yes", "FastBlock is disabled");
   is(results.slowIFrameScript, "yes", "FastBlock is disabled");
 
-  is(results.numTrackersFound, 12, "12 trackers found");
+  is(results.numTrackersFound, 14, "14 trackers found");
   is(results.numTrackersBlocked, 0, "0 tracker blocked");
 }
 
 async function testPrefsSwitch() {
   // FastBlock ON
   await runTest({
     "set": [
       ["browser.contentblocking.enabled", true],
--- a/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp
+++ b/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp
@@ -17,16 +17,17 @@
 #include "google_breakpad/processor/code_modules.h"
 #include "google_breakpad/processor/minidump.h"
 #include "google_breakpad/processor/minidump_processor.h"
 #include "google_breakpad/processor/process_state.h"
 #include "google_breakpad/processor/stack_frame.h"
 #include "processor/pathname_stripper.h"
 
 #include "mozilla/FStream.h"
+#include "mozilla/Unused.h"
 
 #if defined(XP_WIN32)
 
 #include <windows.h>
 #include "mozilla/glue/WindowsDllServices.h"
 
 #elif defined(XP_UNIX) || defined(XP_MACOSX)
 
@@ -66,16 +67,17 @@ using google_breakpad::CodeModules;
 using google_breakpad::Minidump;
 using google_breakpad::MinidumpProcessor;
 using google_breakpad::PathnameStripper;
 using google_breakpad::ProcessResult;
 using google_breakpad::ProcessState;
 using google_breakpad::StackFrame;
 
 using mozilla::OFStream;
+using mozilla::Unused;
 
 MinidumpAnalyzerOptions gMinidumpAnalyzerOptions;
 
 // Path of the minidump to be analyzed.
 static string gMinidumpPath;
 
 struct ModuleCompare {
   bool operator() (const CodeModule* aLhs, const CodeModule* aRhs) const {
@@ -470,16 +472,27 @@ struct CharTraits<wchar_t>
   {
     left = WideToUTF8(right);
     return left;
   }
 };
 
 #endif // defined(XP_WIN)
 
+static void
+LowerPriority()
+{
+#if defined(XP_WIN)
+  Unused << SetPriorityClass(GetCurrentProcess(),
+                             PROCESS_MODE_BACKGROUND_BEGIN);
+#else // Linux, MacOS X, etc...
+  Unused << nice(20);
+#endif
+}
+
 template <typename CharT, typename Traits = CharTraits<CharT>>
 static void
 ParseArguments(int argc, CharT** argv) {
   if (argc <= 1) {
     exit(EXIT_FAILURE);
   }
 
   for (int i = 1; i < argc - 1; i++) {
@@ -502,16 +515,17 @@ ParseArguments(int argc, CharT** argv) {
 // Using wmain here so that the CRT doesn't need to perform a wasteful and
 // lossy UTF-16 to MBCS conversion; ParseArguments will convert to UTF8 directly.
 extern "C"
 int wmain(int argc, wchar_t** argv)
 #else
 int main(int argc, char** argv)
 #endif
 {
+  LowerPriority();
   ParseArguments(argc, argv);
 
   if (!GenerateStacks(gMinidumpPath, gMinidumpAnalyzerOptions.fullMinidump)) {
     exit(EXIT_FAILURE);
   }
 
   exit(EXIT_SUCCESS);
 }
--- a/toolkit/crashreporter/minidump-analyzer/moz.build
+++ b/toolkit/crashreporter/minidump-analyzer/moz.build
@@ -1,20 +1,16 @@
 # -*- 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/.
 
 if CONFIG['OS_TARGET'] != 'Android':
-    if CONFIG['OS_TARGET'] == 'WINNT':
-        # We need mozglue on Windows for access to DLL services
-        GeckoProgram(name='minidump-analyzer', linkage=None)
-    else:
-        Program('minidump-analyzer')
+    GeckoProgram(name='minidump-analyzer', linkage=None)
 
     if CONFIG['OS_TARGET'] == 'Darwin':
         DIST_SUBDIR = 'crashreporter.app/Contents/MacOS'
 
     if CONFIG['OS_TARGET'] == 'WINNT':
         DEFINES['UNICODE'] = True
         DEFINES['_UNICODE'] = True
 
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -711,17 +711,24 @@ Preamble_gettimeofday(CallArguments* aAr
     return PreambleResult::PassThrough;
   }
   return PreambleResult::Redirect;
 }
 
 static PreambleResult
 Preamble_fcntl(CallArguments* aArguments)
 {
-  // Make sure fcntl is only used with a limited set of commands.
+  // We don't record any outputs for fcntl other than its return value, but
+  // some commands have an output parameter they write additional data to.
+  // Handle this by only allowing a limited set of commands to be used when
+  // events are not passed through and we are recording/replaying the outputs.
+  if (AreThreadEventsPassedThrough()) {
+    return PreambleResult::Redirect;
+  }
+
   auto& cmd = aArguments->Arg<1, size_t>();
   switch (cmd) {
   case F_GETFL:
   case F_SETFL:
   case F_GETFD:
   case F_SETFD:
   case F_NOCACHE:
   case F_SETLK:
--- a/xpcom/base/nsMacUtilsImpl.cpp
+++ b/xpcom/base/nsMacUtilsImpl.cpp
@@ -1,16 +1,23 @@
 /* -*- 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 "nsMacUtilsImpl.h"
 
+#include "base/command_line.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsIProperties.h"
+#include "nsServiceManagerUtils.h"
+
 #include <CoreFoundation/CoreFoundation.h>
 
 NS_IMPL_ISUPPORTS(nsMacUtilsImpl, nsIMacUtils)
 
 nsresult
 nsMacUtilsImpl::GetArchString(nsAString& aArchString)
 {
   if (!mBinaryArchs.IsEmpty()) {
@@ -120,8 +127,69 @@ nsMacUtilsImpl::GetIsTranslated(bool* aI
 #else
   // Translation only exists for ppc code.  Other architectures aren't
   // translated.
   *aIsTranslated = false;
 #endif
 
   return NS_OK;
 }
+
+#if defined(MOZ_CONTENT_SANDBOX)
+bool
+nsMacUtilsImpl::GetAppPath(nsCString &aAppPath)
+{
+  nsAutoCString appPath;
+  nsAutoCString appBinaryPath(
+    (CommandLine::ForCurrentProcess()->argv()[0]).c_str());
+
+  nsAutoCString::const_iterator start, end;
+  appBinaryPath.BeginReading(start);
+  appBinaryPath.EndReading(end);
+  if (RFindInReadable(NS_LITERAL_CSTRING(".app/Contents/MacOS/"), start, end)) {
+    end = start;
+    ++end; ++end; ++end; ++end;
+    appBinaryPath.BeginReading(start);
+    appPath.Assign(Substring(start, end));
+  } else {
+    return false;
+  }
+
+  nsCOMPtr<nsIFile> app;
+  nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appPath),
+                                true, getter_AddRefs(app));
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+
+  rv = app->Normalize();
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  app->GetNativePath(aAppPath);
+
+  return true;
+}
+
+#if defined(DEBUG)
+// Given a path to a file, return the directory which contains it.
+nsAutoCString
+nsMacUtilsImpl::GetDirectoryPath(const char *aPath)
+{
+  nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+  if (!file ||
+      NS_FAILED(file->InitWithNativePath(nsDependentCString(aPath)))) {
+    MOZ_CRASH("Failed to create or init an nsIFile");
+  }
+  nsCOMPtr<nsIFile> directoryFile;
+  if (NS_FAILED(file->GetParent(getter_AddRefs(directoryFile))) ||
+      !directoryFile) {
+    MOZ_CRASH("Failed to get parent for an nsIFile");
+  }
+  directoryFile->Normalize();
+  nsAutoCString directoryPath;
+  if (NS_FAILED(directoryFile->GetNativePath(directoryPath))) {
+    MOZ_CRASH("Failed to get path for an nsIFile");
+  }
+  return directoryPath;
+}
+#endif /* DEBUG */
+#endif /* MOZ_CONTENT_SANDBOX */
--- a/xpcom/base/nsMacUtilsImpl.h
+++ b/xpcom/base/nsMacUtilsImpl.h
@@ -16,16 +16,24 @@ class nsMacUtilsImpl final : public nsIM
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMACUTILS
 
   nsMacUtilsImpl()
   {
   }
 
+#if defined(MOZ_CONTENT_SANDBOX)
+  static bool GetAppPath(nsCString &aAppPath);
+
+#ifdef DEBUG
+  static nsAutoCString GetDirectoryPath(const char *aPath);
+#endif /* DEBUG */
+#endif /* MOZ_CONTENT_SANDBOX */
+
 private:
   ~nsMacUtilsImpl()
   {
   }
 
   nsresult GetArchString(nsAString& aArchString);
 
   // A string containing a "-" delimited list of architectures