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 496829 4b9cd1b9bacb1631aa96c4fd92aa33b660581928
parent 496828 c55cc49537553ce267068a89e7046c3f90cc3c81 (current diff)
parent 496643 067a1c08f91d13f9ad8b7c73b40b2a9065d24c0e (diff)
child 496830 c35df5c273d64a2f495ca5159a91dbc9a5feec32
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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